Saturday, August 25, 2007

LINQ to POCO?

I recently had the opportunity to try out LINQ for SQL beta 2 in a real world (though still small scale) enterprise solution. It’s been a while since I took an early CTP for a spin, so I was excited to finally have a go.

I used the Domain Model tool integrated into VS 2008 to have tables mapped into partial classes automatically. That worked like a charm. If any of my observations apply only to the Domain Modelling tool, and not to LINQ2SQL in general, I apoligize in advance. I’m not (yet) a LINQ expert…

I’m often concerned about the restrictions that different O/R mappers impose on your freedom to keep a clean, simple and efficient class design (otherwise known as POCO / Plain Old Clr Objects). My first impressions of LINQ in this regard, are these:

1. I love the embedded query language, and the code completion is good.

2. Association properties cannot be read only, thus preventing immutable properties. Immutable classes or immutable properties are fundamental to creating a clean, domain driven design.

3. You cannot add [Attributes] to the autogenerated properties, since partial properties are not supported in C#3. So you cannot use Enterprise Library’s attribute based validation framework, or some custom framework that uses attributes as the only interface. Xml serialisation can be tricky as well.

4. Autogenerated fields do not follow MS naming conventions which says fields should be camel cased. A property called Horse will have a corrensponding field named _Horse. Not critical but not very pretty either.

5. Associations require an additional property to hold the foreign key value. It can be private, but not omitted. One to many associations always have a parent property, only the child collection is optional. This forces the domain model to include something, which is not an intrinsical part of the domain: Foreign key values. They are there only to satisfy LINQ, so the domain object end up not being very Persistence Ignorant.

6. Even non lazy loadable associations are wrapped in an EntityRef. Not very POCO.

7. The same goes for collections, which are always of a specific type, EntityCollection. So no coding against interfaces or ReadOnlyCollection or custom collection types.

8. Objects that are constructed within a query are tracked automatically. It took me a while to realize why too many rows were being inserted in the database: I had created some of them to be temporary, but LINQ tracked them all and found them to be transient, therefore inserting them into the database.

9. In order for tracking to work, your classes must implement INotifyPropertyChange. Yet another restriction on my classes. They started out pretty POCO, but it all adds up to a very non-POCO feel.

Conclusion: That’s all for the first day with LINQ 2 SQL. Possibly, more issues will surface along the way, without doubt. These first issues are worth being aware of, as O/R mappers can make your life easier (particularly in small scale projects.) And a lot more difficult (typically in larger projects.)

5 comments:

  1. Johannes Hansen said,

    ON AUGUST 28TH, 2007 AT 12:41 AM
    Hi Søren.

    First of all, nice post.

    It seems to me that many of your issues with LINQ2SQL revolves around the built-in code generator that generates the data context and business entity classes using the dbml file. I think the generator is somewhat configurable and will allow you to specify simple things such as alternative inheritance sources, access and inheritance modifiers. If you still need to have even more control, say for the read-only associations or the extra property attributes, and in this case there is nothing wrong in rolling your own context and entity code generator using a tool like CodeSmith.

    This is the method we are currently using in our company to generate entities but we are also rolling our own business entity infrastructure as we are still working within the .NET 2.0 framework. However, in the future we will try to integrate our entity framework with the .NET 3.5 features so we won’t have to maintain the infrastructure code ourselves.

    Also, don’t forget to take a close look at LINQ2Entities which will be released some time after .NET3.5 as far as I can understand. This new model seems to be far more flexible than the LINQ2SQL model.

    Still, you might have to look elsewhere for other solutions that fit better to your current model.

    Kind regards,
    Johannes Hansen
    frontAvenue A/S

    ReplyDelete
  2. Johannes Hansen said,

    ON AUGUST 28TH, 2007 AT 6:00 PM
    So I dropped a line in the last post on the ADO.NET Entity framework blog and only a few hours later they released beta 2 of the framework along with the first ctp of the vs tools for the framework… awesome!

    You should definitely check it out… I know I will.

    http://blogs.msdn.com/adonet/archive/2007/08/27/entity-framework-beta-2-the-1st-entity-framework-tools-ctp-released.aspx

    ReplyDelete
  3. Soren Skovsboll said,

    ON AUGUST 28TH, 2007 AT 8:22 PM
    You are right. At least issues 2, 3, 4, 5 and 6 are more related to the dbml visualization tool, rather than LINQ to SQL itself. I guess I did not think of the dbml tool as a code generation tool but more of a two-way synchronizing model of my domain classes. Like the Class Modeller in VS2005/8, it stays in touch with the code.

    But, unlike the Class Modeller, it relies on partial classes. The one partial class is reserved for the designer, whatever other partial class you create is yours to fiddle with. That’s why I think of the dbml visualizer as more of a continuous contract: “Don’t mess with the designer’s partial class, keep to your own partial class. Make any changes in the designer’s, and it might be gone next time you regenerate the code.”

    So I might choose to abandon the tool after the first generation, but then I loose the benefit of being able to visualize my classes, and to drag additional tables into the model at a later time. That might be a viable choice: Choosing flexibility over productivity. I would have prefered to have both … in my dreams…

    For our pre .NET 3.5 enterprise solutions, I’ve created an O/R mapper from scratch, focusing on simplicity and meeting the specific needs that apply to our solutions. Count other mappers on the market, there are numerous other ways to turn. But seriously, I’d hate to miss out on the integrated query stuff in LINQ.

    ReplyDelete
  4. Soren said,

    ON AUGUST 29TH, 2007 AT 9:17 AM
    Good news, Johannes, it already in my download queue!!

    ReplyDelete
  5. Thomas Jespersen said,

    ON AUGUST 29TH, 2007 AT 5:34 PM
    Hi Soren

    I’m pretty confident that LinqToSql will not satisfy our needs. It is not a full blown OR Mapper like NHibernate and the one you created for Ditmer. Its more like Wilson OR Mapper.

    I’m also looking forward to the Entity Framwork, which they tried to make more POCO friendly (compared to the first CTP versions). E.g. you don’t have to inherited a base object any more… instead you need to implement an Interface, which is much cleaner.

    However, even the Entity Framework will miss some of the powerful OR Features which we come to love, like lazy load and Proxies. But it might actually be a good thing. Because you know… Lazy Load can be very bad, because the OR Mapper talks to the database directly without going through your repositories. So I sure see why Microsoft made the trade off’s.

    I’m using NHibernate for my current project (with the NHibernate Mapping Attribute Contrib), and I like it a lot. So I’m actually hoping that Ling For NHibernate will take of (http://www.ayende.com/Blog/archive/2007/03/17/Implementing-Linq-for-NHibernate-A-How-To-Guide–Part.aspx)

    I know the Attribute style is not very POCO, but I like it a lot, and I don’t think it is that intrusive. But I must admit that the NHibernate Mapping Contrib requires way to many attributes, compared to. Matterhorn

    ReplyDelete