c# - 代码首先有两个对象有其他对象

标签 c# asp.net-mvc database entity-framework ef-code-first

首先使用实体​​框架代码我有这个:

public class Person {
    public int PersonId {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
    public virtual List<Note> Notes {get;set;}
}

public class Product {
    public int ProductId {get;set;}
    public string Name {get;set;}
    public virtual List<Note> Notes {get;set;}
}

public class Note {
    public int NoteId {get;set;}
    public string Body {get;set;}
    public virtual User Author {get;set;}
    // what should be here ?
}

我如何知道一条注释是来自人还是来自产品? 我应该为此需要不同的类(class)(PersonNote、ProductNote)吗? 我可以使用接口(interface)方法吗?喜欢 INoteable 吗?

我不确定要建模的数据库或类的最佳策略是什么。 任何建议表示赞赏。

谢谢,

编辑(根据答案)

建议的答案意味着对于每个有注释的实体,表格都会有一个我不太喜欢的新列。有没有办法使用鉴别器?我不喜欢每次新实体可以有注释时修改表格的想法,如果我有 10 个支持注释的实体,则可能最终得到 10 FK(9 始终为空)。

理想情况下,我希望拥有类似接口(interface)(或其他任何东西)的东西,这样我就可以在代码中拥有 Product : INoteable,这意味着可以使用此 ID 创建便笺。 也许有一个鉴别器列。这可能吗?

抱歉第一次没说清楚。

在现实生活场景中,我喜欢:产品、人员、采购订单、销售、付款、付款订单,以及我需要实现注释的更多实体。

编辑 2:

这个数据库结构怎么样:

TABLE: Note
int PK NoteId
int FK NoteDataId
string Body

TABLE: Person
int PK PersonId 
int FK NoteDataId

TABLE: Product
int PK ProductId
int FK NoteDataId

TABLE: NoteData
int PK NoteDataId

有了这个数据结构,所有想要实现 Notes 的实体我只需添加一个导航属性 NoteDataId 并且在创建笔记时,我只需提供 NoteDataId 值。我认为如果 NoteDataId 行不存在,EF 会负责创建它。

编辑 3:

示例数据:

Person:
PersonId 1
Name Bart
NoteDataId 1

PersonId 2
Name Alex
NoteDataId 2

Product:
ProductId 1
Name "Dulce de Leche"
NoteDataId 3

NoteData:
NoteDataId 1
NoteDataId 2
NoteDataId 3

Note:
NoteId 1
NoteDataId 1
Body "first note"

NoteId 2
NoteDataId 1
Body "second note of Bart"

NoteId 3
NoteDataId 2
Body "first note of Alex"

NoteId 4
NoteDataId 3
Body "Note about Dulce de Leche"

如何获取某人的笔记?

SELECT * FROM Note
JOIN NoteData USING (NoteDataId)
JOIN Person USING (NoteDataId)
WHERE PersonId = 1

向后?

SELECT * FROM Note
JOIN NoteData USING (NoteDataId)
LEFT JOIN Person USING (NoteDataId) 'can be null, only one type exists'
LEFT JOIN Product using (NoteDataId) 'can be null, only one type exists'
WHERE NoteId = 2

最佳答案

创建可为空的外键:

public class Note {
    public int NoteId {get;set;}
    public string Body {get;set;}
    public virtual User Author {get;set;}

    public int? PersonId { get; set; }
    public virtual Person Person { get; set; }

    public int? ProductId { get; set; }
    public virtual Product Product { get; set; }
}

您必须将属性映射为可选。

注释的配置:

Property(n => n.PersonId).IsOptional();
Property(n => n.ProductId).IsOptional();

PersonProduct 的配置:

Property(p => p.Note).IsOptional();


更新:

您还可以使用 table-per-hierarchy解决方案。

保持 Note 不变(不妨将其抽象化)并创建派生类型。例如PersonNote:

public clas PersonNote : Note 
{   
    public int PersonId { get; set; }
    public virtual Person Person { get; set; }
}

Person 获取导航属性的地方:

public virtual PersonNote Note { get; set; }

ProductNote:

public clas ProductNote : Note 
{   
    public int ProductId { get; set; }
    public virtual Product Product { get; set; }
}

Product 获取导航属性的地方:

public virtual ProductNote Note { get; set; }

Entity Framework 将创建一个Note 表,其中包含所有 派生类型的属性和一个discriminator 列。但这会导致您的代码中有很多类,但在我看来这并不是一件坏事。


更新 2

如果不需要,您也可以放弃从 NoteProductPerson 的导航属性。这将使您的代码更加简单。您可以保留 Note 原样,并将导航和外键属性添加到您的其他实体:

public class Person
{
    // properties..

    public int NoteId { get; set; }

    public virtual Note Note { get; set; }
}

关于c# - 代码首先有两个对象有其他对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19280113/

相关文章:

c# - 分布式锁不适用于RedLock.net

c# - AngularJs $http.post 不渲染新 View

c# - 使用 C# 从 NHibernate 连接到 AS400 (iSeries) 时出现错误 RROR [08001] [IBM] SQL30081N

C# 使用 GroupBy 查询 MongoDB

javascript - 发布表单数据时的 Fetch-api 错误处理

ASP.Net MVC 使用路由处理段

javascript - Bootbox 回调表单提交无法正常工作

mysql - 如何在mysql中将创建表的数据类型指定为select?

php - 我想使用 mysql 数据库的内容显示不同的页面

c# - WPF ListBox 将 SelectedItem 值发送到 View 模型