实体对象不能由IEntityChangeTracker误差的多个实例被引用 [英] An entity object cannot be referenced by multiple instances of IEntityChangeTracker error

查看:231
本文介绍了实体对象不能由IEntityChangeTracker误差的多个实例被引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我所知有很多重复这个问题,但我无法找到一个适合我的方案。

所以,我现在用的是ASP.NET MVC 4 +实体框架+ Ninject使用存储库模式(我看到很多提到库+单位工作模式的?这可能是一个潜在的修复我的问题,但我不知道如何实现它)。

当我尝试添加一个新的岗位,我得到错误的下面一行code的实体对象不能被IEntityChangeTracker的多个实例引用

  context.Posts.Add(岗位);

下面是我的全面实施:

混凝土库

 公共类EFBlogRepository:IBlogRepository
{
    私人只读EFDbContext背景;    公共EFBlogRepository(EFDbContext的DbContext)
    {
        上下文=的DbContext;
    }    //添加后
    公众诠释AddPost(后后)
    {
        context.Posts.Add(岗位);
        context.SaveChanges();
        返回post.PostID;
    }    公共分类分类(INT ID)
    {
        返回context.Categories.FirstOrDefault(C => c.CategoryID == ID);
    }    公共标签标签(INT ID)
    {
        返回context.Tags.FirstOrDefault(T => t.TagID == ID);
    }
}

接口

 公共接口IBlogRepository
{
    INT AddPost(后后);
    分类分类(INT ID);
    标签标签(INT ID);
}

我的控制器

 公共类AdminController:控制器
{
    私人IBlogRepository库;    公共AdminController(IBlogRepository回购)
    {
        库=回购;
    }    [HttpPost]
    公共ContentResult类型AddPost(后后)
    {
        JSON字符串;        ModelState.Clear();        如果(TryValidateModel(岗位))
        {
            VAR ID = repository.AddPost(岗位);            JSON = JsonConvert.SerializeObject(新
            {
                ID = ID,
                成功= TRUE,
                消息=后添加成功。
            });
        }
        其他
        {
            JSON = JsonConvert.SerializeObject(新
            {
                ID = 0,
                成功=假,
                消息=无法添加的职位。
            });
        }
        返回内容(JSON,应用/ JSON);
    }
}

我不认为任何上述的是问题的根源,我认为这个问题是在我的自定义模型联

 公共类PostModelBinder:DefaultModelBinder
{
    公众覆盖对象BindModel(ControllerContext controllerContext,ModelBindingContext的BindingContext)
    {
        VAR =后(POST)base.BindModel(controllerContext,BindingContext中);        变种库= DependencyResolver.Current.GetService< IBlogRepository>();        如果(post.Category!= NULL)
            post.Category = repository.Category(post.Category.CategoryID);        VAR标签= bindingContext.ValueProvider.GetValue(标签)AttemptedValue.Split('')。        如果(tags.Length大于0)
        {
            post.Tags =新的List<吊牌及GT;();            的foreach(在标签var标记)
            {
                post.Tags.Add(repository.Tag(int.Parse(tag.Trim())));
            }
        }        返回岗位;
    }
}

和我的global.asax.cs

  ModelBinders.Binders.Add(typeof运算(POST),新PostModelBinder());

这是我的Ninject依赖解析器

 公共类NinjectDependencyResolver:的IDependencyResolver
{
    私人的iKernel内核;    公共NinjectDependencyResolver()
    {
        内核=新StandardKernel();
        AddBindings();
    }    公共对象GetService的(类型的serviceType)
    {
        返回kernel.TryGet(的serviceType);
    }    公共IEnumerable的<对象> GetServices(类型的serviceType)
    {
        返回kernel.GetAll(的serviceType);
    }    私人无效AddBindings()
    {
        kernel.Bind&所述; IBlogRepository方式>()到< EFBlogRepository>();
        kernel.Bind&所述; IAuthProvider方式>()到< FormsAuthProvider>();
    }
}


解决方案

您应该ninject绑定上下文绑定为 InRequestScope

  kernel.Bind< EFDbContext>()到<&EFDbContext GT;()InRequestScope()。

作为错误说,一个实体不能被绑定到多个EF上下文。看来您检索从一个上下文实体,然后将它添加到一个不同的。使用上面你告诉Ninject使用相同的上下文实例,以服务于同一个HTTP请求所有依赖行了。

正在创建的两个仓库。一个控制器 IBlogRepository库和其他模型中的粘合剂变种库= DependencyResolver.Current.GetService< IBlogRepository>()。修复之前,每个库有上下文的新实例,从而导致错误。此修复程序后,两个库将共享上下文的同一个实例。

I understand there are a lot of duplicates to this question, but I couldn't find one that fits my scenario.

So I am using the ASP.NET MVC 4 + Entity Framework + Ninject using repository pattern (I see many mentions of repository + unit of work pattern? That could be a potential fix to my problem but I don't know how to implement it).

When I try to add a new post, I get "An entity object cannot be referenced by multiple instances of IEntityChangeTracker" error on the following line of code

context.Posts.Add(post);

Here is my full implementation:

Concrete repository

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);
    }
}

Interface

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

My controller

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");
    }
}

I don't think any of the above are the root of the problem, I think the problem is in my custom model binder

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;
    }
}

and my global.asax.cs

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

This is my Ninject dependency resolver

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>();
    }
}

解决方案

You should bind your context in ninject bindings as InRequestScope

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

As the error says, one entity cannot be bound to more than one EF context. It seems that you are retrieving the entity from one context and then adding it to a different one. Using the line above you are telling Ninject to use the same context instance to serve all dependencies in the same HTTP request.

Two repositories are being created. One in the controller IBlogRepository repository and the other in the model binder var repository = DependencyResolver.Current.GetService<IBlogRepository>(). Before the fix each repository have a new instance of the context, causing the error. After the fix, both repositories will share the same instance of the context.

这篇关于实体对象不能由IEntityChangeTracker误差的多个实例被引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