ICollectionView вызывает исключение Entity Framework Attach

Когда я пытаюсь сохранить объект в 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);
        }

person Danilo Breda    schedule 22.08.2014    source источник
comment
Используется ли метод Insert для вставки или обновления? код внутри него в первой строке кажется операцией вставки, но следующий код прикрепляется к контексту? И находится ли служба в одном домене приложения с клиентом (или служба фактически размещена в другом домене приложения (служба Windows / iis))? Экземпляр контекста когда-либо удаляется/закрывается?   -  person Yuliam Chandra    schedule 23.08.2014
comment
Неправильный метод, теперь правильный... обновлено   -  person Danilo Breda    schedule 23.08.2014
comment
является экземпляром контекста singleton (единственным, пока существует домен)? Он когда-либо закрывался / утилизировался?   -  person Yuliam Chandra    schedule 23.08.2014
comment
Да... как же это единство от UnityOfWork. Распоряжение очень хорошо управляется внутри структуры репозитория, которую я использую. Эта ошибка может иметь какое-то отношение к этому фреймворку репозитория? public virtual void Update (сущность TEntity) из этой структуры.   -  person Danilo Breda    schedule 23.08.2014


Ответы (1)


Я действительно не знаю, как создать контекст/репозиторий/службу, если контекст правильно расположен после сохранения изменений и создает новый при каждой новой операции, это не должно быть проблемой, поскольку кеш Local всегда новый.

И в исключении говорится, что существует существующая сущность с тем же идентификатором, которая была прикреплена к кешу Local, вы не можете прикрепить другую сущность с тем же идентификатором, вам нужно сначала отсоединить существующую сущность.

var existing = _dbSet.Local.FirstOrDefault(x => x.Id == entity.Id);
if (existing != null)
    _context.Entry(existing).State = EntityState.Detached;

_dbSet.Attach(entity);// EXCEPTION HERE

обновить

Другой альтернативой может быть переопределение SaveChanges и отсоединение измененных объектов после их сохранения.

public override int SaveChanges()
{
    var modifiedEntities = ChangeTracker.Entries()
        .Where(x => x.State == EntityState.Modified).ToArray();
    var rowsAffected = base.SaveChanges();
    foreach (var entity in modifiedEntities)
        entity.State = EntityState.Detached;
    return rowsAffected;
}

обновление2

Исключение также может быть вызвано извлечением элементов из DbSet<T>, а затем присоединением другого другого объекта с тем же ключом, по умолчанию эти элементы будут отслеживаться (прикрепляться). Его можно отключить, указав AsNoTracking. .

Вот простая ошибка, которая вызывает ошибку при получении элементов.

Entity item = new Entity { Id = 324 };

// itemDb is automatically attached.
var itemDb = db.Set<Entity>().First(x => x.Id == 324);
// Attaching another different entity (different reference)
//   with the same key will throw exception.
db.Set<Entity>().Attach(entity);

Если не указано AsNoTracking.

var itemDb = db.Set<Entity>().AsNoTracking().First(x => x.Id == 324);
person Yuliam Chandra    schedule 22.08.2014
comment
я разговаривал с создателем Generic Unit of Work & (Extensible) Repositories Framework, он сказал мне, что проблема была исправлена ​​неделю назад... и я загружу следующую версию, чтобы протестировать ее. Спасибо за помощь. - person Danilo Breda; 24.08.2014
comment
@Daniloloko, в своем примере теста репозитория, контекст и единица работы создаются для каждой операции (короткоживущий контекст), если вы хотите иметь долгоживущий контекст, вам нужно сделать, как я объяснял ранее, я добавил еще одну альтернативу, переопределив сохранение изменений, чтобы отсоединить измененные объекты после сохранения изменений. - person Yuliam Chandra; 02.09.2014
comment
Я не думаю, что это проблема, потому что Local не очищается каждый раз... я отлаживаю его... пожалуйста, посмотрите обновление о том, как его воспроизвести. - person Danilo Breda; 02.09.2014
comment
@Daniloloko, ваш обновленный код вызван отслеживаемыми объектами при извлечении Cliente из _clienteService.ClienteService_GetAll();, что можно упростить, как этот пример, и это можно решить, введя AsNoTracking, и поскольку фреймворк обертывает DbSet<T> , вы не можете его использовать, я думаю, что эта структура не подходит для приложения Windows, если вы не измените способ создания экземпляра IClienteService для каждой операции (для каждого вызова метода) - person Yuliam Chandra; 02.09.2014
comment
Спасибо за ответное сообщение... вы мне очень помогаете... Я думаю, что этот фреймворк действительно не подходит для приложения Windows... я пытаюсь поговорить с владельцем фреймворка... но ответное сообщение требует времени .Чтобы добавить AsNoTracking... мне нужно обновить структуру репозитория... верно? Это проблема... - person Danilo Breda; 02.09.2014
comment
Пожалуйста, добавьте комментарии об AsNoTracking в свой ответ, чтобы кому-то было проще найти решение. Спасибо... Проблема решена. - person Danilo Breda; 03.09.2014