2

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

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

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

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

谢谢,

编辑(基于答案)

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

理想情况下,我希望拥有类似接口(或其他任何东西)的东西,这样我就可以在代码中拥有 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
4

3 回答 3

4

创建可为空的外键:

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

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

配置Note

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

Person和的配置Product

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

您也可以放开导航属性 fromNote到 aProduct或者Person如果您不需要它。这将使您的代码更简单。您可以Note保持原样,并将导航和外键属性添加到您的其他实体:

public class Person
{
    // properties..

    public int NoteId { get; set; }

    public virtual Note Note { get; set; }
}
于 2013-10-09T18:46:44.960 回答
3

编辑:全面考虑。这并没有解决第一个问题,我们只是添加了另一个表。为什么不添加一个映射到枚举的注释类型列。


根据您的上次编辑,这就是我将如何执行代码

public class Person {
    public int PersonId {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}

    public int NoteData NoteDataId{get;set;}

    [ForeignKey("NoteDataId")]
    public virtual NoteData NoteData{get;set;}
}

public class Product {
    public int ProductId {get;set;}
    public string Name {get;set;}

    public int NoteData NoteDataId{get;set;}

    [ForeignKey("NoteDataId")]
    public virtual NoteData NoteData{get;set;}
}

public class NoteData {
    public int NoteDataID {get;set;}

    public virtual List<Note> Notes {get;set;}
}    

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

    public int NoteData NoteDataId{get;set;}

    [ForeignKey("NoteDataId")]
    public virtual NoteData NoteData{get;set;}
}
于 2013-10-10T13:45:22.270 回答
0

我不确定它如何适用于 EF,但在我们的模型中,我们使用了一个通用的“父”属性来返回一个对象。这仅适用于您只有一个对象拥有该便笺并且引用该便笺的对象不多时。

public virtual object Parent { get; set; }

但是,我认为 EF 不会自动为您填充...

于 2013-10-09T19:24:55.510 回答