2016-06-23 3 views
6

Я получаю ошибкуEntity Framework «Объект лицо не может ссылаться несколько экземпляров IEntityChangeTracker»

Объект объект не может ссылаться несколько экземпляров IEntityChangeTracker

при попытке создать новый объект и сохранить его в БД.

Я понимаю ошибку и то, как она обычно происходит, но в этом случае все, что я делаю, это создание нового объекта и добавление к нему перед ним int s, а не добавление каких-либо других объектов из других контекстов.

Я включил функцию, вызывающую ошибку. Как вы видите, это передается EndProduct, который является объектом, который отслеживается другим контекстом, чем тот, который находится в _billableRepository, но поскольку я не пытаюсь в любом случае назначить этот объект для вновь созданного оплачиваемого, я не как это может быть проблемой.

Единственный способ, которым я могу видеть, ошибка происходит потому, что несколько из int значений, которые назначены на новый Billable взяты из существующих EndProduct, который отслеживается с помощью другого контекста, но верно IEntityChangeTracker Безразлично» t отслеживать отдельные примитивы объекта?

public void AddBillable(EndProduct endProduct, int? purchaseId, string centreCode, int userId) 
{ 
    if (endProduct.Product != null) 
    { 
     var existingBillableForUserForProductId = _billableRepository.GetQuery(b => b.UserId == userId && b.ProductId == endProduct.ProductId); 
     if (endProduct.BillablePartId != null && !existingBillableForUserForProductId.Any()) 
     { 
      var billable = new Billable { 
       ProductId = endProduct.ProductId.Value, //int 
       UserId = userId, //int 
       PartId = endProduct.BillablePartId.Value, //int 
       DateAdded = DateTime.UtcNow, //datetime 
       PurchaseId = purchaseId, //int 
       CentreCode = centreCode //string 
      }; 

      _billableRepository.Add(billable); //error here 
      _billableRepository.UnitOfWork.SaveChanges(); 
     } 
    } 
} 
+0

Попробуйте это. _billableRepository.Billable.Add (оплачиваемый); _billableRepository.SaveChanges(); – NEER

+0

Вы правильно распоряжаетесь своим контекстом каждый раз? Вы должны инициализировать его прямо перед тем, как он вам понадобится, и утилизировать его как можно скорее. –

ответ

10

Наиболее вероятной причиной этого является использование любого инструмента для инъекций зависимости, который вы используете.

В игре на единицу работы должен быть только один DbContext. Если вы каждый раз новичок в новом, убедитесь, что старый из них удален.

В противном случае у вас будет несколько экземпляров одного и того же контекста, работающих рядом друг с другом.

Здесь трекер изменений смущен и не может отслеживать изменения ваших объектов.

+0

Возможно, вы правы.На данный момент мы вводим контекст для каждого репозитория, поэтому мы определенно имеем _do_ несколько параллельных контекстов. Это то, что мы пытаемся обновить по всей базе кода. В то же время нет простого способа переключиться на один контекст на запрос или аналогичный. Однако я не думал, что это будет иметь значение здесь, потому что, насколько я могу судить, здесь действительно играет только один контекст, который для '_billableRepository' – Anduril

1

Вы можете исправить, добавив свою сущность в репозиторий. Например:

_context.Set<T>.Attach(entity) 

Где установить свой DbSet в контексте.

+0

Это не поможет, если право на присоединение уже привязано к другому экземпляру контекст ... – Bartosz

1

Этот образец кода решит проблему;

public class DataModel 
    { 
     private static DBContext context; 
     public static DBContext Context 
     { 
      get 
      { 
       if (context == null) 
       { 
        context = new SozlukContext(); 
        return context; 
       } 
       return context; 
      } 
     } 
    } 
public class EntryRepository : IEntryRepository 
    { 
     DBContext _context = DataModel.Context; 
     public IEnumerable<Data.Model.Entry> GetAll() 
     { 
      return _context.Entry.Select(x => x); 
     } 
    } 
+0

Код только ответы arent рекомендуется, поскольку они не предоставляют много информации для будущих читателей, пожалуйста, предоставьте некоторое объяснение тому, что вы написали – WhatsThePoint

+0

Я думаю, что все ясно. У меня есть соединение и операция invoke. Соединение является статическим и вызывается один раз. Если внутренняя часть заполнена, она поворачивается. Таким образом, соединение выполняется один раз. –

+0

Наличие статического 'DbContext' является alaways, которое считается плохой практикой. Это может привести к нехватке памяти, проблемам с MultiThreading ('DbContext' не Threadsafe) и многое другое. Alaways используют один за то, что вы определяете * Единица работы *, и помните, какая «Сущность» зависит от того, какой «DbContext». Если 'DbContext' Disposed, вы можете либо связать Entity с другим Контекстом, либо работать с * Disconnected Entity *, где все необходимые данные уже кэшированы * (Eager Loading) *. Много информации для этой темы можно найти в Интернете. – LuckyLikey

2

На модели (GetById method) попробовать поставить что-то вроде этого:

var billable = _db.Billable.AsNoTracking().SingleOrDefault(i => i.BillableId == id);

Использование AsNoTracking() так, что она возвращает новый запрос, где объекты будут не следует кэшировать в System.Data.Entity.DbContext

+0

Это лучшее! –

+0

@TelsonAlva Спасибо! –

Смежные вопросы