检查当前上下文中是否已存在EF实体

时间:2015-07-08 04:28:20

标签: c# ef-code-first entity-framework-6

我知道有关于此的几个问题已经存在,但它们都没有真正解决我的问题:

应用背景

我有一个首先使用Entity Framework 6.1 Code的Web应用程序。我在我的DAL中使用Repository模式,这意味着,我有Repo查询我的上下文并将结果返回给Services,然后Services使用automapper将我的实体映射到视图模型,然后返回VM。服务由Web API方法调用。

基于上述架构,我明确表示我正在使用分离的实体。

我遇到的问题是更新(PUT)现有实体。流程如下:

Angular Issue HTTP PUT to WebAPI方法将VM作为参数传递。 然后,WebAPI调用Service方法,将VM作为参数传递。 Services方法使用automapper将VM转换为EF实体 然后,服务方法调用各自的存储库,将分离的EF实体的新实例作为参数传递。

服务方法示例:

    public async Task<List<DependantViewModel>> SaveDependants(int customerId, List<DependantViewModel> dependantViewModels)
    {
        var dependantEntities = Mapper.Map<List<DependantViewModel>, List<Dependant>>(dependantViewModels);

        bool result = false;
        foreach (var dependantEntity in dependantEntities)
        {
            result = await _dependantRepository.InsertOrUpdate(dependantEntity);
            if (result != true)
            {
                // log errror
            }
        }

        return Mapper.Map<List<Dependant>, List<DependantViewModel>>(dependantEntities);
    }

BaseRepo:

    public virtual async Task<bool> InsertOrUpdate(TE entity)
    {
        if (entity.Id == 0 || entity.Id == ModelState.New)
        {
            // insert new item
            _context.Entry<TE>(entity).State = EntityState.Added;
        }
        else
        {
            // update existing item
            _context.Entry<TE>(entity).State = EntityState.Modified;
            _context.Entry<TE>(entity).Property(o => o.CreatedUserId).IsModified = false;
            _context.Entry<TE>(entity).Property(o => o.CreatedDate).IsModified = false;
        }
        return await _context.SaveChangesAsync() > 0;
    }

尝试设置时发生异常:

_context.Entry(entity).State = EntityState.Modified;

  

附加类型的实体   &#39; Business.Data.Entities.Customer.Dependant&#39;因为另一个失败了   相同类型的实体已具有相同的主键值。这个   使用&#39;附加&#39;方法或设置状态   实体到&#39;未改变&#39;或者&#39;修改&#39;如果图中有任何实体   冲突的关键值。这可能是因为一些实体是新的和   尚未收到数据库生成的键值。在这种情况下使用   &#39;添加&#39;方法或“添加”#39;实体状态跟踪图形和   然后将非新实体的状态设置为“未更改”#39;或者&#39;修改&#39;如   合适的。

据我了解,这是因为在设置实体状态之前需要首先附加分离的实体。这个问题是,我无法附加实体,因为它已经在context.Dependant.local集合中。出于某种原因,实体框架已经在跟踪实体。

是否有办法首先检查上下文中是否存在实体,如果它不存在,则附加,否则,检索已附加的实体,并将修改后的实体中的更改应用于附加实体,如果这是有道理的。

感谢任何反馈

2 个答案:

答案 0 :(得分:4)

这对我有用:

public virtual async Task<bool> InsertOrUpdate(TE entity)
{
    if (entity.Id == 0 || entity.Id == ModelState.New)
    {
        // insert new item
        _context.Entry<TE>(entity).State = EntityState.Added;
    }
    else
    {           
        var attachedEntity = _context.ChangeTracker.Entries<TE>().FirstOrDefault(e => e.Entity.Id == entity.Id);
        if (attachedEntity != null)
        {
            // the entity you want to update is already attached, we need to detach it and attach the updated entity instead
            _context.Entry<TE>(attachedEntity.Entity).State = EntityState.Detached;
        }

        _context.Entry<TE>(entity).State = EntityState.Modified; // Attach entity, and set State to Modified.
        _context.Entry<TE>(entity).Property(o => o.CreatedUserId).IsModified = false;
        _context.Entry<TE>(entity).Property(o => o.CreatedDate).IsModified = false;
    }
    return await _context.SaveChangesAsync() > 0;
}

答案 1 :(得分:1)

一开始我应该保存你只有当所有的entites被添加或更新到EF上下文时才使用SaveChanges()(这不是你问题的答案,但我需要提一下)。例如:

 public async Task<List<DependantViewModel>> SaveDependants(int customerId, List<DependantViewModel> dependantViewModels)
{
    var dependantEntities = Mapper.Map<List<DependantViewModel>, List<Dependant>>(dependantViewModels);

    bool result = false;
    foreach (var dependantEntity in dependantEntities)
    {
        // Also InsertOrUpdate don't need to be async in that case
        _dependantRepository.InsertOrUpdate(dependantEntity);
        if (result != true)
        {
            // log errror
        }
    }
    // Let the SaveChanges be async
    result = await _dependantRepository.SaveChanges();

    return Mapper.Map<List<Dependant>, List<DependantViewModel>>(dependantEntities);
}

BaseRepo:

public async Task<bool> SaveChanges(){
   return await _context.SaveChangesAsync() != 0;
}

它只会向DB发出一个查询而不是几个查询。

关于你的问题,这应该有所帮助:

public virtual void InsertOrUpdate(TE entity)
{
    var entitySet = _context.Set<TE>();
    if(entity.Id.Equals(default(int))){
        entitySet.Add(entity);
        return;
    }
    entitySet.Update(entity);
}

多数民众赞成。希望这会有所帮助。(我没有测试过代码,所以可能会出现一些错误)