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

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

Итак, я использую ASP.NET MVC 4 + Entity Framework + Ninject с использованием шаблона репозитория (я вижу много упоминаний шаблона репозитория + единицы работы? Это может быть потенциальным решением моей проблемы, но я не знаю, как это реализовать ).

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

context.Posts.Add(post);

Вот моя полная реализация:

Бетонное хранилище

public class EFBlogRepository : IBlogRepository
{
    private readonly EFDbContext context;

    public EFBlogRepository(EFDbContext dbcontext)
    {
        context = dbcontext;
    }

    //add post
    public int AddPost(Post post)
    {
        context.Posts.Add(post);
        context.SaveChanges();
        return post.PostID;
    }

    public Category Category(int id)
    {
        return context.Categories.FirstOrDefault(c => c.CategoryID == id);
    }

    public Tag Tag(int id)
    {
        return context.Tags.FirstOrDefault(t => t.TagID == id);
    }
}

Интерфейс

public interface IBlogRepository
{
    int AddPost(Post post);
    Category Category(int id);
    Tag Tag(int id);
}

Мой контроллер

public class AdminController : Controller
{
    private IBlogRepository repository;

    public AdminController(IBlogRepository repo)
    {
        repository = repo;
    }

    [HttpPost]
    public ContentResult AddPost(Post post)
    {
        string json;

        ModelState.Clear();

        if (TryValidateModel(post))
        {
            var id = repository.AddPost(post);

            json = JsonConvert.SerializeObject(new
            {
                id = id,
                success = true,
                message = "Post added successfully."
            });
        }
        else
        {
            json = JsonConvert.SerializeObject(new
            {
                id = 0,
                success = false,
                message = "Failed to add the post."
            });
        }
        return Content(json, "application/json");
    }
}

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

public class PostModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var post = (Post)base.BindModel(controllerContext, bindingContext);

        var repository = DependencyResolver.Current.GetService<IBlogRepository>();

        if (post.Category != null)
            post.Category = repository.Category(post.Category.CategoryID);

        var tags = bindingContext.ValueProvider.GetValue("Tags").AttemptedValue.Split(',');

        if (tags.Length > 0)
        {
            post.Tags = new List<Tag>();

            foreach (var tag in tags)
            {
                post.Tags.Add(repository.Tag(int.Parse(tag.Trim())));
            }
        }

        return post;
    }
}

и мой global.asax.cs

ModelBinders.Binders.Add(typeof(Post), new PostModelBinder());

Это мой преобразователь зависимостей Ninject

public class NinjectDependencyResolver: IDependencyResolver
{
    private IKernel kernel;

    public NinjectDependencyResolver()
    {
        kernel = new StandardKernel();
        AddBindings();
    }

    public object GetService(Type serviceType)
    {
        return kernel.TryGet(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return kernel.GetAll(serviceType);
    }

    private void AddBindings()
    {
        kernel.Bind<IBlogRepository>().To<EFBlogRepository>();
        kernel.Bind<IAuthProvider>().To<FormsAuthProvider>();
    }
}

person Mindless    schedule 13.08.2014    source источник


Ответы (1)


Вы должны привязать свой контекст к привязкам ninject как InRequestScope.

kernel.Bind<EFDbContext >().To<EFDbContext >().InRequestScope();

Как говорится в ошибке, одна сущность не может быть привязана более чем к одному контексту EF. Кажется, что вы извлекаете объект из одного контекста, а затем добавляете его в другой. Используя строку выше, вы говорите Ninject использовать один и тот же экземпляр контекста для обслуживания всех зависимостей в одном HTTP-запросе.

Создаются два репозитория. Один в контроллере IBlogRepository repository, а другой в связывателе модели var repository = DependencyResolver.Current.GetService<IBlogRepository>(). Перед исправлением в каждом репозитории был новый экземпляр контекста, вызывающий ошибку. После исправления оба репозитория будут совместно использовать один и тот же экземпляр контекста.

person rareyesdev    schedule 13.08.2014
comment
Спасибо, попробовал, ошибка все равно высвечивается. - person Mindless; 14.08.2014
comment
Еще раз спасибо, помня о вашем ответе, я загрузил расширение ninject mvc и удалил свой собственный преобразователь зависимостей, а затем добавил InRequestScope в свою привязку, теперь все работает нормально. - person Mindless; 14.08.2014
comment
@EricWang Возможно, следует использовать _kernel.Bind<IBlogRepository>().To<BlogRepository>().InSingletonScope(); - person baozi; 13.03.2015
comment
@baozi В этом действительно нет необходимости, потому что репозитории будут иметь одну и ту же зависимость EFDbContext и у них нет состояния. Никакого вреда от этого не будет. - person rareyesdev; 13.03.2015
comment
@EricWang Это интересно, потому что вчера у меня была та же проблема, и она исчезла после того, как я внес изменения. - person baozi; 13.03.2015