如何使用UnitOfWork模式防止重复条目与代码优先实体框架?

时间:2012-01-19 02:06:40

标签: c#-4.0 entity-framework-4.1 ef-code-first sql-server-2008-r2

我使用的是工作单元和通用存储库模式。以下是检查重复条目的语句:

int id = int.Parse(beer.id); //id comes from the item we're hoping to insert

if (_unitOfWork.BeerRepository.GetByID(id) == null)
     \\create a new model br
     _unitOfWork.BeerRepository.Insert(br);
     _unitOfWork.save();

显然,我没有检查啤酒是否已经在数据库中,因为我得到了这个内部异常:

  

违反PRIMARY KEY约束'PK_ 啤酒 _3214EC2703317E3D'。   无法在对象'dbo.Beers'中插入重复键。\ r \ n语句   已被终止。

我也收到了这条消息:

  

保存不显示外部实体的实体时发生错误   他们关系的关键属性。 EntityEntries属性   将返回null,因为无法将单个实体标识为   异常的来源。保存时可以处理异常   通过在实体类型中公开外键属性使其变得更容易。   有关详细信息,请参阅InnerException。

UnitOfWork类有我的BeerRecommenderContext,它实现了DbContext,而UnitOfWork有一个每个实体的通用存储库:

namespace BeerRecommender.Models
{
public class GenericRepository<TEntity> where TEntity : class
{
    internal BeerRecommenderContext context;
    internal DbSet<TEntity> dbSet;

    public GenericRepository(BeerRecommenderContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }

    public virtual void Delete(object id)
    {
        TEntity entityToDelete = dbSet.Find(id);
        Delete(entityToDelete);
    }

    public virtual void Delete(TEntity entityToDelete)
    {
        if (context.Entry(entityToDelete).State == EntityState.Detached)
        {
            dbSet.Attach(entityToDelete);
        }
        dbSet.Remove(entityToDelete);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        dbSet.Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }

    }
}

1 个答案:

答案 0 :(得分:0)

我使用代码优先使用存储库。偶尔,我会看到像你描述的那样的冲突。我的问题是跨多个流程的变更跟踪。您是在一个进程内(使用单个实体上下文)将项目插入数据库吗?

如果是,您应该查看Entity Framework提供的合并选项。如果您使用默认合并选项(AppendOnly),那么您可以查询内存上下文而不是转到数据库。这可能会导致您描述的行为。

不幸的是,据我所知,所有合并选项尚未暴露给Code-First。您可以选择默认(AppendOnly)或NoTracking,它们每次都会进入数据库。

希望这有帮助, 达文

相关问题