EF代码优先-预先加载和过滤子类属性(继承)
本文关键字:属性 子类 过滤 继承 加载 代码 EF | 更新日期: 2023-09-27 18:04:19
我有以下类(过于简化):
public class Person
{
public int ID { get; set; }
}
public class Content
{
public int ID { get; set; }
}
public class Image : Content
{
public bool Private { get; set; }
public Person Author { get; set; }
}
public class Tag
{
public int ID { get; set; }
public Content Content { get; set; }
public Person Person { get; set; }
}
我想得到所有的Tags
,其中Content
是Image
, Image
不是Private
(同时急切地加载Image
的属性)。尝试这样做,但不工作的例子:
var tags = context.Tags
.Include("Content.Author")
.Include("Person")
.Where(t => !((Image)t.Content).Private);
得到以下错误:
无法将"内容"类型强制转换为"图像"类型。LINQ to Entities只支持转换EDM基本类型或枚举类型。
删除Where
子句后:
指定的包含路径无效。EntityType 'Content'没有声明名为'Author'的导航属性。
我需要什么样的查询和/或模型模式更改才能完成这种方法?
您可以在Where
子句中按照以下方式编写过滤器:
.Where(t => t.Content is Image && !(t.Content as Image).Private)
然而,更大的问题是Include
部分。Author
属性只存在于派生类型Image
,但Include
将尝试加载基本类型Content
(没有Author
属性),因为这是Tag
中导航属性Content
的类型。你不能在这里使用Include
。
您可以尝试将查询重写为投影:
var tags = context.Tags
.Where(t => t.Content is Image && !(t.Content as Image).Private)
.Select(t => new
{
Tag = t,
Image = t.Content as Image, // possibly this line is not needed
Author = (t.Content as Image).Author,
Person = t.Person
})
.AsEnumerable()
.Select(x => x.Tag)
.ToList();
只要您不禁用更改跟踪(例如,使用AsNoTracking
) EF应该自动将对象图放在一起,以便加载的标签具有填充的Content
, Content.Author
和Person
属性(就好像您已经使用Include
加载了导航属性)。
顺便说一句:包含派生类型的导航属性的功能是在UserVoice上请求的。这与您的情况不完全相同,但在评论部分是一个请求,甚至适合您的场景。
尝试将类定义更改为…
class Person
{
public int ID { get; set; }
}
class Content
{
public int ID { get; set; }
}
class Image : Content
{
public bool IsPrivate { get; set; }
public virtual Person Author { get; set; }
}
class Tag
{
public int ID { get; set; }
public Content Content { get; set; }
public Person Person { get; set; }
}
Private似乎不是个好名字,因为它与public或Private声明冲突。