Code First两个具有其他对象的对象

时间:2013-10-09 18:43:37

标签: 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 ?
}

我如何知道某个音符是来自某个人还是一个产品? 我应该需要不同的类(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值。我认为如果不存在,EF将负责创建NoteDataId行。

编辑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

3 个答案:

答案 0 :(得分: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();

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

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


更新2

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

public class Person
{
    // properties..

    public int NoteId { get; set; }

    public virtual Note Note { get; set; }
}

答案 1 :(得分: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;}
}

答案 2 :(得分:0)

我不确定它对EF的作用,但在我们的模型中,我们使用返回对象的通用“Parent”属性。这仅在您拥有一个拥有该注释的对象且没有多个引用该注释的对象时才有效。

public virtual object Parent { get; set; }

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