我正在尝试在Entity Framework中创建多对多关系(代码优先),根据以下帖子:Database design for limited number of choices in MVC and Entity Framework?
然而,我无法让它正常工作,而且我确信我的做法非常简单。这是我的尝试中没有的图表:
联结表的要点是我需要在关系中有一个额外的属性Level,所以我不能只顾问顾问和程序之间的直接关系。我在设计器中手动添加了ConsultantProgramLink实体,然后分别向Program和Consultant添加了关联,选择为每个添加FK,然后将它们作为主键。但是,当我这样做时,它不能像我预期的那样工作:
如果我在顾问和程序之间建立了直接关联,我可以在我的代码中引用Consultant.Programs。但现在使用联结表不起作用。有没有办法解决这个问题,或者我是否总是需要通过交汇点属性(Consultant.ConsultantProgramLink.Programs)?在任何情况下,即使我尝试通过交汇处属性也无济于事。我可以在我的代码中做Consultant.ConsultantProgramLink,但是另一个点没有给我导航属性程序(由于某种原因它也变成了简单的程序,为什么?如果我最终可以访问它们,我可以重命名它们吗?)
那么我做错了什么?为什么我不能通过代码中的点表示法访问属性?
答案 0 :(得分:11)
将联结表作为实体建模后,确实会失去Consultant
和Program
之间的直接多对多关系。这就是它的工作原理。您将在联结表中具有直接的多对多关系或其他属性。不是都。如果您想要两者,可以尝试在Programs
上创建自定义Consultant
属性,并使用linq查询来获取相关程序:
public IEnumerable<Program> Programs
{
get
{
return this.ConsultantProgramLinks.Select(l => l.Program);
}
}
这个例子也解释了你的上一个问题。您不能在Program
上拥有ConsultantProgramLink
属性,因为它是相关实体的集合,而不是单个实体(应该称为ConsultantProgramLinks
)。 ConsultantProgramLink
实体中的属性仅称为Program
,因为它表示单个实体不是集合。
编辑:
如果您需要每个Program
自动与每个Consultant
关联,则必须在创建新Program
时强制执行该var program = new Program();
...
context.Programs.AddObject(program);
var ids = from c in context.Consultants
select c.Id;
foreach (var id in ids)
{
var link = new ConsultantProgramLink
{
ConsultantId = id,
Program = program
};
context.ConsultantProgramLinks.AddObject(link);
}
context.SaveChanges();
。将联结表暴露为单独的实体可能会让您轻松实现:
Consultant
如果添加新的{{1}},则必须以相同的方式创建指向所有程序的链接。
缺点是,如果你有1000个顾问,这个构造将创建1001个数据库插入,其中每个插入将在单独的往返数据库中执行。要避免它,唯一的选择是使用存储过程或触发程序表。