检查 EF 实体是否已存在于当前上下文中
Check if EF entity already exist in current context
我知道已经有几个关于这个的问题,但是 none 确实解决了我的问题:
应用背景
我有一个 Web 应用程序首先使用 Entity Framework 6.1 代码。我在我的 DAL 中使用存储库模式,这意味着,我有 Repo 查询我的上下文并将结果 returns 到服务,然后使用自动映射器将我的实体映射到视图模型,然后 returns 一个虚拟机。服务由 Web API 方法调用。
基于上述架构,很明显我使用的是分离实体。
我遇到的问题是更新 (PUT) 现有实体。流程如下所示:
Angular 向 WebAPI 方法发出 HTTP PUT 并将 VM 作为参数传递。
WebAPI 然后调用服务方法,将 VM 作为参数传递。
服务方法使用自动映射器将 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(实体).State = EntityState.Modified;
Attaching an entity of type
'Business.Data.Entities.Customer.Dependant' failed because another
entity of the same type already has the same primary key value. This
can happen when using the 'Attach' method or setting the state of an
entity to 'Unchanged' or 'Modified' if any entities in the graph have
conflicting key values. This may be because some entities are new and
have not yet received database-generated key values. In this case use
the 'Add' method or the 'Added' entity state to track the graph and
then set the state of non-new entities to 'Unchanged' or 'Modified' as
appropriate.
据我了解,发生这种情况是因为在设置实体状态之前需要先附加分离的实体。问题是,我无法附加该实体,因为它已经在 context.Dependant.local 集合中。出于某种原因,entity framework 已经在跟踪该实体。
有没有办法首先检查一个实体是否存在于上下文中,如果不存在,则附加,否则,检索已经附加的实体,并将修改后的实体的更改应用到附加的实体,如果有道理的话。
感谢任何反馈
一开始我应该说你只有在所有实体都被添加或更新到 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;
}
它只会对数据库进行一次查询,而不是多次查询。
关于你的问题,这应该有帮助:
public virtual void InsertOrUpdate(TE entity)
{
var entitySet = _context.Set<TE>();
if(entity.Id.Equals(default(int))){
entitySet.Add(entity);
return;
}
entitySet.Update(entity);
}
就是这样。希望这会有所帮助。(我没有测试代码,所以可能会有一些错误)
这对我有用:
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;
}
我知道已经有几个关于这个的问题,但是 none 确实解决了我的问题:
应用背景
我有一个 Web 应用程序首先使用 Entity Framework 6.1 代码。我在我的 DAL 中使用存储库模式,这意味着,我有 Repo 查询我的上下文并将结果 returns 到服务,然后使用自动映射器将我的实体映射到视图模型,然后 returns 一个虚拟机。服务由 Web API 方法调用。
基于上述架构,很明显我使用的是分离实体。
我遇到的问题是更新 (PUT) 现有实体。流程如下所示:
Angular 向 WebAPI 方法发出 HTTP PUT 并将 VM 作为参数传递。 WebAPI 然后调用服务方法,将 VM 作为参数传递。 服务方法使用自动映射器将 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(实体).State = EntityState.Modified;
Attaching an entity of type 'Business.Data.Entities.Customer.Dependant' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
据我了解,发生这种情况是因为在设置实体状态之前需要先附加分离的实体。问题是,我无法附加该实体,因为它已经在 context.Dependant.local 集合中。出于某种原因,entity framework 已经在跟踪该实体。
有没有办法首先检查一个实体是否存在于上下文中,如果不存在,则附加,否则,检索已经附加的实体,并将修改后的实体的更改应用到附加的实体,如果有道理的话。
感谢任何反馈
一开始我应该说你只有在所有实体都被添加或更新到 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;
}
它只会对数据库进行一次查询,而不是多次查询。
关于你的问题,这应该有帮助:
public virtual void InsertOrUpdate(TE entity)
{
var entitySet = _context.Set<TE>();
if(entity.Id.Equals(default(int))){
entitySet.Add(entity);
return;
}
entitySet.Update(entity);
}
就是这样。希望这会有所帮助。(我没有测试代码,所以可能会有一些错误)
这对我有用:
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;
}