Dane Morgridge

Programmer, Geek, ASPInsider
A blog about code and data access

  Home  |   Contact  |   Syndication    |   Login
  44 Posts | 0 Stories | 67 Comments | 0 Trackbacks

News

INETA Community Speakers Program

Twitter












Archives

Post Categories

I normally use an int with an identity as the primary key for most tables in Sql Server and I think that is probably the normal habit of most developers, but on occasion, you will need to use a unique identifier, which maps to a System.Guid in code.  I am not going to go into the pros/cons of using a Guid as your primary key, as there is much debate around this.

I am currently working on a project where this is required and I also use Entity Framework 4 and ran in a snag almost immediately.  Entity Framework doesn't support server generated Guids when inserting entities because not all providers support it (http://msdn.microsoft.com/en-us/library/dd283139.aspx). This can pose a problem since you have to get the Guid generated for you somehow.  When you insert an entity and the Guid is null, the call will fail because the primary key cannot be null.  The quickest way to do this is set your Guid column to Guid.NewGuid() before inserting:

   1: using (EFContext db = new EFContext())
   2: {                
   3:     Entity1 entity = new Entity1();
   4:     entity.Id = Guid.NewGuid();
   5:     entity.Name = "Test";
   6:     db.AddObject("Entity1", entity);
   7:     db.SaveChanges();
   8: }

The suggestion from the MSDN article above is to create a proxy class and override the SaveChanges event hander: http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.savingchanges.aspx

I'm not a big fan of doing that unless absolutely necessary because I would prefer to work with the context itself and not a proxy to get around this issue.  The solution I came to was to use POCO classes and make this happen in the property of the Guid column itself:

   1: private System.Guid _id;
   2: public System.Guid Id
   3: {
   4:     get
   5:     {
   6:         if (_id == null || _id == Guid.Empty)
   7:             _id = Guid.NewGuid();
   8:  
   9:         return _id;
  10:     }
  11:     set
  12:     {
  13:         _id = value;
  14:     }
  15: }

Since this is the primary key, it will need to have a value assigned so creating a new guid when the Id property is accessed will fix the problem.  This will allow your inserts to happen as they do with a int/identity based primary key.  You can set this on any non-nullable property of your entity.  Since the Entity Framework will access this property on insert, everything just works.

There are a couple of small things to keep in mind, however.  If you are using the T4 templates to generate your entities, you will need to modify the T4 template to create this code, or it will be overridden whenever the model is changed.  My recommendation would be to use hand-crafted entities and then you can control it and not worry about it being overridden.  Another option would be to use a partial class to set the guid. 

The other issue you need to be aware of is if the entity's StoreGeneratedPropery is not set to None, this trick will not work as the Id will be reset to back to null on inserts.

posted on Friday, February 12, 2010 11:27 AM