编译查询失败-查询是针对不同于与指定DataContext关联的映射源的另一映射源进行编译的

时间:2018-12-09 20:01:32

标签: c# sql .net sql-server linq-to-sql

对于经编译的Linq2sql查询,我具有以下代码以对表中的行进行计数。尽管同一未编译查询运行顺利,但查询仍引发异常:

public static Func<ServiceCustomContext, int> CompiledCount
    = CompiledQuery.Compile((ServiceCustomContext db) => db.Current.Count());
public static int Count()
{
    using (ServiceCustomContext db = new ServiceCustomContext(Constants.NewSqlConnection))
        return CompiledCount(db);
}

ServiceCustomContext继承自DataContext,仅(除构造方法外)Table包括上面示例中使用的名为Current的表。

然后出现以下异常:

  

'查询是针对与映射源不同的映射源进行编译的   与指定的DataContext相关联。'

仅当使用如上所述的已编译查询时,此选项才可用。只要我有一个简单的方法:

return db.Current.Count();

Count()方法中,一切都很好。

我不明白怎么了。我认为可能是我需要保留对DataContext(ServiceCustomContext)的引用,尽管这似乎与直觉相反,但即使the Microsoft examples也不这样做。我发现的唯一解释是here,这基本上是上面链接的Microsoft示例中提到的编译查询确实是错误的。我怀疑那是真的。

1 个答案:

答案 0 :(得分:1)

如果在您的应用程序生存期内仅使用Count()一次,则代码将运行良好。错误的含义恰恰是它所说的。如果您查看CompiledQuery的代码:

    private object ExecuteQuery(DataContext context, object[] args) {
        if (context == null) {
            throw Error.ArgumentNull("context");
        }
        if (this.compiled == null) {
            lock (this) {
                if (this.compiled == null) {
                    this.compiled = context.Provider.Compile(this.query);
                    this.mappingSource = context.Mapping.MappingSource;
                }
            }
        }
        else {
            if (context.Mapping.MappingSource != this.mappingSource)
                throw Error.QueryWasCompiledForDifferentMappingSource();
        }
        return this.compiled.Execute(context.Provider, args).ReturnValue;
    }

您可以看到它的作用,它仅在第一次调用时才编译查询。它还会保存对您的DataContext.Mapping.MappingSource的引用,并确保在以后的每次调用中都使用相同的MappingSource

默认情况下,每次创建新的DataContext时,都会创建一个新的MappingSource。这是在构造函数中完成的,以后没有办法覆盖它,因为DataContext.MappingMetaModel.MappingSource属性都只有一个公共getter。但是,DataContext有一个构造函数重载,它以一个MappingSource作为参数(幸运的是)允许您在应用程序的整个生命周期内重用单个映射源。

不确定ServiceCustomContext类的确切构造函数是什么,但是以下代码应为您提供解决方案的提示,以防止发生错误:

public class ServiceCustomContext : DataContext
{
    private static readonly MappingSource mappingSource = new AttributeMappingSource();

    public ServiceCustomContext(string connection) : base(connection, mappingSource)
    {
    }
}

我假设您正在使用属性来声明映射,但是如果您使用XML文件进行数据库映射,则可以使用XmlMappingSource