检查当前上下文中是否已经存在EF实体
本文关键字:存在 EF 实体 是否 上下文 检查 | 更新日期: 2023-09-27 18:01:35
我知道关于这个已经有几个问题,但没有一个真正解决我的问题:
<<p> 应用背景/strong>我有一个web应用程序,首先使用实体框架6.1代码。我在我的DAL中使用存储库模式,这意味着,我有Repo查询我的上下文并将结果返回给服务,然后使用automapper将我的实体映射到视图模型,然后返回VM。服务由Web API方法调用。
基于上述架构,很明显我使用的是分离实体。
我遇到的问题是更新(PUT)现有实体。流程如下所示:
Angular向WebAPI发送HTTP PUT方法,并将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(实体)。
附加类型的实体"Business.Data.Entities.Customer。依赖者失败是因为另一个同一类型的实体已经具有相同的主键值。这可能发生在使用"附加"方法或设置如果图中的任何实体已更改,则将实体更改为"未更改"或"已修改"键值冲突。这可能是因为一些实体是新的和尚未收到数据库生成的键值。在这种情况下使用"添加"方法或"添加"实体状态来跟踪图形和然后将非新实体的状态设置为"Unchanged"或"Modified"合适。
据我所知,发生这种情况是因为在设置实体状态之前需要首先附加分离的实体。这样做的问题是,我不能附加实体,因为它已经在context. dependent .local集合中。由于某些原因,实体框架已经在跟踪实体了。
是否有一种方法可以首先检查一个实体是否存在于上下文中,如果不存在,则附加,否则,检索已经附加的实体,并将修改后的实体的更改应用于附加的实体,如果这样做有意义的话。
感谢您的反馈
这对我有用:
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;
}
一开始我应该保存只有当所有实体被添加或更新到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);
}
这它。希望这对你有帮助。(我没有测试代码,所以可能有一些错误)