我正在尝试使用EF5 Code First,我正在使用这些模型(如下所示)。
当我查看创建的数据库时,我很困惑,因为我在Track表中没有看到任何指向Category表的内容。类别的FK指向Track,但这意味着类别会有重复吗?
一点背景:我正在尝试构建一个具有轨道的模型,每个轨道可以有1到N个类别。所有类别都已定义,即它们基本上是一个查找,我计划在创建数据库时在种子方法中创建它们。
我想我不明白一些明显的东西...当我查询一首曲目时,我怎么知道它包含哪个类别?
THX
public class Track : IAuditInfo
{
public Int32 Id { get; set; }
public String Name { get; set; }
public String Description { get; set; }
public String Data { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime ModifiedOn { get; set; }
public ICollection<Category> Categories { get; set; }
public Track()
{
Categories = new List<Category>();
}
}
public class Category
{
public Int32 Id { get; set; }
public Boolean IsVisible { get; set; }
public String DisplayName { get; set; }
}
答案 0 :(得分:1)
您当前的模型是曲目和类别之间的一对多关系。 这通常是实现的,正如您已经注意到实体框架那样,在一侧(轨道)的许多方面(类别)使用外键。
如果我理解正确,你想要的是多对多的关系。许多曲目可以与同一类别相关,单个曲目可以属于许多类别。
要让实体框架了解您需要多对多关系,您只需将ICollection属性添加到类别类即可。 所以你的两个类都应该有另一个类的集合。 即曲目有许多类别,类别有很多曲目。
有关详细信息,您还可以看到:http://msdn.microsoft.com/en-us/data/hh134698.a.nospx
答案 1 :(得分:0)
Olav是对的,目前你的数据模型并没有告诉实体框架那里存在多对多的关系。
解决此问题的最简单方法是添加
public virtual ICollection<Track> Tracks { get; set; }
到你的Category
班。
但是......您可能不希望使用与您的域无关的人工制品污染您的域模型。更重要的是,当您以这种方式执行时,由实体框架决定要调用绑定表的内容。在EF6之前,这个命名是非确定性的(参见http://entityframework.codeplex.com/workitem/1677),这可能意味着编译相同代码的两台不同的机器将决定该表的不同名称并导致一些有趣的迁移问题。你的生产系统。
这两个问题的答案是始终使用Fluent配置明确管理多对多关系。
在您的数据上下文类中,覆盖OnModelCreating
,如下所示:
public class MyDb : DbContext
{
public IDbSet<Track> Tracks { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Track>()
.HasMany(t => t.Categories)
.WithMany()
.Map(c => c.ToTable("CategoriesForTracks"));
}
}
如果你这样做,你不需要为你的Category类添加一个导航属性,尽管你仍然可以(如果你这样做,你应该使用WithMany的重载,允许你指定一个属性。)
实体之间的关系以及如何将其映射到关系数据库本身就很难。除了最简单的父子关系之外,您还需要使用流畅的API来确保实际得到您想要的内容。
Morteza Manavi有一个really good blog series描述EF Code First中的关系,详尽无遗。
注意强>
您通常应该创建虚拟导航属性。所以,您应该像这样更改Category
类:
public virtual ICollection<Category> Categories { get; set; }
理论上,不使它成为虚拟应该只是导致急切加载而不是延迟加载。实际上,当我的导航属性不是虚拟的时候,我总是会发现许多微妙的错误。