chris carter's web log

Home |  Contact |  Admin
 

Active Record From Scratch

Posted on August 29, 2008

According to Martin Fowler, the Active Record pattern is described like this:

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.

So I set out to implement this pattern in a quick spike. With no thought to performance, good coding, etc, I came up with a working Active Record implementation.

I started with the model.  I used the greatly abused concept of a blog and created a Post model with two properties, and it looks like this:

public class Post {
  public string Title { get; set; }
  public DateTime CreateDate { get; set; }
}
1
2
3
4

Notice how there's no id property.  I'm noticing that, recently anyway, all of the primary keys I define are identity columns, so I wanted to remove any concept of id from the models and keep that as something for a  base class to define and manage.

I'm heavily influenced by Castle's ActiveRecord, so of course I have a base class named ActiveRecord that takes a model as a generic type parameter, the shell of the class looks like this:

public class ActiveRecord<T> where T : new(){
}
1
2

One of the things I was thinking was that it would be nice to also have a mechanism that allowed the creation of the schema from the model, similar to how Rails works.

Here's the source code file for my naive ActiveRecord implementation.

I couldn't help but constantly thinking about how much work would be involved in defining relationships and the corresponding tables from code, maybe that'll be my next attempt.

Here's how you define an ActiveRecord class:

public class Post : ActiveRecord<Post> {
  public string Title { get; set; }
  public DateTime CreateDate { get; set; }
}
1
2
3
4

Ninject + ActiveRecord + ASP.NET MVC + Scaffolding

Posted on August 27, 2008

OK.  So using a combination of Ninject for my IOC, ActiveRecord(the Mediator flavor) for my data access objects slash models, and ASP.NET MVC, I have my first cut of scaffolding done.  The source is here, http://svn.chrisjcarter.com/public/ActiveRecordScaffolding/, you can point your favorite SVN client at the url and check it out.

There's one controller, ARController that handles all of the operations of List, Save, and Edit.  It's a generic type that takes the ActiveRecord class as a type parameter.  There is one ARController per ActiveRecord class in any assembly you tell the start up code to look at.  There are 2 shared views, one for listing and one for editing. Only the bare minimum was used for the edit form, pretty just enough to get a form on the screen with zero logic and no concern for the type of field being edited.  Both views use a single mvc style master page.

The ARControllerModule is a Ninject StandardModule that's used to wire up each ActiveRecord classs in the project to an ARController of the same type.  Here's the CreateARControllers method responsible for finding all of ActiveRecord classes in an assembly and creating a new ARController of the same type as the ActiveRecord class:

