使用Entity Framework的非常通用的CreateOrUpdate方法

时间:2013-08-17 10:15:58

标签: entity-framework repository-pattern

我创建了一个通用的存储库类,我的所有其他存储库类都继承自该类。这很好,因为它意味着几乎所有管道都为所有存储库完成了一次。我对我所说的here进行了完整的解释,但这里是我的GenericRepository的代码(为简洁起见,删除了一些代码):

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;
    }
}

如您所见,我有一个Create方法和一个Update方法。使用“CreateOrUpdate”方法非常方便,因此每次我必须将某些内容保存到数据库时,我不必手动检查现有对象。

我在Entity Framework中的每个对象都有一个“Id”,但这里的挑战是GenericRepository使用“T”。

现在,通过这个相当长的介绍,我的具体问题。

如何为CreateOrUpdate创建通用GenericRepository方法?

更新

在Marcins回复之后,我在GenericRepository中实现了以下泛型方法。我需要一些时间来测试它是否按预期工作,但它看起来很有希望。

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);
    }
}

上面的代码在更新时不少于3次往返数据库。我确信它可以进行优化,但实际上并不是这个问题的练习。

这个问题更好地处理了这个话题: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key

1 个答案:

答案 0 :(得分:4)

创建一个具有Id属性的接口,在每个实体上实现它,并为您的类添加另一个通用约束:

public interface IEntity
{
    int Id { get; set;}
}

public abstract class GenericRepository<T> : IGenericRepository<T> where T : class, IEntity, new()

通过这种方式,您将能够在通用存储库类中使用Id属性。

当然 - Id不一定是int,也可以是Guid