开发与实体框架兼容的数据模型

时间:2019-03-01 10:21:02

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

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

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

enter image description here

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

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

除该表ItemReference之外,还包含项之间的子母关系。例如,狗与人之间存在儿童-父母关系(狗主人-狗或人可能是兄弟姐妹)

我需要按字母顺序列出狗和人的清单(将它们混合在一起)。此外,我需要能够进入以下每个详细信息页面。

使用这种方法确实很愚蠢,因为将来可能会有更多的表。例如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"

1 个答案:

答案 0 :(得分:2)

您的对象图并不完全清楚。看来DogPersonItem相关,但是根据您的描述和简短的代码示例,它们似乎实际上是类型的项目。如果是这样,您应该采用继承策略,而不是合成。

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表中。外键将被添加到指向Dogs表的PersonsItems表上。例如,当您检索Dog时,EF将自动加入Items中的相应记录以创建完整的Dog

这将为您的查询提供一些特殊功能。当然,您可以使用_context.Items来获取所有项,无论类型如何,但是您也可以将DbSetDog分别使用Person来查询那些独立的:例如_context.Dogs。即使没有显式的DbSet,也可以使用通用的Set<TEntity>方法:_context.Set<Dog>()。此外,您可以使用OfType<TEntity>来过滤Items_context.Items.OfType<Dog>()

最后,即使您仅检索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表上产生一堆可为空的外键,这将是一团糟,并且会破坏规范化。