代码之家  ›  专栏  ›  技术社区  ›  ispiro

编译的查询失败-查询是为与指定的DataContext关联的映射源之外的其他映射源编译的。

  •  10
  • ispiro  · 技术社区  · 6 年前

    对于已编译的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 回复  |  直到 6 年前
        1
  •  1
  •   Imantas    6 年前

    如果只使用 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 ,一个新的 映射源 一起创建。这是在构造函数中完成的,以后无法将其重写为 DataContext.Mapping MetaModel.MappingSource 属性只有一个公共getter。但是,有一个构造函数重载 数据上下文 这需要一个 映射源 作为一个参数,它(幸运的是)允许您在应用程序的整个生命周期中重用单个映射源。

    不确定您的 ServiceCustomContext 类,但下面的代码应向您提供解决方案的提示,以防止发生错误:

    public class ServiceCustomContext : DataContext
    {
        private static readonly MappingSource mappingSource = new AttributeMappingSource();
    
        public ServiceCustomContext(string connection) : base(connection, mappingSource)
        {
        }
    }
    

    我假设您正在使用属性来声明映射,但是您可以使用 XmlMappingSource 以防在数据库映射中使用XML文件。