3

为了在 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

4 回答 4

5

我不知道 Fluent 是否直接支持它(如果没有,只需包含 xml),但您可以使用辅助数据库对象来做到这一点

<nhibernate-mapping>
  <database-object>
    <create>create clustered index ix on UsersInRole(UserId, RoleId)</create>
    <drop>drop index UsersInRole.ix</drop>
  </database-object>
</nhibernate-mapping>
于 2011-02-02T02:12:01.547 回答
2

我在与主题启动器相同的问题上苦苦挣扎(因为我也在结合 Fluent NHibernate 和 Sql Azure),但给定的答案并不令人满意。这是因为按照惯例它不是动态的。当然,可以动态创建 HBM 文件并将其添加到配置中,configuration.AddXmlFile("AddClusteredIndexesToManyToManyTables.hbm.xml");但我只是不喜欢 HBM 文件,我无法想象有更好的方法。

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

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

在构建配置之后(因此解析映射),(Fluent)NHibernate 为我们提供了使用configuration.ClassMappings和来查看实际映射的机会configuration.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,但它可以工作,您可以自由调整和编辑我的解决方案(^_-)。问题是集合映射相当空/未填充。

祝编码和创建约定好运!

于 2012-06-12T11:43:29.143 回答
0

任何一组列都可以是聚集索引......我不需要知道哪个会迫使您使用 PK 约束来构建聚集索引。

此外,我不明白客户端如何需要聚集索引。它可能使它们成为默认值,但这与要求不同。这通常被报告为 SQL Server 的“最佳实践”,但对于客户端而言,列上的二级 b 树索引和对表记录进行排序的聚集索引之间没有真正的区别。客户端如何能够区分数据的底层存储?一个存储按集群键排序的数据,另一个不存储。

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

但我也不是 YMMV 的专家。

于 2011-02-02T00:41:30.297 回答
-2

很好的解决方案 M.Mimpen。

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

例如:HasManyToMany(x => x.Acessos).("IRole_id");

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

于 2015-03-26T21:38:38.767 回答