public IDictionary<string, Type> CreateARControllers(Assembly assembly)
{
  Dictionary<string, Type> controllers = new Dictionary<string, Type>();

  Type[] types = assembly.GetExportedTypes();
  foreach (Type type in types)
  {
    object[] attribs = type.GetCustomAttributes(typeof(ActiveRecordAttribute), false);
    if (attribs != null && attribs.Length == 1)
    {
      Type controller = typeof(ARController<>).MakeGenericType(type);
      controllers.Add(type.Name, controller);
    }
  }
  return controllers;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

I included the Sql Server CE flavor of the Northwind database.  It works.  But a few screens break for reasons I didn't tackle yet, that'll be another post.  The cool thing is that all you do is load up whatever assemblies contain your active record classes and it'll build a web ui to edit them.  It's a first pass, but it should work with minimal effort on your machine, lemme know otherwise.  You can grab a zip of the code here(it's about 10 megs).

Death Row

Posted on August 25, 2008

I first learned about the concept of sentencing software to Death Row in Gina Trapani's book lifehacker: 88 tech tips to turbocharge your day.  I believe it started here.

I have couple of folders that get a fair share of abuse, one is a dev folder, it's where I put all those one off scratch apps that are created usually to test out one thing.  usually poorly named.  Those pile up fast.  So implemented a Death Row folder.  It's awesome.  grab every project that's older than say a month, or named something like craptester or crackmonkey or MvcApplication1, MvcApplication2, MvcApplication3, etc, and sentence them to the Death Row folder.  Where they sit for say a month? you choose.  Then you delete them. Keeps the clutter down. 

My other folder that gets abused is my svn folder, where i checkout crap from every place that lets me.  Now i'm in the habit of Death Row, so I can keep that folder nice and clean.

Cutting Down On The Number Of Enums _AND_ Improve Readability

Posted on August 21, 2008

Tobin gave me an idea in his comment on my Enum versus Boolean post. 

In the asp.net mvc framework, there are few method signatures that take an object parameter like this:

string Html.ActionLink(string linkText, string actionName, string controllerName, object values)
1

In the source, the devs either have TODO comments indicating that they need to use TypeDescriptor for determining properties, or they are using the TypeDescriptor.  A little digging got me this post and I put it on my delicious todo list.  So now it all makes sense.  I'm sure there is a cleaner way to do this but here's an overload I added to OrderBy:

public IEnumerable<TModel> OrderBy(object values) {

  if (values == null) throw new ArgumentNullException("values");

  string propertyName = String.Empty;
  Sort sortDirection = Sort.Ascending;

  PropertyDescriptorCollection props = TypeDescriptor.GetProperties(values);
  foreach (PropertyDescriptor prop in props) {
    switch (prop.Name) {
      case "Property":
        propertyName = prop.GetValue(values).ToString();
        break;
      case "SortAscending":
        sortDirection = Convert.ToBoolean(prop.GetValue(values)) ? Sort.Ascending : Sort.Descending;
        break;
    }
  }
  return OrderBy(propertyName, sortDirection);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

There's prolly something I can do about the switch statement, I just scratched out the method this morning.  But now checkout the usage:

repo.OrderBy(new { Property = "FirstName", SortAscending = true });
1

Now reading the code *usage* is easier and there are no enums.  The only problem is that now you have to make sure and document the possible values for that object parameter, cuz using an api that has a parameter of type object can be a little confusing unless you know what's supposed to go in there.

Enum Versus Boolean

Posted on August 20, 2008

I've been in discussions in the past about this one.  Let's say you have a method signature, and one of the parameters to the method can either be true or false.  What Type do you use? Boolean? seems simple enough.  But it's becoming increasingly annoying to have to discover boolean values in method signatures.

Recently I created a method with a signature like this:

IEnumerable<T> OrderBy(string propertyName, bool sortAscending)
1

Using the above signature, my client code looked like this:

myRepository.OrderBy("FirstName", true)
1

Reading that code kinda makes sense, but that true as the second arg is a mystery.  What's true?? Intellisense tells me, but only after I put effort into this; effort I don't want to have to put in when I'm reading code.  So I went back and changed it to this:

IEnumerable<T> OrderBy(string propertyName, Sort sortDirection)
1

Where Sort is an enum that looks like this:

public enum Sort {
  Ascending,
  Descending
}
1
2
3
4

What's the difference? When I'm skimming code, this:

myRepository.OrderBy("FirstName", Sort.Ascending)
1

is more readable than this

myRepository.OrderBy("FirstName", true)
1

I guess it depends on what you're building, but I like the more readable look rather than the other, at least if I'm publishing the interface.

Dynamic.cs: Yummy Linq Goodness

Posted on August 20, 2008

While testing out some more asp.net mvc stuff, I came up with a need to order a list of objects by property name(a string value).  Assuming I have a list of customers named customerList, i want to do something like: customerList.OrderBy("FirstName"), and get back a list of customers sorted by the FirstName property of each customer instance in the list.

Originally, I used something based on this post.  It looked like this:

public IEnumerable<TModel> OrderBy(string propertyName, bool sortAscending){

  if (String.IsNullOrEmpty(propertyName))
    throw new ArgumentNullException("propertyName");

  PropertyInfo property = typeof(TModel).GetProperty(propertyName);
  if (property == null)
    throw new NullReferenceException(
      String.Format("property '{0}' was not found on type '{1}'",
      propertyName,
      typeof(TModel).Name));

  if (sortAscending)
    return _models.OfType<TModel>().OrderBy(mo => property.GetValue(mo, null));
  else
    return _models.OfType<TModel>().OrderByDescending(mo => property.GetValue(mo, null));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

But then I found dynamic.cs located in the DynamicQuery project in the CSharpSamples.zip file.  Wicked cool shizzle. Now that method above looks like this:

public IEnumerable<TModel> OrderBy(string propertyName, Sort sortDirection){

  if (String.IsNullOrEmpty(propertyName))
    throw new ArgumentNullException("propertyName");

  return _models.AsQueryable<TModel>()
    .OrderBy(propertyName, sortDirection.ToString());
}
1
2
3
4
5
6
7
8

Now using my updated code looks like this:

IEnumerable<Customer> customers = customerRepository.OrderBy("FirstName", Sort.Descending);
1

I had to dig a little for this, but the signature on OrderBy, one of them anyway, looks like this:

IQueryable<T> OrderBy<T>(string ordering, params object[] values)
1

To use this, pass in the property name in the first spot, and "Ascending" or "Descending" in the second spot, like this:

customerList.AsQueryable<Customer>().OrderBy("FirstName", "Descending")
1

I felt like sticking the OrderBy method on my IRepository interface which, using your favorite subversion tool, can be checked out here:
http://svn.chrisjcarter.com/public/EPS

There's some really cool geeky code in dynamic.cs, check it out.

Bare bones ASP.NET MVC Project Template

Posted on August 18, 2008

One minor annoying thing about starting a new ASP.NET MVC project, is the template that's installed has a bunch of stuff that belongs in a Starter Kit type project, not a new project template.  So I created my own empty project template that has the bare minimum to get started.  I removed all the membership crap and .NET 3.5 shite that clutters the web.config, and stuck the preview 4 assemblies in a libs directory, within the project. Here's the template http://panteravb.com/downloads/ASP.NET MVC Preview 4 Project.zip.

Installing the Template

Using this post by Dave Bouwman and this msdn article, here's a short pictorial on how to install the template:

First, find out where your user project templates directory is located.  Tools > Options > Projects and Solutions:

Next, download and copy the zip from above to the that directory:

Next, run this command from the command line devenv -installvstemplates.  Once that completes fire up visual studio, choose new project, and you should see this:

Cool Tools:Visual Studio File Explorer

Posted on August 17, 2008

This is a pretty cool free tool from Mindscape you can find here.  I was almost going to uninstall it though until unexpectedly it saved me some clicks, so it stays in my toolbox.  I hooked up CTRL + SHIFT + E to launch it.

Firefox takes the Gold!

Posted on August 13, 2008

firefox takes the gold!

ASP.NET != WebForms

Posted on August 13, 2008

WebForms is Microsoft's UI framework, built ontop of ASP.NET.  They are two separate things

MonoRail is another UI framework, built by the Castle team, and it runs ontop of ASP.NET. 

ASP.NET MVC is also another Microsoft UI framework, and it's built ontop of ASP.NET. 

Request? part of ASP.NET.  UserControl? part of WebForms.  Session? part of ASP.NET.  TextBox? part of WebForms.

Got it?

Repeat after me:

WebForms is not the same thing as ASP.NET

WebForms is not the same thing as ASP.NET

WebForms is not the same thing as ASP.NET 

It Seemed So Simple...I'm an idiot

Posted on August 12, 2008

What's wrong with this picture:

if (!validateEmail('YourEmail', { maxlength:100 } )) disableButtons(); return;
1

Uh Oh...That's Not Good

Posted on August 9, 2008

value craftsmanship over crap

Posted on August 8, 2008

The M Word

Posted on August 8, 2008

I'm reading some good blog posts by Michael Hanney on using ASP.NET MVC, NHibernate, Castle ActiveRecord and Rhino Tools (part 1, part 2, part 3). 

In the first part Michael mentions the reason why he chose ASP.NET MVC over MonoRail.  He references Ben Scheirman's blog post on the topic of picking a Microsoft(this is the M word) tool, just because it has the M word attached to it not because it's necessarily the best choice.  This is the exact reason why we're picking ASP.NET MVC over MonoRail at my current gig, one of those frameworks comes out of Redmond, the other does not, it was that simple.

This needs to change.

Keeping Up With Castle

Posted on August 6, 2008

I've gotten used to building off of the trunk. However, I can never remember every single assembly that Castle.ActiveRecord.dll and NHibernate.dll need nearby.  If I create new projects using those tools, I usually put the required assemblies in a lib folder within the solution I'm building, then any project in the solution references the assemblies in lib(and not the gac or anywhere else). 

To help me just copy all referenced assemblies those two assemblies require, I wrote a little snippet to help(you can run this straight out of snippetcompiler):

public void RunSnippet(){

	string sourceDir = @"C:\svn\castle\trunk\build\net-3.5\debug\";
	string[] targetAssemblies = new String[]{ "Castle.ActiveRecord.dll", "NHibernate.dll" };
	List<string> baseFileNames = new List<string>();

	//add the two assemblies we're starting with
	baseFileNames.Add("Castle.ActiveRecord");
	baseFileNames.Add("NHibernate");

	//get a distinct list of referenced assemblies for all targetAssemblies
	foreach(string targetAssembly in targetAssemblies){
		Assembly asses = Assembly.LoadFrom(Path.Combine(sourceDir, targetAssembly));
		foreach(AssemblyName ass in asses.GetReferencedAssemblies()){
			if (ass.Name.StartsWith("System"))
				continue;

			if (File.Exists(Path.Combine(sourceDir, ass.Name + ".dll")))
				baseFileNames.Add(ass.Name);
		}
	}

	//get a list of file names that match the ref assemblies regardless of file extension; so
	//basically we want not only .dll, but .xml and .pdb files as well(and anything else that matches)
	List<string> files = new List<string>();
	foreach(string baseFileName in baseFileNames){
		foreach(string f in Directory.GetFiles(sourceDir, baseFileName + ".*")){
			if (!files.Contains(f))
				files.Add(new FileInfo(f).Name);
		}
	}

	//copy everything from source to destination, overwriting if we need to
	string destDir = @"C:\dev\Awish.Security\lib";
	foreach(string file in files){
		File.Copy(Path.Combine(sourceDir, file), Path.Combine(destDir, file), true);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

Exactly!

Posted on August 6, 2008

Kyle Baley hits the nail on the head with this one concerning WebForms developers apprehension with Microsoft's MVC offering.

IRepository

Posted on August 4, 2008

As I'm testing features of ASP.NET MVC, I'm noticing that it would  be really nice to be able perform non-persistent CRUD operations on POCO's.  Meaning, i need data, i need objects, but I don't want to set up a test database for these tests. I need to be able to create a class, and then create lists of instances of that class, and then add new ones, edit existing ones, delete some, exactly the same stuff I'd normally do, just no database. 

I searched on "IRepository" and came back with awesome examples, most of which enabled you to do almost if not everything you would need to do in your app, many of which I'll be revisiting.  But I couldn't find one that did almost nothing.  So I wrote one.  And it does...well, almost nothing.

Here is my initial version of IRepository:

public interface IRepository<TModel>
			where TModel : IModel, new()

	TModel Find(int id);
	IEnumerable<TModel> FindAll();
	void Save(TModel model);
	void Delete(TModel model);
	int Count { get; }
}
1
2
3
4
5
6
7
8
9

It's pretty simple, and does only the bare minimum.  Every class that wants to participate in a repository must implement IModel, this tells the repository that anything in it is guaranteed to have an int ID property, by which it can query:

 
public interface IModel{
	int ID { get; set; }
}
1
2
3

Let's say you create a class, Customer.  In order to enable it to be usable in a repository, it needs to implement IModel, so the class might look something like this:

public class Customer : IModel {

  public int ID { get; set; } //required by IModel

  public string FirstName{ get; set; }

  public string LastName{ get; set; }

}
1
2
3
4
5
6
7
8
9

Using the repository is simple,

//first create a customer repository
IRepository<Customer> repo = new Repository<Customer>();

//now add some customers
repo.Save(new Customer() { FirstName = "Chris", LastName = "Carter" });
repo.Save(new Customer() { FirstName = "Emmitt", LastName = "Carter" });

//make sure they are in there
Assert.AreEqual(2, repo.Count);
Assert.AreEqual("Emmitt", repo.Find(2).FirstName);

//let's remove one
repo.Delete(repo.Find(2));

//make sure it's gone
Assert.AreEqual(1, repo.Count);
Assert.IsNull(repo.Find(2));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

I bundled up the code in a project inspired by Rhino Commons called EPS.Common, the source is here: http://svn.chrisjcarter.com/public/EPS.  I have a sample ASP.NET MVC(Preview 4) solution available for download here(less than 100k).

There Be Dragons

Posted on August 4, 2008

I was poking around Ayende's Rhino Commons and found this, hilarious and a good idea too: