繁体   English   中英

在EF Core中使用TPH时,将属性称为查询中的子类型

[英]Referring to properties as substypes in queries when using TPH in EF Core

我有以下课程:

   public abstract class Area
   {
      public long Id { get; set; }

      [Required]
      public string Name { get; set; }

      public ICollection<Asset> Assets { get; set; }
   }

   public class AreaWithParent : Area
   {
      public AreaAsParent ParentArea { get; set; }

      public long ParentAreaId { get; set; }
   }

   public class AreaAsParent : Area
   {
      public ICollection<AreaWithParent> AreasWithParent { get; set; }
   }

   public class Asset
   {
      public long Id { get; set; }

      public long? AreaId { get; set; }

      public Area Area { get; set; }
   }

基本上,我有一个与区域关联的资产。 并且可以将不同类型的区域放入一个层次结构中。

现在,我想查询直接与特定区域关联或通过其父区域间接关联的所有“资产”。 可以进行这样的查询吗?

我觉得这样的事情应该可行:

    var areaId = /* the area id I want to query for */

    var assets = await ctx.Assets
       .Where( x => x.AreaId == areaId || ( x.Area as AreaWithParent ).ParentAreaId == areaId )
       .ToListAsync( cancellationToken );

但事实并非如此。 有可能做这样的事情吗?

事实证明,我并没有穷尽地尝试结合“ is”运算符对它进行铸造(使用cast / as)的所有可能性。

基本上,以下两个示例引发一个异常,该异常指定该属性为“未定义”(System.ArgumentException:未为类型“ Area”定义属性“ Int64 ParentAreaId”)

var areaId = /* the area id I want to query for */

var assets = await ctx.Assets
   .Where( x => x.AreaId == areaId || ( (AreaWithParent)x.Area ).ParentAreaId == areaId )
   .ToListAsync( cancellationToken );

var areaId = /* the area id I want to query for */

var assets = await ctx.Assets
   .Where( x => x.AreaId == areaId || ( x.Area is AreaWithParent && ( (AreaWithParent)x.Area ).ParentAreaId == areaId ) )
   .ToListAsync( cancellationToken );

下一个示例将引发NullReferenceException(大概是因为它实际上在将表达式转换为sql查询之后使用谓词来应用其他过滤器)。 因此,如果区域的类型不正确,则该区域将为null,并引发NullReferenceException。 (这是我在原始问题中发布的示例)

var areaId = /* the area id I want to query for */

var assets = await ctx.Assets
   .Where( x => x.AreaId == areaId || ( x.Area as AreaWithParent ).ParentAreaId == areaId )
   .ToListAsync( cancellationToken );

但是,以下方法实际上有效,并且基本上是我在发布此问题之前未尝试的唯一组合(使用两个运算符:is / as):

var areaId = /* the area id I want to query for */

var assets = await ctx.Assets
   .Where( x => x.AreaId == areaId || ( x.Area is AreaWithParent && ( x.Area as AreaWithParent ).ParentAreaId == areaId ) )
   .ToListAsync( cancellationToken );

基本上,这意味着您应该始终在对EF Core的linq查询中使用“ is / as”运算符(对于SQL Server提供程序至少)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM