C# 两个iQueryTables上的LINQ to Entities.Concat()抛出NullReferencesException

C# 两个iQueryTables上的LINQ to Entities.Concat()抛出NullReferencesException,c#,entity-framework,linq,C#,Entity Framework,Linq,我有以下抽象概念: public interface IRepository<TEntity> { IQueryable<TEntity> Entities { get; } } 我想注意选择中的所有属性都是按正确顺序设置的 执行.Entities查询时,我得到一个NullReferenceException,它是从EntitiyFramework.dll抛出的,具有以下顶部堆栈跟踪: at System.Data.Entity.Core.Query.Pl

我有以下抽象概念:

public interface IRepository<TEntity>
{
    IQueryable<TEntity> Entities { get; }
}
我想注意选择中的所有属性都是按正确顺序设置的

执行
.Entities
查询时,我得到一个
NullReferenceException
,它是从
EntitiyFramework.dll
抛出的,具有以下顶部堆栈跟踪:

   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.VisitSetOp(SetOp op, Node n, AliasGenerator alias, Func`3 setOpExpressionBuilder)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.Visit(UnionAllOp op, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.UnionAllOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.Visit(FilterOp op, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.FilterOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.Visit(ConstrainedSortOp op, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.ConstrainedSortOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.BuildProjection(Node relOpNode, IEnumerable`1 projectionVars)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.Visit(PhysicalProjectOp op, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.PhysicalProjectOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator..ctor(Command itree, Node toConvert)
   at System.Data.Entity.Core.Query.PlanCompiler.ProviderCommandInfoUtils.Create(Command command, Node node)
   at System.Data.Entity.Core.Query.PlanCompiler.CodeGen.Process(List`1& childCommands, ColumnMap& resultColumnMap, Int32& columnCount)
   at System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Compile(List`1& providerCommands, ColumnMap& resultColumnMap, Int32& columnCount, Set`1& entitySets)
   at System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Compile(DbCommandTree ctree, List`1& providerCommands, ColumnMap& resultColumnMap, Int32& columnCount, Set`1& entitySets)
   at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition..ctor(DbProviderFactory storeProviderFactory, DbCommandTree commandTree, DbInterceptionContext interceptionContext, IDbDependencyResolver resolver, BridgeDataReaderFactory bridgeDataReaderFactory, ColumnMapFactory columnMapFactory)
   at System.Data.Entity.Core.EntityClient.Internal.EntityProviderServices.CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Core.Common.DbProviderServices.CreateCommandDefinition(DbCommandTree commandTree, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlanFactory.CreateCommandDefinition(ObjectContext context, DbQueryCommandTree tree)
   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlanFactory.Prepare(ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, Boolean streaming, Span span, IEnumerable`1 compiledQueryParameters, AliasGenerator aliasGenerator)
   at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
   at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__2[TResult](IEnumerable`1 sequence)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[TResult](Expression expression)
   at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)

我有一个强烈的印象,这可能是Entity Framework 6.1.3中的一个bug,但我不确定。我想知道这是否真的是一个bug,或者我正在做一些愚蠢的事情,经过3个小时的调查后我无法弄清楚。

这肯定是一个bug,因为你没有做错什么,而且例外是对用户非常不友好

有一个解决方法,但需要额外的编码。诀窍是使用中间投影到“平坦”数据类(因为bug在某种程度上与嵌套的
公司
投影相关),然后
Concat
,最后将所需的投影应用到连接的结果上。所有这些都不会影响最终的SQL查询,它应该是简单的
UNION-All

下面是它的外观:

public class CustomerRepository : IRepository<Customer>
{
    private readonly MyDbContext dbContext;

    public CustomerRepository(MyDbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public IQueryable<Customer> Entities => InternalCustomersData.Concat(ExternalCustomersData).Select(CustomerSelector);

    private IQueryable<Customer> InternalCustomers => InternalCustomersData.Select(CustomerSelector);

    private IQueryable<Customer> ExternalCustomers => ExternalCustomersData.Select(CustomerSelector);

    private IQueryable<CustomerData> InternalCustomersData =>
        from customer in dbContext.InternalCustomers
        select new CustomerData
        {
            Id = customer.Id,
            Name = customer.Name,       
            CompanyId = 1,
            CompanyName = "Company",
        };

    private IQueryable<CustomerData> ExternalCustomersData =>
        from customer in dbContext.ExternalCustomers
        select new CustomerData
        {
            Id = customer.Id,
            Name = customer.Name,       
            CompanyId = customer.Company.Id,
            CompanyName = customer.Company.Name,
        };

    private static readonly Expression<Func<CustomerData, Customer>> CustomerSelector = data => new Customer
    {
        Id = data.Id,
        Name = data.Name,
        Company = new Company
        {
            Id = data.CompanyId,
            Name = data.CompanyName,
        }
    };

    private class CustomerData
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int CompanyId { get; set; }
        public string CompanyName { get; set; }
    }
}
公共类CustomerRepository:IRepository
{
私有只读MyDbContext;
公共CustomerRepository(MyDbContext)
{
this.dbContext=dbContext;
}
public IQueryable Entities=>InternalCustomerData.Concat(ExternalCustomerData).Select(CustomerSelector);
private IQueryable InternalCustomers=>InternalCustomerData.Select(CustomerSelector);
private IQueryable ExternalCustomers=>ExternalCustomerData.Select(CustomerSelector);
私有IQueryable InternalCustomerData=>
来自dbContext.InternalCustomers中的customer
选择新CustomerData
{
Id=customer.Id,
Name=customer.Name,
CompanyId=1,
CompanyName=“公司”,
};
private IQueryable ExternalCustomerData=>
来自dbContext.ExternalCustomers中的客户
选择新CustomerData
{
Id=customer.Id,
Name=customer.Name,
CompanyId=customer.Company.Id,
CompanyName=customer.Company.Name,
};
私有静态只读表达式CustomerSelect=data=>new Customer
{
Id=data.Id,
Name=data.Name,
公司=新公司
{
Id=data.CompanyId,
Name=data.CompanyName,
}
};
私有类CustomerData
{
公共int Id{get;set;}
公共字符串名称{get;set;}
public int CompanyId{get;set;}
公共字符串CompanyName{get;set;}
}
}

烦人,但有效。

@DanielLorenz除非表中有重复项需要删除,否则无效。我怀疑根本没有复制品,所以没有必要特意去检查它们。@DanielLorenz不,不会的。这段代码永远不会运行,它只是用来构建转换成SQL的表达式,SQL在取消引用时传播空值,而不是抛出空值。这正是@Servy在这两个问题上所说的。我已经尝试了
.Union()
,它的行为方式与
.Concat()
相同(如中抛出了相同的异常),但这里的想法应该只是一个串联。请幽默我,然后做。包括公司的外部客户。Concat可能最终在内存中而不是在sql server上运行。您必须看到SQL在网络上运行,才能看到它具体在做什么。除非SQL甚至不能跨越网络,否则它肯定是一个bug,如果不是关键的,不要浪费时间。解决方法是为
Company.Id
提供非常量值,例如为
InternalCustomers
使用旧式属性get,并使用
var internalCompanyId=1;在db.InternalCustomers中从客户返回选择新客户{Id=customer.Id,Name=customer.Name,Company=new Company{Id=internalCompanyId,Name=“Company”,},}
对于
string
属性,不需要这样做,只需要对第一个值类型属性执行此操作。
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.VisitSetOp(SetOp op, Node n, AliasGenerator alias, Func`3 setOpExpressionBuilder)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.Visit(UnionAllOp op, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.UnionAllOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.Visit(FilterOp op, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.FilterOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.Visit(ConstrainedSortOp op, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.ConstrainedSortOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.VisitAsRelOp(Node inputNode)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.BuildProjection(Node relOpNode, IEnumerable`1 projectionVars)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator.Visit(PhysicalProjectOp op, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.PhysicalProjectOp.Accept[TResultType](BasicOpVisitorOfT`1 v, Node n)
   at System.Data.Entity.Core.Query.InternalTrees.BasicOpVisitorOfT`1.VisitNode(Node n)
   at System.Data.Entity.Core.Query.PlanCompiler.CTreeGenerator..ctor(Command itree, Node toConvert)
   at System.Data.Entity.Core.Query.PlanCompiler.ProviderCommandInfoUtils.Create(Command command, Node node)
   at System.Data.Entity.Core.Query.PlanCompiler.CodeGen.Process(List`1& childCommands, ColumnMap& resultColumnMap, Int32& columnCount)
   at System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Compile(List`1& providerCommands, ColumnMap& resultColumnMap, Int32& columnCount, Set`1& entitySets)
   at System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Compile(DbCommandTree ctree, List`1& providerCommands, ColumnMap& resultColumnMap, Int32& columnCount, Set`1& entitySets)
   at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition..ctor(DbProviderFactory storeProviderFactory, DbCommandTree commandTree, DbInterceptionContext interceptionContext, IDbDependencyResolver resolver, BridgeDataReaderFactory bridgeDataReaderFactory, ColumnMapFactory columnMapFactory)
   at System.Data.Entity.Core.EntityClient.Internal.EntityProviderServices.CreateDbCommandDefinition(DbProviderManifest providerManifest, DbCommandTree commandTree, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Core.Common.DbProviderServices.CreateCommandDefinition(DbCommandTree commandTree, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlanFactory.CreateCommandDefinition(ObjectContext context, DbQueryCommandTree tree)
   at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlanFactory.Prepare(ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, Boolean streaming, Span span, IEnumerable`1 compiledQueryParameters, AliasGenerator aliasGenerator)
   at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
   at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
   at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__2[TResult](IEnumerable`1 sequence)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable`1 query, Expression queryRoot)
   at System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[TResult](Expression expression)
   at System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](Expression expression)
Company = new Company
{
    Id = 0, //random number
    Name = "Hello",
},
public class CustomerRepository : IRepository<Customer>
{
    private readonly MyDbContext dbContext;

    public CustomerRepository(MyDbContext dbContext)
    {
        this.dbContext = dbContext;
    }

    public IQueryable<Customer> Entities => InternalCustomersData.Concat(ExternalCustomersData).Select(CustomerSelector);

    private IQueryable<Customer> InternalCustomers => InternalCustomersData.Select(CustomerSelector);

    private IQueryable<Customer> ExternalCustomers => ExternalCustomersData.Select(CustomerSelector);

    private IQueryable<CustomerData> InternalCustomersData =>
        from customer in dbContext.InternalCustomers
        select new CustomerData
        {
            Id = customer.Id,
            Name = customer.Name,       
            CompanyId = 1,
            CompanyName = "Company",
        };

    private IQueryable<CustomerData> ExternalCustomersData =>
        from customer in dbContext.ExternalCustomers
        select new CustomerData
        {
            Id = customer.Id,
            Name = customer.Name,       
            CompanyId = customer.Company.Id,
            CompanyName = customer.Company.Name,
        };

    private static readonly Expression<Func<CustomerData, Customer>> CustomerSelector = data => new Customer
    {
        Id = data.Id,
        Name = data.Name,
        Company = new Company
        {
            Id = data.CompanyId,
            Name = data.CompanyName,
        }
    };

    private class CustomerData
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int CompanyId { get; set; }
        public string CompanyName { get; set; }
    }
}