In NHibernate there is a Save(entityObject) method, which creates a new row in the database with the given entity object, also, has an Update(entityObject) which updates the row corresponding to the entity object with the property values of this object. It also has a SaveOrUpdate(entityObject) method, which checks the whether the entity object corresponds to an existing row in the database, and chooses whether to call Save(…) or Update(…) based on that.
The way I usually do web applications across multiple tiers, when not using view models specifically, makes me encapsulate much code in Services layer that sometimes does not need to care about whether the given entity is persisted in database or not. Thus wanted to have similar method using Entity Framework as ORM.
Of course I have implemented the method number of times and the code evolved based on which version of Entity Framework I’m coding against, and my knowledge of the framework internals as well. Actually, when you work with so many ORMs like I did, a new ORM or ORM version turns to only sound like “What’s new in the manual?” thing.
The Method
You must have heard about the new Entity Framework 4 Feature CTP 4. I was playing with the example code of the Code First enhancements walkthrough, and writing some tweaks, I found myself implementing this function this way in the process ….
using System.Data;
using System.Data.Objects;
public static class ObjectContextExtensions
{
public static void SaveOrUpdate<TEntity>
(this ObjectContext context, TEntity entity)
where TEntity : class
{
ObjectStateEntry stateEntry = null;
context.ObjectStateManager
.TryGetObjectStateEntry(entity, out stateEntry);
var objectSet = context.CreateObjectSet<TEntity>();
if (stateEntry == null || stateEntry.EntityKey.IsTemporary)
objectSet.AddObject(entity);
else if (stateEntry.State == EntityState.Detached)
objectSet.Attach(entity);
}
}
The method is implemented as an extension method to the ObjectContext class to call it on any context instance. Also, no namespace is there so that it’s available without having to add any using namespace … statement to fine it available.
Also, toy notice the method does NOT call context.SaveChanges(). This is on purpose so that the calling code is still in control when to submit the context changes, and makes the method similar in effect to other ObjectContext methods.
The Calling Code
A sample calling code to this method would be similar to below. This is not the code I used when testing it but the easiest to understand, as most people know the repository pattern already. Also, in many places there have been over-simplifications on purpose (no extra base classes or DI containers etc..)), but this is to serve the sample clarity purpose solely.
I’m assuming you have checked the walkthrough already, but if not, it’s enough to know that Book is a class that represents an entity, and BookCatalog is a class that inherits ObjectContext.
namespace EF.CodeFirst.Walkthrough
{
// Most likely this is going to inherit base class also
// Not shown for simplification
public class BookRepository : IRepository<Book>
{
private BookCatalog _objectCcontext;
//Set on top to highlight
public void SaveBook(Book book)
{
_objectCcontext.SaveOrUpdate(book);
_objectCcontext.SaveChanges();
}
// ..... Other parts of the repository
public BookRepository()
{
//In real example the BookCatalog constructor
// requires a connection, which is not to discuss here
_objectCcontext = new BookCatalog();
}
}
}
Conclusion / Disclaimer
This method is not special at all. I just noticed that I have not posted code into my blog for very long, and wanted to change this by creating something as small as this one, hopefully to be followed by more advanced stuff that I should be taking out from my internal helper/toolkit libraries. I have stuff related to Entity Framework, NHibernate, Spark, ASP.NET, and others, but those are to come at another time…
CV Download (.docx)
Google Reader Shared Items
Twitter Updates
no comment untill now