Fluent NHibernate:如何在多对多连接表上创建聚簇索引?

时间:2011-02-02 00:33:02

标签: sql nhibernate fluent-nhibernate azure-sql-database

为了在SQL Azure上使用我的Fluent NHibernate映射,我需要在每个表上都有一个聚簇索引。 Fluent NHibernate为多对多连接创建的默认堆表显然不会这样做,因为它们没有主键。

我希望能够告诉关系的一方为其连接表创建聚簇索引,但我不确定如何。这是我的映射的样子:

 public class UserMap : ClassMap<User>{
    public UserMap()
    {
        Table("Users");
        Id(x => x.UserId).GeneratedBy.Identity().Column("UserId");
        Map(x => x.UserName).Unique().Not.Nullable().Length(DataConstants.UserNameLength).Column("UserName");
        Map(x => x.Email).Unique().Not.Nullable().Length(DataConstants.EmailAddressLength).Column("Email");
        Map(x => x.Password).Not.Nullable().Length(DataConstants.PasswordHashLength).Column("Password");
        HasMany(x => x.Clicks).Cascade.AllDeleteOrphan();
        HasManyToMany(x => x.Roles).Cascade.SaveUpdate().Table("UsersInRole").ParentKeyColumn("UserId").
            ChildKeyColumn("RoleId");

    }
}

如果您需要更多信息,请与我们联系!

4 个答案:

答案 0 :(得分:5)

我不知道Fluent是否直接支持它(如果没有,只包括xml),但你可以用Auxiliary Database Objects

来支持它
<nhibernate-mapping>
  <database-object>
    <create>create clustered index ix on UsersInRole(UserId, RoleId)</create>
    <drop>drop index UsersInRole.ix</drop>
  </database-object>
</nhibernate-mapping>

答案 1 :(得分:2)

我遇到了与主题启动器相同的问题(因为我正在将Fluent NHibernate和Sql Azure结合起来)但是给定的答案并不满足。这是因为它不符合惯例。当然可以动态创建HBM文件,然后使用configuration.AddXmlFile("AddClusteredIndexesToManyToManyTables.hbm.xml");将其添加到配置中,但我只是不喜欢HBM文件,我无法想象有更好的方式。

几个小时后,我找到了另一个动态(可读!)的解决方案,并没有处理hbm xml文件。解决方案如下:

假设#1:我将为每个联结表创建一个复合主键,从而在SQL Server中生成聚簇索引。

在构建配置之后(因此解析了映射),(流畅的)NHibernate为我们提供了机会来查看configuration.ClassMappingsconfiguration.CollectionMappings的实际映射。使用后者是因为我们对多对多映射感兴趣。

foreach (var collectionMapping in configuration.CollectionMappings
    // Filter on many-to-many
    .Where(x => !x.IsOneToMany)) {
    // Build the columns (in a hacky way...)
    const string columnFormat = "{0}_id";
    var leftColumn = new Column(string.Format(
        columnFormat,
        collectionMapping.Owner.MappedClass.Name));
    var rightColumn = new Column(string.Format(
        columnFormat,
        collectionMapping.GenericArguments[0].Name));
    // Fetch the actual table of the many-to-many collection
    var manyToManyTable = collectionMapping.CollectionTable;
    // Shorten the name just like NHibernate does
    var shortTableName = (manyToManyTable.Name.Length <= 8)
                                ? manyToManyTable.Name
                                : manyToManyTable.Name.Substring(0, 8);
    // Create the primary key and add the columns
    var primaryKey = new PrimaryKey {
        Name = string.Format("PK_{0}", shortTableName),
    };
    primaryKey.AddColumn(leftColumn);
    primaryKey.AddColumn(rightColumn);
    // Set the primary key to the junction table
    manyToManyTable.PrimaryKey = primaryKey;
}

是的,获取左右列的逻辑之后,列有点hacky但它​​可以工作,你可以自由调整和编辑我的解决方案(^ _-)。问题是集合映射相当空/未填充。

祝你好运编码和创建约定!

答案 2 :(得分:0)

任何一组列都可以是聚簇索引...我不需要知道你为了构建聚簇索引而使用PK约束的强制措施。

更多我不明白客户端如何处理聚簇索引。它可能是make them as a default,但这与要求不同。这通常被报告为SQL Server的“最佳实践”,但对于客户端,列上的辅助b树索引与对表记录进行排序的聚簇索引之间没有真正的区别。客户如何区分数据的底层存储?一个存储由群集键排序的数据,另一个不存储。

也许fluent-nhibernate表现得更好,或声称 - 但它会在没有任何索引的情况下“正常工作”。

但我不是YMMV的专家。

答案 3 :(得分:-2)

伟大的解决方案M.Mimpen。

当需要map接口时,请将ChildKeyColumn与接口名称放在一起。

例: HasManyToMany(x =&gt; x.Acessos)。(“IRole_id”);

Acesso类实现了IRole接口。如果您没有通知子密钥名称,则创建的列将为“Acesso_id”,但创建密钥时将尝试“IRole_id”。