I have the following classes:
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; }
}
Basically, I have an asset, which is associated to an area. And there are different types of areas that can fit into a hierarchy.
I would now like to query all 'Assets' that are associated either directly with a specific area, or indirectly through it's parent. Is it possible to make such a query?
I feel like something like this, should be possible:
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 );
But it is not. Is it possible to do something like this?
As it turns out, I had not exhausitively tried every possibility of casting it (using cast/as) in combination with the "is" operator.
Basically the following two examples throws an exception specifying that the property is "not defined" (System.ArgumentException: Property 'Int64 ParentAreaId' is not defined for type 'Area')
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 );
and
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 );
And the next example throws a NullReferenceException (presumably because it actually uses the predicate to apply an additional filter after turning the expression into a sql query). Hence, if the area is not of the correct type, it will be null and therefore throw a NullReferenceException. (This is the example I posted in the original question)
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 );
However, the following actually works and it was basically the only combination I had not tried prior to posting this question (using both the both operators: 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 );
Basically, this means you should always use the "is/as" operators in your linq queries to EF Core (atleast for the SQL Server provider).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.