Как отключить сущность из контекста в Entity Framework?

Я использую EF 4.1 с репозиторием и DbContext .. POCO с шаблоном T4. Для каждого репозитория я использую отдельный DbContext.

Мне нужно обновить объект с соответствующим свойством, на данный момент я получаю эту ошибку

An entity object cannot be referenced by multiple instances of IEntityChangeTracker. 

Я полагаю, что моя проблема – eventObj а candidate создается из разных Хранилищ.

Поэтому я пытаюсь решить проблему с этим кодом, без успеха.

Мой вопрос?

  • Как я могу избавиться от этой ошибки?
  • Возможно ли удалить кандидата из его контекста?

     public void UpdateAddingCandidate(Event eventObj, Candidate candidate){ Event updatedEvent = new Event(); Candidate updatedCandidate = new Candidate(); updatedEvent = eventObj; updatedCandidate = candidate; updatedEvent.Candidate = updatedCandidate; db.Entry(updatedEvent).State = EntityState.Modified; } 

РЕДАКТИРОВАТЬ

  public void UpdateAddingCandidate(Event eventObj, Candidate candidate) { /* db.Events.AsNoTracking(); db.Candidates.AsNoTracking(); */ db.Entry(eventObj).State = EntityState.Detached; db.Entry(candidate).State = EntityState.Detached; Event updatedEvent = new Event(); Candidate updatedCandidate = new Candidate(); updatedEvent = eventObj; updatedCandidate = candidate; updatedEvent.Candidate = updatedCandidate; db.Entry(updatedEvent).State = EntityState.Detached; db.Entry(updatedEvent).State = EntityState.Modified; } 

Эта ошибка действительно возникает, когда объект, который вы пытаетесь обновить, привязан к другому объекту contexttext, чем контекст, который вы используете для его обновления. Только один объектконтекст может отслеживать объект

Вы можете отделить объекты от контекста, вызвав:

где контекст – это контекст, к которому привязана сущность.

 using (var context = new UnicornsContext()) { var unicorn = new Unicorn { Name = "Franky", PrincessId = 1}; context.Entry(unicorn).State = EntityState.Detached; context.SaveChanges(); } 

http://blogs.msdn.com/b/adonet/archive/2011/01/29/using-dbcontext-in-ef-feature-ctp5-part-4-add-attach-and-entity-states.aspx

И в вашей реализации:

 public void UpdateAddingCandidate(Event eventObj, Candidate candidate) { db.Entry(candidate).State = EntityState.Detached; db.SaveChanges(); eventObj.Candidate = candidate; db.Entry(eventObj).State = EntityState.Modified; db.SaveChanges(); } 

Вместо использования шаблона репозитория также используйте шаблон «Единица работы». Таким образом, у вас есть 1 балл для каждого объекта, который вы используете.

