首页 > 代码库 > The specified LINQ expression contains references to queries that are associated with different contexts

The specified LINQ expression contains references to queries that are associated with different contexts

今天在改写架构的时候,遇到这么个错误。当时单从字面意思,看上去错误是由join的两个不同的表来源不一致引起的。

image

其中的videoResult和deerpenList均来自与同一个edmx文件,所以两个表的来源不一致导致了错误的发生,这个猜想是不正确的。

正在左右为难之际,在stackoverflow上面发现了一个主题,正好解决了我的难题。这个问题的回答是这样的:

This can happen if your Context property returns a new instance every time

它的字面意思是:如果你的Context每次访问都返回一个新的实例的话,就会造成这个错误

回想起我之前的构造:

public interface IContext<T>:IDisposable where T:class{	DbContext DbContext{get;}	IDbSet DbSet{get;}}public class Context<T>:IContext<T> where T:class{	    public Context()        {            DbContext = new DbContext(ConfigurationManager.ConnectionStrings["GDeerGardenEntities"].ConnectionString);            DbSet = DbContext.Set<T>();        }        public void Dispose()        {            DbContext.Dispose();        }        public DbContext DbContext { get; private set; }        public IDbSet<T> DbSet { get; private set; }}

由于每次调用,都会新建一个DbContext,所以导致错误的发生。找到原因所在,就好了,我们只需要利用autofac这个ioc容器就行,使用的时候,从容器拿就行了。

所以打开安装器,输入

install-package autofac.mvc3 -project GDeerParkWeb

然后安装完毕,注入一下:

builder.RegisterGeneric(typeof(Context<>)).As(typeof(IContext<>)).SingleInstance();

本以为这样就没问题了。但是在使用的时候,依然会出现上述的错误。

到底原因在哪里呢? 这次排查的线索都断掉了。

想了好久,最后发现可能是泛型的Context存在问题,为什么呢?

因为在取实例化的时候,按照目前的设计,实例上下文应该是这样取得:

Context<bas_video>, Context<bas_deerpen>.

这样,带来的问题就显而易见了: 这两个上下文会产生两个不同的实例!!!!!!!

为什么会产生两个不同的实例呢? 因为泛型T只是一个占位符,当实例化出来的时候,泛型的上下文当然会拿不同的实例去hold住,这样就会造成在进行join操作的时候,出现开头的错误。

如果真是这样,那么我们把去掉,不就可以了吗?

这次我们的重构如下:

 public interface IContext    {        IDbSet<T> DbSet<T>() where T : class;        DbContext DbContext { get; }    }	 public class Context:DbContext,IContext    {        public Context()            : base("GDeerGardenEntities")        {}        public IDbSet<T> DbSet<T>() where T : class        {            return base.Set<T>();        }        public new DbContext DbContext        {            get;            private set;        }    }

我们的容器注入如下:

 builder.RegisterType<Context>().As<IContext>().SingleInstance();

最后上阵使用,wow,我们的错误消失了,看来最后的推测是对的。

谨以此文,权当抛砖引玉。

The specified LINQ expression contains references to queries that are associated with different contexts