【发布时间】:2016-12-22 18:05:08
【问题描述】:
我知道 Code-First 使用约定进行模型绑定,这是默认情况下可用(并且是活动的?)的 list of conventions。
似乎多对多关系的联结表名称的选择有点随机..
使用哪些参考约定来确定联结表名称?用于确定该名称的算法是什么?
【问题讨论】:
标签: .net entity-framework-4.1 code-first
我知道 Code-First 使用约定进行模型绑定,这是默认情况下可用(并且是活动的?)的 list of conventions。
似乎多对多关系的联结表名称的选择有点随机..
使用哪些参考约定来确定联结表名称?用于确定该名称的算法是什么?
【问题讨论】:
标签: .net entity-framework-4.1 code-first
我认为,多对多连接表名的一般规则是
ClassNameOfLeftEntity + PluralizedClassNameOfRightEntity
所以,如果第一个实体是User,第二个是Role,则连接表名称是UserRoles。
这可能会受到删除PluralizingTableNameConvention 的影响,但我不确定。
更大的问题是确定什么是“左”,什么是“右”实体。我认为这几乎取决于随机因素,例如 EF 构建模型的顺序,而模型又取决于实体之间的导航属性以及您在派生上下文中编写 DbSets 的顺序。因此,强烈建议使用 Fluent API 显式定义连接表名称。您的模型中的一个小改动或在您的上下文中更改集合的顺序可以 EF 让我们认为名称必须是 RoleUsers 而不是之前的 UserRoles。
这是reference to a similar answer。
编辑
始终使用 Fluent API 明确定义多对多映射的另一个原因(与表名问题没有太大关系,而是更多地与应该是左侧实体和右侧实体的问题相关)是性能。
连接表具有复合主键和该键上的聚集索引(至少在 SQL Server 中)。现在假设表名称为RoleUsers,左侧实体为Role,右侧实体为User,因为可能某些开发人员决定在上下文中按字母顺序对集合进行排序:
public DbSet<Role> Roles { get; set; }
public DbSet<User> Users { get; set; }
连接表条目如下所示:
RoleId UserId
----------------
1 1
1 2
2 1
2 2
3 1
3 2
现在,您的应用程序中的大多数查询可能都对获取给定用户的角色感兴趣。但是您并不经常或从不对获取给定角色的所有用户感兴趣。可以通过Include 查询给定用户的角色:
var user = context.Users.Include(u => u.Roles).Single(u => u.UserId == 1);
这将在连接表中的UserId 上在 SQL 中创建一个 JOIN:ON Users.UserId = RoleUsers.UserId。此连接不能使用连接表中的索引,而是会导致表扫描以检索表中的第 1、3 和 5 行以获取用户的 RoleId。
更好的查询性能是将User 作为左实体,Role 作为右实体,从而为 (UserId, RoleId) 对生成一个聚集索引,这对于性能更好此类查询。 (您当然可以在上面的示例中创建第二个索引来提高性能。)为此,您必须使用 Fluent API 指定映射。
因此,明智地选择左右实体而不是将决定权交给 EF 是有意义的。
【讨论】: