static void

EF Code First - Using dummy references

Published Sunday 18 March 2012

You’re adding a new record, which has a reference to an existing object.

var johnCarter = new Movie() { Title = "John Carter" };
johnCarter.Director = new
Director { Id = andrewStantonId };
context.Movies.Add(johnCarter);
context.SaveChanges();

SaveChanges() will save the new Movie- but it also saves a new Director record (which gets a new Id, even though you set it manually). When you add an entity to a DbSet, the entire object graph is marked as “Added”.

You could do a Find to load the Director record from the database, but it is a pointless database access that you don’t need. It just needs to save the Movie record with a known directorId.

In NHibernate you can use session.Load<Director>(andrewStantonId) which will create an empty proxy object without hitting the database. Only if you use one of the proxy properties (like director.Name) will it hit the database to load the record. EF Code First doesn’t have this feature.

One way round it to add a foreign key Id property to the Movie record:

       public virtual Director Director { get; set; }
       public int? DirectorId { get; set; }

You can then set the DirectorId directly. The two properties are not kept in step automatically, so setting the DirectorId doesn’t cause Director to load from the database. Foreign key Id properties are convenient, but your object model is “denormalized”.

The alternative is to mark the dummy record as unchanged. There are two ways.

One is to set the context.Entry state for the dummy reference AFTER the new record has been added.

var johnCarter = new Movie() { Title = "John Carter" };
johnCarter.DirectorId = andrewStantonId;
context.Movies.Add(johnCarter);
//after it's added, change the status of the reference
context.Entry(johnCarter.Director).State =
EntityState.Unchanged;
context.SaveChanges();

The second way is to create the dummy reference by Attaching it.

//attach the dummy director record
var andrewStanton = new
Director { Id = andrewStantonId};
context.Directors.Attach(andrewStanton);
//now we have an "unchanged" director record to attach
var johnCarter = new
Movie() { Title = "John Carter" };
johnCarter.Director = andrewStanton;
context.Movies.Add(johnCarter);
context.SaveChanges();

Previously: EF Code First - Updating changed values only (17 Mar 2012)