をスローLINQは、私は、次の抽象化を持ってNullReferencesException
public class CustomerRepository : IRepository<Customer>
{
private readonly MyDbContext dbContext;
public CustomerRepository(MyDbContext dbContext)
{
this.dbContext = dbContext;
}
public IQueryable<Customer> Entities => InternalCustomers.Concat(ExternalCustomers);
private IQueryable<Customer> InternalCustomers =>
from customer in dbContext.InternalCustomers
select new Customer
{
Id = customer.Id,
Name = customer.Name
Company = new Company
{
Id = 1,
Name = "Company",
},
};
private IQueryable<Customer> ExternalCustomers =>
from customer in dbContext.ExternalCustomers
select new Customer
{
Id = customer.Id,
Name = customer.Name
Company = new Company
{
Id = customer.Company.Id,
Name = customer.Company.Name,
},
};
}
私は冗長な性質を省略し、これを単純化してきました問題を強調する例
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public Company Company { get; set; }
}
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
}
私がしたい:
クラスCustomer
.InternalCustomers
と.ExternalCustomers
マッピングしています)です注には、select
のすべてのプロパティが正しい順序で設定されています。 .Entities
クエリを実行すると
、私は次のトップスタックトレースで、EntitiyFramework.dll
からスローされNullReferenceException
を、取得しています:
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)
あなたが見ることができるように、例外メッセージとスタックトレースは役立ちません。私。特に、LINQ to Entitiesが構築している「マジック」表現木では、(少なくとも私のために)謎のパズルを調査しています。
だから私は、リポジトリの実装にいくつかのマイナーな改良を行なったし、私は次の観察に来ました:
- のみ InternalCustomersを実行し、私は、データベースから有効なリストを取得します。
- ExternalCustomersのみを実行すると、データベースから有効なリストも取得します。
- .Concat()メソッドを使用すると、例外が発生しているようです。
- 私はExternalContactsのための次のコードスニペットを持っているときに例外が発生しません:
コードスニペット:
Company = new Company
{
Id = 0, //random number
Name = "Hello",
},
私は、これはバグかもしれないという強い印象を取得していますエンティティフレームワーク6.1.3しかし、わかりません。私はこれが実際にバグか、私が3時間の調査の後で分からない何かばかげたことをしているかどうかを知りたいと思います。
@DanielLorenz削除する必要があるテーブルに重複がない限りは、そうではありません。私は重複が全くないと思うので、あなたの方法を調べてそれらをチェックする必要はありません。 – Servy
@DanielLorenzいいえ、そうではありません。そのコードは決して実行されません。SQLに変換される式を作成するために使用され、投げられるのではなく逆参照されるとSQLはNULL値を伝播します。 – Servy
@Servyが両方の質問について正確に何を言いますか?私は '.Union()'と同じ方法で '.Concat()'と同じように動作しましたが(同じ例外をスローする場合と同じですが)、ここでの考え方は単に連結でなければなりません。 – QuantumHive