LINQ to SQL NullReferenceException on SubmitChanges

I’ve been busy working on some LINQ to SQL (formerly DLINQ) apps that have been going well bar a NullReferenceException thrown at me from deep in the bowels of LINQ and it’s change tracker. A cursory glance in debug showed none of the properties that represent columns were null…

The null was actually a collection property that represented a one-to-many relationship that was automatically created using the foreign key constraints in the database. Normally this is set to an empty EntitySet however I was failing to call the default constructor from my new useful constructor.

The moral of the story is always call the default constructor with this(), especially when extending generated code. So much for persistence ignorance.

public partial class Invoice {
  public Invoice(int number) : this() {
    this.number = number;
  }
}

[)amien

5 responses

  1. Avatar for Ian Cooper

    Hi Damien,

    The trick for PI is not to use the designer generated code, but start with a clean class and then map manually. The code generation from LINQ to SQL produces a 'fat' solution to the problem, with optimizations that you may not want to take until you know you need them.

    If you want clean code, follow the TDD approach and write it yourself. A lot of code generation is fast food - quick and cheap - but filled with nasty additives that damage your long term health.

    Ian Cooper 13 June 2007
  2. Avatar for Damien Guard

    Writing manual code to perform the data mapping is cumbersome, prone to error, repetitive and is often forgotten or overlooked when making DB changes.

    The other extreme is a run-time layer which attempts to map using metadata. This really can introduce a black-box that may not scale, move with your technology or provide hidden gotchas at runtime you can't get a handle on.

    Code generation is a good compromise between these two and I have been using custom CodeSmith templates for some time.

    Linq to SQL keeps the code generation light and restricted to a datacontext and entity classes. The data mapper/table classes use metadata on the entity classes.

    The entity classes are pure property-only mappings of the fields as you would expect. The exception to this rule is the one-to-many relationship which requires a wrapper to resolve the relationship and it is this that requires the default constructor to be called.

    The whole issue could be resolved if the designer/SQLMetal just made these properties construct inline as part of the definition.

    Damien Guard 13 June 2007
  3. Avatar for ian Cooper

    Code generation comes with its own difficulties. It's difficult to use with TDD; the coupling between your code and the generated code causes a 'ripple of changes'; and merging between versions becomes difficult.

    The point of coding a PI domain and then implementing the mapping once you are happy is that your changes flow from the domain out to the DB, not the other way. You don't need to remember to modify the the map for DB changes, because you don't change that first. Instead you write tests to persist the entity, once you are happy with its domain representation.

    Its the tests that preserve correctness - not the tooling.

    ian Cooper 13 June 2007
  4. Avatar for Damien Guard

    I haven't encountered the problems you describe but then I'm not sold on TDD during prototyping stages.

    There isn't coupling between the LINQ to SQL generated and your own code at an entity level - the properties are just there and thanks to partial classes you don't even have to ever look at the source.

    I see ORM as commoditising, as part of the toolset and environment. As such I rely on higher-level tests to expose any flaws in the ORM just as I wouldn't test parts of the .NET framework directly to make sure lists and math work.

    I can understand the extra level of abstraction required when modelling objects against legacy systems or for very complex environments but in many of the recent projects I've worked on there has been a 1:1 relationship between the database and objects.

    Damien Guard 13 June 2007
  5. Avatar for Andrei Rinea

    Wow... I wish I read your blog entry a few weeks ago because it would have saved me a lot of headaches and I wouldn't had to write a (separate - but pretty much the same) blog entry... ( http://andreir.wordpress.com/2009/01/30/linq-to-sql-nullreferenceexception-gotcha/ )

    Andrei Rinea 3 February 2009