Very generic CreateOrUpdate method with Entity Framework
entity-framework, repository-pattern
Solution
Create a interface with `Id` property, implement it on every of your entities and add another generic constraint to your class:
public interface IEntity
{
int Id { get; set;}
}
And
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, IEntity, new()
With that, you'll be able to use `Id` property within your generic repository class.
Of course - `Id` don't have to be an `int`, it can be `Guid` as well.
Problem
I created a generic repository class that all my other repository classes are inheriting from. This is great, because it means almost all the plumbing is done one time for all repositories. I put a full explanation of what I'm talking about here, but here is the code for my GenericRepository (some code is removed for brevity): ``` public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, new() { private IMyDbContext _myDbContext; public GenericRepository(IMyDbContext myDbContext) { _myDbContext = myDbContext; } protected IMyDbContext Context { get { return _myDbContext; } } public IQueryable<T> AsQueryable() { IQueryable<T> query = Context.Set<T>(); return query; } public virtual void Create(T entity) { Context.Set<T>().Add(entity); } public virtual void Update(T entity) { Context.Entry(entity).State = System.Data.EntityState.Modified; } } ``` As you see, I have a Create method and an Update method. It would be very convenient to have a "CreateOrUpdate" method, so I don't have to manually check for existing objects each time I have to save something to the database. Each of my objects in Entity Framework have an "Id", but the challenge here is that the GenericRepository works with "T". Now, with that rather long introduction, to my specific question. How do I create a generic `CreateOrUpdate` method for my `GenericRepository`? UPDATE After Marcins response, I implemented the following generic methods in my GenericRepository. It will take some time before I can test that it works as expected, but it looks very promising. ``` public virtual bool Exists(Guid id) { return Context.Set<T>().Any(t => t.Id == id); } public virtual void CreateOrUpdate(T entity) { if (Exists(entity.Id)) { var oldEntity = GetSingle(entity.Id); Context.Entry(oldEntity).CurrentValues.SetValues(entity); Update(oldEntity); } else { Create(entity); } } ``` The code above has no less than 3 roundtrips to the database when updating. I'm sure it can be optimized, but it wasn't really the exercise for this question. This question handles that topic better: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key