Когда я пытаюсь сохранить объект в EF, он выдает это исключение:
Исключение типа «System.InvalidOperationException» возникло в EntityFramework.dll, но не было обработано в пользовательском коде.
Дополнительная информация: Не удалось присоединить сущность типа "Sistema.DataEntities.Models.Cliente", поскольку другая сущность того же типа уже имеет такое же значение первичного ключа. Это может произойти при использовании метода «Прикрепить» или при установке состояния объекта на «Без изменений» или «Изменение», если какие-либо объекты на графике имеют конфликтующие ключевые значения. Это может быть связано с тем, что некоторые объекты являются новыми и еще не получили значения ключей, сгенерированные базой данных. В этом случае используйте метод «Добавить» или состояние объекта «Добавлено», чтобы отслеживать график, а затем установите состояние не новых объектов на «Без изменений» или «Изменено» в зависимости от ситуации.
Если я возьму '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 для своего слоя репозитория.
Для сопоставления между ViewModels и Entity im с использованием Value Injector
И изображение моего проекта (это рабочий стол + модули 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))? Экземпляр контекста когда-либо удаляется/закрывается? - person Yuliam Chandra   schedule 23.08.2014