Jua*_*uan 71 c# entity-framework ninject repository-pattern entity-framework-5
使用带有通用存储库模式的EF5和ninject用于依赖性损害并在尝试使用存储过程与我的edmx将实体更新到数据库时遇到问题.
我在DbContextRepository.cs中的更新是:
public override void Update(T entity)
{
if (entity == null)
throw new ArgumentException("Cannot add a null entity.");
var entry = _context.Entry<T>(entity);
if (entry.State == EntityState.Detached)
{
_context.Set<T>().Attach(entity);
entry.State = EntityState.Modified;
}
}
Run Code Online (Sandbox Code Playgroud)
从我的AddressService.cs回到我的存储库我有:
public int Save(vw_address address)
{
if (address.address_pk == 0)
{
_repo.Insert(address);
}
else
{
_repo.Update(address);
}
_repo.SaveChanges();
return address.address_pk;
}
Run Code Online (Sandbox Code Playgroud)
当它命中Attach和EntityState.Modified时,它会发出错误:
ObjectStateManager中已存在具有相同键的对象.ObjectStateManager无法使用相同的键跟踪多个对象.
我已经查看了堆栈和互联网上的许多建议,但没有提出解决它的任何建议.任何工作都将受到赞赏.
谢谢!
Lad*_*nka 125
编辑:使用原始答案Find而不是Local.SingleOrDefault.它与@Juan的Save方法结合使用但它可能导致对数据库进行不必要的查询,并且else部分可能从未执行过(执行else部分会导致异常,因为Find已查询数据库但未找到实体,因此无法更新) .感谢@BenSwayne找到问题.
您必须检查上下文是否已跟踪具有相同密钥的实体,并修改该实体而不是附加当前实体:
public override void Update(T entity) where T : IEntity {
if (entity == null) {
throw new ArgumentException("Cannot add a null entity.");
}
var entry = _context.Entry<T>(entity);
if (entry.State == EntityState.Detached) {
var set = _context.Set<T>();
T attachedEntity = set.Local.SingleOrDefault(e => e.Id == entity.Id); // You need to have access to key
if (attachedEntity != null) {
var attachedEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
} else {
entry.State = EntityState.Modified; // This should attach entity
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,主要问题是该SingleOrDefault方法需要知道查找实体的关键.您可以创建公开密钥的简单界面(IEntity在我的示例中),并在您希望以此方式处理的所有实体中实现它.
小智 8
我不想通过添加接口或属性来污染我自动生成的EF类.所以这真的是上面的一些答案(所以归功于Ladislav Mrnka).这为我提供了一个简单的解决方案.
我在update方法中添加了一个func,它找到了实体的整数键.
public void Update(TEntity entity, Func<TEntity, int> getKey)
{
if (entity == null) {
throw new ArgumentException("Cannot add a null entity.");
}
var entry = _context.Entry<T>(entity);
if (entry.State == EntityState.Detached) {
var set = _context.Set<T>();
T attachedEntity = set.Find.(getKey(entity));
if (attachedEntity != null) {
var attachedEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
} else {
entry.State = EntityState.Modified; // This should attach entity
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后当你调用你的代码时,你可以使用..
repository.Update(entity, key => key.myId);
Run Code Online (Sandbox Code Playgroud)
您实际上可以通过反射来检索Id,请参阅下面的示例:
var entry = _dbContext.Entry<T>(entity);
// Retreive the Id through reflection
var pkey = _dbset.Create().GetType().GetProperty("Id").GetValue(entity);
if (entry.State == EntityState.Detached)
{
var set = _dbContext.Set<T>();
T attachedEntity = set.Find(pkey); // access the key
if (attachedEntity != null)
{
var attachedEntry = _dbContext.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
entry.State = EntityState.Modified; // attach the entity
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
71444 次 |
| 最近记录: |