根据以下帖子,我正在尝试在 Entity Framework (代码优先)中创建多对多关系:Database design for limited number of choices in MVC and Entity Framework?
但是,我无法让它正常工作,而且我确定我正在以错误的方式做一些非常简单的事情。这是我尝试中没有的图表:
联结表的要点是我需要在关系中拥有一个额外的属性 Level,所以我不能只使用顾问和程序之间的直接关系。我在设计器中手动添加了ConsultantProgramLink实体,然后分别给Program和Consultant添加关联,选择为每个添加一个FK,然后将它们设为主键。但是当我这样做时,它并没有按我预期的那样工作:
如果我在Consultant 和Program 之间建立了直接关联,我就可以在我的代码中引用Consultant.Programs。但这不适用于连接表。有什么办法可以解决这个问题,还是我总是必须通过连接属性(Consultant.ConsultantProgramLink.Programs)?无论如何,即使我确实尝试通过连接属性,它也无济于事。我可以在我的代码中执行Consultant.ConsultantProgramLink,但是另一个点不给我导航属性Programs(由于某种原因,它也变成了Program,为什么?如果最终可以访问它们,我可以重命名它们吗?) .
那么我做错了什么?为什么我不能通过我的代码中的点表示法访问属性?
最佳答案
一旦将连接表建模为实体,您确实会失去 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
,则必须以相同的方式创建指向所有程序的链接。缺点是,例如,如果您有 1000 名顾问,此构造将创建 1001 个数据库插入,其中每个插入将在到数据库的单独往返中执行。为了避免它,唯一的选择是在程序表上使用存储过程或触发器。