来自TPH继承中的子类型的LINQ .Include()属性

时间:2014-12-23 15:47:27

标签: c# json linq inheritance

我在Entity Framework中使用每层次表(TPH)继承。现在我希望得到一个列表 - 在这个例子中 - 部门可以是子类型。我希望集合中的项目包含他们自己的自定义属性,而不仅仅是基本模型的属性。

我怎样才能做到这一点?

public class Department
{
    public Department()
    {
        DepartmentType = this.GetType.Name;
    }
    public int Id {get; set;}
    public string DepartmentType {get; set;}
}

public class Finance : Department
{
    public virtual Manager Manager {get; set;}
}

public class Sports : Department
{
    public virtual Coach Coach {get; set;}
}


// This obviously crashes instantly
// How can I include Manager if type is Finance and Coach if type is Sports?
context.Departments
        .Include(c => (c is Finance) ? c.Manager : null)
        .Include(c => (c is Sports) ? c.Coach : null);

我甚至试图返回IEnumerable<object>并为每个子类型添加一个多态方法,如下所示:

public class Sports : Department
{
    public Coach Coach {get; set;}

    public object Export()
    {
        return new 
        {
            this.Id,
            this.DepartmentType,
            this.Coach
        }
    }
}

然后做这样的事情:

context.Departments.Select(c => c.Export())

但这也不起作用。

所需的JSON使用

[
    { Id: 1, DepartmentType: "Finance", Manager: { Name: "John" } },
    { Id: 2, DepartmentType: "Finance", Manager: { Name: "Harold" } },
    { Id: 3, DepartmentType: "Sport", Coach: { Name: "Fred", SportType: "Soccer" } },
    { Id: 4, DepartmentType: "Finance", Manager: { Name: "Hank" } },
    { Id: 5, DepartmentType: "Sport", Coach: { Name: "Mark", SportType: "Football" } }
]

2 个答案:

答案 0 :(得分:1)

通过这种方式,您可以找到财务和体育部门并包含其财产:

var financeDeparments = context.Departments.OfType<Finance>().Include(p => p.Manager).ToList();
var sportDepartments = context.Departments.OfType<Sports>().Include(p => p.Coach).ToList();

答案 1 :(得分:1)

将一个列表中的所有部门都可以序列化为JSON的方法是

var deparments = context.Departments.OfType<Finance>().Include(p => p.Manager)
                 .AsEnumerable()
                 .OfType<Department>()
                 .Union(
                 context.Departments.OfType<Sports>().Include(p => p.Coach)
                 ).ToList();

说明:

  1. OfType<Department>():您不能直接Union这两个列表。您必须将其中一个投放到IEnumerable<Department>才能Union另一个。但是......

  2. .AsEnumerable():如果你只进行演员表,EF会结束它与Depeartment的交易,并且它不会接受Include Manager的。{通过包含AsEnumerble,您可以在内存中进行后续演员,EF永远不会知道它。

  3. 我认为这只是一堆人为的代码,仅仅是为了序列化。

    完全不同的选项是确保在上下文处于活动状态时进行序列化,因此会触发延迟加载以填充导航属性。在这种情况下,您可以简单地序列化Department,并且您将在JSON中找到派生类型的所有属性。也许(如果实际模型比你展示的更复杂)你必须防止循环引用 如果Department的数量不是太大,我认为这是一个可行的选项,即使它会为延迟加载生成大量查询。