【发布时间】:2014-10-16 18:24:53
【问题描述】:
当我尝试将对象保存到 EF 时,它会抛出此异常:
EntityFramework.dll 中出现“System.InvalidOperationException”类型的异常,但未在用户代码中处理。
附加信息:附加类型的实体 'Sistema.DataEntities.Models.Cliente' 失败,因为另一个实体 相同的类型已经具有相同的主键值。这可能发生 当使用“附加”方法或将实体的状态设置为 “未更改”或“已修改”,如果图中的任何实体具有 键值冲突。这可能是因为一些实体是新的并且 尚未收到数据库生成的键值。在这种情况下使用 'Add' 方法或 'Added' 实体状态来跟踪图形和 然后将非新实体的状态设置为“未更改”或“已修改”为 合适。
如果我取出 'cliItems = new ListCollectionView(t.ToList());'它运行完美,但是我需要将 ListCollectionView 用于 PRISM 模式。
public class CadastroClienteViewModel : BindableBase, ICadastroClienteViewModel
{
private readonly IClienteService _clienteService;
public CadastroClienteViewModel(IClienteService ServiceCliente)
{
_clienteService = ServiceCliente;
this.SaveCommand = new DelegateCommand(ExecuteMethodSave);
this.RefreshCommand = new DelegateCommand(ExecuteMethodRefresh, CanExecuteMethodRefresh);
RefreshCommand.Execute(null);
}
private void ExecuteMethodSave()
{
Sistema.DataEntities.Models.Cliente clifinal = new Sistema.DataEntities.Models.Cliente();
clifinal.InjectFrom<UnflatLoopValueInjection>(ObCliente);
_clienteService.ClienteService_Update(clifinal); //EXCEPTION HERE
RefreshCommand.Execute(null);
}
private bool CanExecuteMethodRefresh()
{
return true;
}
private void ExecuteMethodRefresh()
{
//var t = _clienteService.ClienteService_GetAll().ToList();
//var y = t.Select(p => new Cliente().InjectFrom<FlatLoopValueInjection>(p));
var t = _clienteService.ClienteService_GetAll().Select(p => new Cliente().InjectFrom<FlatLoopValueInjection>(p));
cliItems = new ListCollectionView(t.ToList());//if i take this line out, no exceptions.
cliItems.CurrentChanged += cliItemsOnCurrentChanged;
OnPropertyChanged("cliItems");
}
private void cliItemsOnCurrentChanged(object sender, EventArgs eventArgs)
{
ObCliente = (Cliente)cliItems.CurrentItem;
this.OnPropertyChanged("ObCliente");
}
public ICommand SaveCommand { get; private set; }
public ICommand RefreshCommand { get; private set; }
public Cliente ObCliente { get; private set; }
public ICollectionView cliItems { get; private set; }
}
我的服务(业务逻辑)类:
public class ClienteService : Common.Services.Service<Cliente>, IClienteService
{
private readonly IRepositoryAsync<Cliente> _repository;
private readonly IUnitOfWorkAsync _uow;
public ClienteService(IRepositoryAsync<Cliente> repository, IUnitOfWorkAsync uow)
: base(repository)
{
_repository = repository;
_uow = uow;
}
public void ClienteService_Adicionar(Cliente Obcliente)
{
_repository.Insert(Obcliente);
_uow.SaveChanges();
}
public void ClienteService_Update(Cliente Obcliente)
{
Obcliente.ObjectState = ObjectState.Modified;
_repository.Update(Obcliente);//HERE THE EXCEPTION
_uow.SaveChanges();
}
public IEnumerable<Cliente> ClienteService_GetAll()
{
var t = _repository.Query().Select().AsEnumerable();
return t;
}
}
在我的 Repository.cs 里面有这个:
public virtual void Update(TEntity entity)
{
((IObjectState)entity).ObjectState = ObjectState.Modified;
_dbSet.Attach(entity);// EXCEPTION HERE
_context.SyncObjectState(entity);
}
我正在使用Generic Unit of Work & (Extensible) Repositories Framework 对于我的存储库层。
使用Value Injecter在 ViewModel 和实体之间进行映射
还有我项目的图片(它是桌面 + UNITY + Prism 模块)
更新:
如何重现它:
IEnumerable<Cliente> Clientes = _clienteService.ClienteService_GetAll();
var personViewModels = new List<Sistema.MVVMModels.CadastroModule.Cliente>().InjectFrom(Clientes);
Sistema.MVVMModels.CadastroModule.Cliente cliConvertido = personViewModels.SingleOrDefault(x => x.ClienteID == 1);
//cliConvertido.InjectFrom<SmartConventionInjection>(obCliente);
cliConvertido.Nome = "A" + rand.Next(999999, 9999999) + " BREDA";
Cliente obCliente = new Cliente();
obCliente.InjectFrom<SmartConventionInjection>(cliConvertido);
_clienteService.ClienteService_Update(obCliente);
更新已解决:
使用上述回答者的评论解决了问题。
Repository.cs 有一个内部 IQueryable Select(.... 我在这一行添加了 AsNoTracking():
IQueryable<TEntity> query = _dbSet.AsNoTracking();
现在当我使用以下方法更新我的对象时:
public virtual void Update(TEntity entity)
{
var existing = _dbSet.Local;// NOW LOCAL IS NULL
entity.ObjectState = ObjectState.Modified;
_dbSet.Attach(entity);//no exceptions here
_context.SyncObjectState(entity);
}
【问题讨论】:
-
是
Insert方法用于插入还是更新?第一行里面的代码似乎是一个插入操作,但是下一个代码附加到上下文中?该服务是否与客户端位于同一应用程序域中(或者该服务实际上托管在不同的应用程序域(Windows 服务/iis)上)?上下文实例是否曾经被释放/关闭? -
方法错误,现在正确...更新
-
是上下文实例单例(只要域存在,就只有一个)?它曾经关闭/处置吗?
-
是的......如何管理它是 UnityOfWork 的统一。这些处置在我使用的存储库框架内得到了很好的管理。此错误可能与此存储库框架有关吗? public virtual void Update(TEntity entity) 来自这个框架。
标签: c# entity-framework mvvm prism valueinjecter