与实体框架中的联结表有多对多的关系?

时间:2011-03-24 11:06:32

标签: asp.net asp.net-mvc-3 entity-framework-4 junction-table

我正在尝试在Entity Framework中创建多对多关系(代码优先),根据以下帖子:Database design for limited number of choices in MVC and Entity Framework?

然而,我无法让它正常工作,而且我确信我的做法非常简单。这是我的尝试中没有的图表:

enter image description here

联结表的要点是我需要在关系中有一个额外的属性Level,所以我不能只顾问顾问和程序之间的直接关系。我在设计器中手动添加了ConsultantProgramLink实体,然后分别向Program和Consultant添加了关联,选择为每个添加FK,然后将它们作为主键。但是,当我这样做时,它不能像我预期的那样工作:

如果我在顾问和程序之间建立了直接关联,我可以在我的代码中引用Consultant.Programs。但现在使用联结表不起作用。有没有办法解决这个问题,或者我是否总是需要通过交汇点属性(Consultant.ConsultantProgramLink.Programs)?在任何情况下,即使我尝试通过交汇处属性也无济于事。我可以在我的代码中做Consultant.ConsultantProgramLink,但是另一个点没有给我导航属性程序(由于某种原因它也变成了简单的程序,为什么?如果我最终可以访问它们,我可以重命名它们吗?)

那么我做错了什么?为什么我不能通过代码中的点表示法访问属性?

1 个答案:

答案 0 :(得分:11)

将联结表作为实体建模后,确实会失去ConsultantProgram之间的直接多对多关系。这就是它的工作原理。您将在联结表中具有直接的多对多关系或其他属性。不是都。如果您想要两者,可以尝试在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个数据库插入,其中每个插入将在单独的往返数据库中执行。要避免它,唯一的选择是使用存储过程或触发程序表。