The easiest way to see dotNails in action is to scaffold out the Model, Controller, and Views for a single table. Here are the nuts and bolts until more thorough documentation can be written...

The Model Factory
The ModelFactory handles all interactions with the model. This differs from normal ActiveRecord, which usually has static methods hanging off the classes - e.g. Product.GetAll(). In order to enable complete mocking of the model, the minor compromise was made to use a ModelFactory - e.g. Model.New<Product>.GetAll(). If a better solution presents itself, or if enough involved people want to change this pattern, it is very open to changing.

Using poor man's dependency injection, have a default controller constructor, and a constructor that takes an IModelFactory (for unit testing).
protected IModelFactory Model { get; set; }
public ProductController() {
    Model = new ModelFactory(new SampleDBDataContext());
public ProductController(IModelFactory modelFactory) {
    Model = modelFactory;

Common LINQ syntax applies after the intial GetByKey() or GetAll(). There are lots of LINQ querying tutorials online. Note - The ToList() tends to throw people new to LINQ - it forces a materialization of the results. Prior to that, the queries simply stack in code and no sql gets built, nor the db hit.

Product product = Model.New<Product>().GetByKey(1); 
List<Product> products = Model.New<Product>().GetAll().ToList();
List<Product> productsAfterDate = Model.New<Product>().GetAll().Where(p => p.CreatedDate > new DateTime("11/1/2009")).ToList();

The Query mechanism allows reusable queries to be placed in stackable and easier to use methods if you don't want to mess with straight LINQ syntax while consuming.
List<Product> productsAfterDate = Model.New<Product>().GetAll().AfterDate("11/1/2009").ToList(); 

Writing re-usable queries

Product product = Model.New<Product>();
product.SomeProp = "somevalue";

SQL will only be generated to alter the properties set. Unlike Linq-to-Sql, no hit to the db is required prior to save.
Product product = Model.New<Product>();
product.ID = 1;
product.SomeProp = "newvalue";


Viewing generated SQL
In order to view all sql generated, simply set the Log property of your DataContext to a DebugTextWriter (found in dotNailsCommon). You will usually want to do this in your controller's constructor (if using poor man's dependency injection). All sql will show up in the Output window of Visual Studio.
SampleDBDataContext db = new SampleDBDataContext();
db.Log = new DebugTextWriter();

MVC Model Binding
In order to use MVC's model binding, the following override must be placed in your controller...
#region IDotNailsController Members
public IEntity CreateModelEntityUsingDefaultFactory(Type type) {
    return Model.New(type);

dotNails will attempt to place the following in your global.asax.cs - in your Application_Start() method. This enables dotNails to create the model objects for classes that support IEntity, and the MVC default for all the rest.
ModelBinders.Binders.DefaultBinder = new SampleApp.Models.dotNailsCommon.DotNailsModelBinder();

Hierarchical serialization is available using DataContract serialization. All the necessary attributes are generated by dotNails. The following example uses Session to serialize to a byte array and a string representation of xml (it is not recommended to use session, but it makes for a simple example).
byte[] productData = product.SerializeToBinary();
Session["productData"] = productData;

string productXml = product.SerializeToXml();
Session["productXml"] = productXml;

The following example deserializes from a byte array and an xml string.
byte[] productData = (byte[])Session["productData"];
Product product1 = Model.NewFromBinary<Product>(productData);

string productXml = Session["productXml"].ToString();
Product product2 = Model.NewFromXml<Product>(productXml);

Last edited Feb 23, 2010 at 3:16 AM by timhardy, version 11


No comments yet.