【问题标题】:Developing Entity Framework compatible data model开发实体框架兼容的数据模型
【发布时间】:2019-03-01 23:15:49
【问题描述】:

我正在尝试首先使用实体​​框架代码为 c# .net Core 应用程序开发数据模型。

我基本上拥有的是下面的数据模型。

有表DogPerson。它们各自包含不同的信息。例如,我可以养不同类型的狗。人可以有一些特定的东西,这不适用于狗。

PersonItem 之间存在 1:1 的关系。 DogItem 之间的关系相同。

除此之外,ItemReference 还包含 Item 之间的子父关系。例如狗和人之间存在子父关系(狗主人-狗或人可能是兄弟姐妹)

我需要按字母顺序列出狗和人(将它们混合在一起)。此外,我需要能够访问以下各项的详细信息页面。

使用这个感觉真的很愚蠢,因为将来可能会有更多的表。例如CatCar,我每次都需要修改这些If 语句。

@foreach (var x in Model.Item.OrderBy(y=>y.ItemName))
{
    if (x.ItenType == "Dog")
    {
        <li><a asp-page="DogDetails" asp-route-id="@x.Item.Dog.Id">@x.ItemName</a></li>
    }
    if (x.ItenType == "Person")
    {
        <li><a asp-page="PersonDetails" asp-route-id="@x.Item.Person.Id">@x.ItemName</a></li>
    }
}

有谁知道如何制作这样一个数据模型,所以它是更智能的设计?

非常感谢任何帮助

DogPersonItem 将如下所示:

Id  DogName     DogTypeId   DogStatusId ItemId
1   "Alex"      1           1           1
2   "Rex"       2           1           2

Id  PersonName  PersonStatusId      ItemId
1   "Joe"       1                   3     
2   "Jane"      2                   4

物品

Id  ObjectName   ItemType
1   "Alex"       "Dog"
2   "Rex"        "Dog"
3   "Joe"        "Person"
4   "Jane"       "Person"

【问题讨论】:

    标签: c# entity-framework asp.net-core


    【解决方案1】:

    您的对象图并不完全清楚。看起来DogPerson 只是与Item 相关,但根据您的描述和简短的代码示例,它们实际上是项目的类型。如果是这种情况,您应该使用继承策略,而不是组合。

    public class Item
    
    public class Dog : Item
    
    public class Person : Item
    

    默认情况下,EF 将使用 TPH(按层次结构表)策略处理继承,这在此处似乎不合适。相反,我认为您会想要 TPT(每种类型的表),这可以通过在派生类上使用 Table 属性来实现:

    [Table("Dogs")]
    public class Dog : Item
    
    [Table("Persons")]
    public class Person : 
    

    这将创建三个表,DogsPersonsItems。所有项目共有的任何数据,无论是狗还是人,显然都会出现在您的 Item 类中,最终会出现在 Items 表中。将在指向Items 表的DogsPersons 表上添加外键。例如当你检索到一个Dog时,EF会自动加入Items中的对应记录,创建一个完整的Dog

    这会给你一些特殊的查询能力。当然,无论类型如何,您通常都可以使用_context.Items 获取所有项目,但您也可以为DogPerson 提供单独的DbSets,允许您独立查询这些项目:例如_context.Dogs。即使没有显式的DbSet,您也可以使用通用的Set&lt;TEntity&gt; 方法:_context.Set&lt;Dog&gt;()。此外,您可以使用OfType&lt;TEntity&gt; 过滤Items 集:_context.Items.OfType&lt;Dog&gt;()

    最后,即使您只是检索Items,EF 仍会跟踪每个Item 的最终类型,这意味着您可以执行模式匹配等操作:

    if (item is Dog dog)
    {
        // `dog` is now a variable in this scope of your `item` downcast to `Dog`
    }
    

    或者在 switch 语句中:

    switch (item) 
    {
        case Dog dog:
            // do something with `dog`
            break;
        case Person person:
            // do something `person`
            break;
        default:
            // do something with generic items (`item`)
            break;
    }
    

    编辑

    我意识到我只是暗示了以下内容,而不是明确说明。由于DogPerson 在TPT 中是完全不同的表,因此您可以在那里定义完全不同的关系。例如,Dog 可以与DogStatus 建立关系,而不会影响与Person 发生的任何事情。从技术上讲,即使使用 TPH,您仍然可以执行此操作,但您最终会在 Items 表上得到一堆可为空的外键,这将是一团糟,而且还会破坏规范化。

    【讨论】:

    • 非常感谢克里斯 - 我什至不知道 TPT 和 TPH 如此重要。我做了很多阅读,我想我现在可以解决我的问题了。
    • 我尝试使用 TPT 解决我的情况,但没有为继承的类创建新表。有一个带有鉴别器列的项目表 - 这基本上是我已经拥有的东西。我读到了一些关于 EF Core 不支持 TPT 的内容,您能否确认这一点,或者是否有一些解决方法?提前致谢
    猜你喜欢
    • 1970-01-01
    • 2017-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多