EF代码优先 - 渴望加载和过滤子类属性(继承)

时间:2013-03-16 17:13:10

标签: c# entity-framework inheritance ef-code-first

我有以下课程(过度简化):

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所在的ImageImage不是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'的导航属性。

我需要什么样的查询和/或模型架构更改才能完成此方法?

2 个答案:

答案 0 :(得分:6)

您可以通过以下方式在Where子句中编写过滤器:

.Where(t => t.Content is Image && !(t.Content as Image).Private)

然而,更大的问题是Include部分。 Author属性仅对派生类型Image存在,但Include将尝试加载基类型Content(没有Author属性)因为这是Content中导航属性Tag的类型。你不能在这里使用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就会自动将对象图放在一起,这样加载的代码就会填充ContentContent.AuthorPerson属性(,好像您已使用Include加载了导航属性。)

BTW:请求包含派生类型的导航属性的功能here on UserVoice。它与您的情况不完全相同,但在评论部分中甚至是针对您的情况的请求。

答案 1 :(得分:-1)

尝试将类定义更改为类似......

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; }
}

私人似乎不是一个好名字,因为它与公共或私人声明冲突。