Данные / Контракты / IRepository.cs

 namespace Data.Contracts { public interface IRepository where T : class { IQueryable GetAll(); T GetById(int id); void Add(T entity); void Update(T entity); void Delete(T entity); void Delete(int id); } 

Данные / Контракты / IUnitOfWork.cs

 namespace Data.Contracts { ///  /// Interface for the "Unit of Work" ///  public interface IUnitOfWork { // Save pending changes to the data store. void Commit(); // Repositories IRepository Events { get; } IRepository Candidates { get; } } } 

Данные / EFRepository.cs

 using System; using System.Data; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Linq; using Data.Contracts; namespace Data { ///  /// The EF-dependent, generic repository for data access ///  /// Type of entity for this Repository. public class EFRepository : IRepository where T : class { public EFRepository(DbContext dbContext) { if (dbContext == null) throw new ArgumentNullException("dbContext"); DbContext = dbContext; DbSet = DbContext.Set(); } protected DbContext DbContext { get; set; } protected DbSet DbSet { get; set; } public virtual IQueryable GetAll() { return DbSet; } public virtual T GetById(int id) { //return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate(id)); return DbSet.Find(id); } public virtual void Add(T entity) { DbEntityEntry dbEntityEntry = DbContext.Entry(entity); if (dbEntityEntry.State != EntityState.Detached) { dbEntityEntry.State = EntityState.Added; } else { DbSet.Add(entity); } } public virtual void Update(T entity) { DbEntityEntry dbEntityEntry = DbContext.Entry(entity); if (dbEntityEntry.State == EntityState.Detached) { DbSet.Attach(entity); } dbEntityEntry.State = EntityState.Modified; } public virtual void Delete(T entity) { DbEntityEntry dbEntityEntry = DbContext.Entry(entity); if (dbEntityEntry.State != EntityState.Deleted) { dbEntityEntry.State = EntityState.Deleted; } else { DbSet.Attach(entity); DbSet.Remove(entity); } } public virtual void Delete(int id) { var entity = GetById(id); if (entity == null) return; // not found; assume already deleted. Delete(entity); } } } 

Данные / UnitOfWork.cs

 using System; using Data.Contracts; using Data.Helpers; using Models; namespace Data { ///  /// The "Unit of Work" /// 1) decouples the repos from the controllers /// 2) decouples the DbContext and EF from the controllers /// 3) manages the UoW ///  ///  /// This class implements the "Unit of Work" pattern in which /// the "UoW" serves as a facade for querying and saving to the database. /// Querying is delegated to "repositories". /// Each repository serves as a container dedicated to a particular /// root entity type such as a . /// A repository typically exposes "Get" methods for querying and /// will offer add, update, and delete methods if those features are supported. /// The repositories rely on their parent UoW to provide the interface to the /// data layer (which is the EF DbContext in this example). ///  public class UnitOfWork : IUnitOfWork, IDisposable { public UnitOfWork(IRepositoryProvider repositoryProvider) { CreateDbContext(); repositoryProvider.DbContext = DbContext; RepositoryProvider = repositoryProvider; } // Repositories public IRepository Events { get { return GetStandardRepo(); } } public IRepository Candidates { get { return GetStandardRepo(); } } ///  /// Save pending changes to the database ///  public void Commit() { //System.Diagnostics.Debug.WriteLine("Committed"); DbContext.SaveChanges(); } protected void CreateDbContext() { DbContext = new UnicornsContext(); } protected IRepositoryProvider RepositoryProvider { get; set; } private IRepository GetStandardRepo() where T : class { return RepositoryProvider.GetRepositoryForEntityType(); } private T GetRepo() where T : class { return RepositoryProvider.GetRepository(); } private UnicornsContext DbContext { get; set; } #region IDisposable public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { if (DbContext != null) { DbContext.Dispose(); } } } #endregion } } 

Данные / Помощники / IRepositoryProvider.cs

 using System; using System.Data.Entity; using Data.Contracts; namespace Data.Helpers { ///  /// Interface for a class that can provide repositories by type. /// The class may create the repositories dynamically if it is unable /// to find one in its cache of repositories. ///  ///  /// Repositories created by this provider tend to require a  /// to retrieve data. ///  public interface IRepositoryProvider { ///  /// Get and set the  with which to initialize a repository /// if one must be created. ///  DbContext DbContext { get; set; } ///  /// Get an  for entity type, T. ///  ///  /// Root entity type of the . ///  IRepository GetRepositoryForEntityType() where T : class; ///  /// Get a repository of type T. ///  ///  /// Type of the repository, typically a custom repository interface. ///  ///  /// An optional repository creation function that takes a  /// and returns a repository of T. Used if the repository must be created. ///  ///  /// Looks for the requested repository in its cache, returning if found. /// If not found, tries to make one with the factory, fallingback to /// a default factory if the factory parameter is null. ///  T GetRepository(Func factory = null) where T : class; ///  /// Set the repository to return from this provider. ///  ///  /// Set a repository if you don't want this provider to create one. /// Useful in testing and when developing without a backend /// implementation of the object returned by a repository of type T. ///  void SetRepository(T repository); } } 

Данные / Помощники / RepositoryProvider.cs

 using System; using System.Collections.Generic; using System.Data.Entity; using Data.Contracts; namespace Data.Helpers { ///  /// Provides an  for a client request. ///  ///  /// Caches repositories of a given type so that repositories are only created once per provider. /// There should be aa new provider per client request. ///  public class RepositoryProvider : IRepositoryProvider { public RepositoryProvider(RepositoryFactories repositoryFactories) { _repositoryFactories = repositoryFactories; Repositories = new Dictionary(); } ///  /// Get and set the  with which to initialize a repository /// if one must be created. ///  public DbContext DbContext { get; set; } ///  /// Get or create-and-cache the default  for an entity of type T. ///  ///  /// Root entity type of the . ///  ///  /// If can't find repository in cache, use a factory to create one. ///  public IRepository GetRepositoryForEntityType() where T : class { return GetRepository>( _repositoryFactories.GetRepositoryFactoryForEntityType()); } ///  /// Get or create-and-cache a repository of type T. ///  ///  /// Type of the repository, typically a custom repository interface. ///  ///  /// An optional repository creation function that takes a DbContext argument /// and returns a repository of T. Used if the repository must be created and /// caller wants to specify the specific factory to use rather than one /// of the injected . ///  ///  /// Looks for the requested repository in its cache, returning if found. /// If not found, tries to make one using . ///  public virtual T GetRepository(Func factory = null) where T : class { // Look for T dictionary cache under typeof(T). object repoObj; Repositories.TryGetValue(typeof(T), out repoObj); if (repoObj != null) { return (T)repoObj; } // Not found or null; make one, add to dictionary cache, and return it. return MakeRepository(factory, DbContext); } ///  /// Get the dictionary of repository objects, keyed by repository type. ///  ///  /// Caller must know how to cast the repository object to a useful type. /// 

This is an extension point. You can register fully made repositories here /// and they will be used instead of the ones this provider would otherwise create.

///
protected Dictionary Repositories { get; private set; } /// Make a repository of type T. /// Type of repository to make. /// /// The with which to initialize the repository. /// /// /// Factory with argument. Used to make the repository. /// If null, gets factory from . /// /// protected virtual T MakeRepository
(Func factory, DbContext dbContext) { var f = factory ?? _repositoryFactories.GetRepositoryFactory(); if (f == null) { throw new NotImplementedException("No factory for repository type, " + typeof(T).FullName); } var repo = (T)f(dbContext); Repositories[typeof(T)] = repo; return repo; } /// /// Set the repository for type T that this provider should return. /// /// /// Plug in a custom repository if you don't want this provider to create one. /// Useful in testing and when developing without a backend /// implementation of the object returned by a repository of type T. /// public void SetRepository(T repository) { Repositories[typeof(T)] = repository; } /// /// The with which to create a new repository. /// /// /// Should be initialized by constructor injection /// private RepositoryFactories _repositoryFactories; } }

Данные / Помощники / RepositoryFactories.cs

 using System; using System.Collections.Generic; using System.Data.Entity; using Data.Contracts; namespace Data.Helpers { ///  /// A maker of Repositories. ///  ///  /// An instance of this class contains repository factory functions for different types. /// Each factory function takes an EF  and returns /// a repository bound to that DbContext. ///  /// Designed to be a "Singleton", configured at web application start with /// all of the factory functions needed to create any type of repository. /// Should be thread-safe to use because it is configured at app start, /// before any request for a factory, and should be immutable thereafter. ///  ///  public class RepositoryFactories { ///  /// Return the runtime repository factory functions, /// each one is a factory for a repository of a particular type. ///  ///  /// MODIFY THIS METHOD TO ADD CUSTOM FACTORY FUNCTIONS ///  private IDictionary> GetFactories() { return new Dictionary> { //If you have an custom implementation of an IRepository //{typeof(IArticleRepository), dbContext => new ArticleRepository(dbContext)} }; } ///  /// Constructor that initializes with runtime repository factories ///  public RepositoryFactories() { _repositoryFactories = GetFactories(); } ///  /// Constructor that initializes with an arbitrary collection of factories ///  ///  /// The repository factory functions for this instance. ///  ///  /// This ctor is primarily useful for testing this class ///  public RepositoryFactories(IDictionary> factories) { _repositoryFactories = factories; } ///  /// Get the repository factory function for the type. ///  /// Type serving as the repository factory lookup key. /// The repository function if found, else null. ///  /// The type parameter, T, is typically the repository type /// but could be any type (eg, an entity type) ///  public Func GetRepositoryFactory() { Func factory; _repositoryFactories.TryGetValue(typeof(T), out factory); return factory; } ///  /// Get the factory for  where T is an entity type. ///  /// The root type of the repository, typically an entity type. ///  /// A factory that creates the , given an EF . ///  ///  /// Looks first for a custom factory in . /// If not, falls back to the . /// You can substitute an alternative factory for the default one by adding /// a repository factory for type "T" to . ///  public Func GetRepositoryFactoryForEntityType() where T : class { return GetRepositoryFactory() ?? DefaultEntityRepositoryFactory(); } ///  /// Default factory for a  where T is an entity. ///  /// Type of the repository's root entity protected virtual Func DefaultEntityRepositoryFactory() where T : class { return dbContext => new EFRepository(dbContext); } ///  /// Get the dictionary of repository factory functions. ///  ///  /// A dictionary key is a System.Type, typically a repository type. /// A value is a repository factory function /// that takes a  argument and returns /// a repository object. Caller must know how to cast it. ///  private readonly IDictionary> _repositoryFactories; } } 

Теперь, если у вас есть это для использования UnitOfWork, вы не можете просто вызвать его из-за всех зависимостей, если вы использовали контейнер IoC, прежде чем знаете, что можете просто разрешить эти зависимости. В моем случае я использовал Ninject, поэтому код для его настройки:

 var kernel = new StandardKernel(); // Ninject IoC kernel.Bind().To().InSingletonScope(); kernel.Bind().To(); kernel.Bind().To(); 

Затем для ваших страниц вы можете добавить class базовой страницы:

Web.BasePage.cs

 namespace Web { public abstract class BasePage : System.Web.UI.Page { // NOT NECESSARY TO DISPOSE THE UOW IN OUR CONTROLLERS // Recall that we let IoC inject the Uow into our controllers // We can depend upon on IoC to dispose the UoW for us protected IUnitOfWork Uow { get; set; } } } 

Или в случае MVC вы можете добавить базовый controller:

Web / Контроллеры / BaseController.cs

 using System.Web.Mvc; namespace Site.Controllers { public abstract class BaseController : Controller { // NOT NECESSARY TO DISPOSE THE UOW IN OUR CONTROLLERS // Recall that we let IoC inject the Uow into our controllers // We can depend upon on IoC to dispose the UoW for us protected IUnitOfWork Uow { get; set; } } } 

Тогда в вашем коде, когда вы хотите получить доступ к своим сущностям, это очень просто. Вы можете просто вызвать UnitOfWork, который доступен на каждой странице и получить доступ к различным хранилищам в нем. Поскольку все они имеют один и тот же DbContext, ваша проблема перестает существовать.


Я сделал очень простой пример шаблона Unit of Work с поддержкой Ninject for Inversion of Control.

В моем примере есть пример ASP.NET Webforms AND и ASP.NET MVC4

Пример – это сайт с одной страницей, и каждый раз, когда вы загружаете сайт, он добавляет событие в базу данных примера и категорию в базу данных, как со случайными именами. (Мне нужно что-то для БД, поэтому я просто сделал 2 простых pocos). После этого на странице будет отображаться все в обоих списках. Просто загляните в Mvc4/Controllers/HomeController.cs или WebForms/Default.aspx.cs .

Пример по skydrive

Почему вы создаете новый экземпляр Event и Candidate ? Вы можете просто изменить состояние, которое у вас уже есть. Если вы используете один и тот же экземпляр объекта ObjectContext своих репозиториев, вы можете попытаться разрешить эти объекты из контекста с помощью ObjectStateManager.GetObjectStateEntry(string key) ObjectStateManager .

  • Как суммировать сумму в MongoDB, чтобы получить общий счет?
  • Поиск по нескольким коллекциям в MongoDB
  • Что лучше для хранилища данных Struct / Classes?
  • Структура объекта C ++ в памяти Vs a Struct
  • Реализация комментариев и комментариев в базе данных
  • Алгоритм анаграммы в java
  • C / C ++ Struct vs Class
  • MongoDB: структура агрегирования: получить последний датированный документ для идентификатора группы
  • Что такое оператор разматывания в MongoDB?
  • Печать значений всех полей в структуре C ++
  • Сложение структуры в C ++
  • Interesting Posts

    WatiN или Selenium?

    Flash-файлы (.swf) запрашивают загрузку вместо открытия

    Насколько хорошо IE7 / 8 режим в IE9 сравнивается с фактически запущенным IE7 / 8

    Вывод первого аргумента шаблона с другими параметрами шаблона по умолчанию

    Как сравнить две целые строки в листе

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

    Разделить строку, содержащую параметры командной строки, в строку в C #

    Проблемы с доставкой ПК, если я перееду за границу?

    Как использовать подмодуль Git с загруженной библиотекой Composer?

    Как интегрировать заставку для всех типов iPhone в XCode 6.1?

    Использование оператора нуль-условных чисел в левой части присваивания

    Как использовать динамическую схему весенних данных с помощью mongodb?

    Установите тайм-аут для webClient.DownloadFile ()

    Отправить запрос с параметрами с помощью «Дооснащения»

    Изменение цвета фона вкладки TabLayout (библиотека поддержки дизайна Android) не занимает все пространство вкладки

    Давайте будем гением компьютера.