【问题标题】:Many-to-Many fluent NHibernate mapping with SQL Azure使用 SQL Azure 进行多对多流畅的 NHibernate 映射
【发布时间】:2012-06-11 22:24:58
【问题描述】:

由于 SQL Azure 需要为每个表复制聚集索引(请参阅此处 http://blogs.msdn.com/b/sqlazure/archive/2010/05/12/10011257.aspx),我已将以下 MsSqlAzureDialect 添加到我的 MsSqlConfiguration:

public class MsSqlAzureDialect : MsSql2008Dialect
{
    public override string PrimaryKeyString
    {
        get { return "primary key CLUSTERED"; }
    }
}

但是,这并不能解决我目前在使用多对多表时遇到的问题。我目前的情况是,我有一个具有角色的用户,一个具有用户的角色。所以用户和角色之间存在多对多的关系,以及由 NHibernate 生成的链接表。所以在我的 UserAutomappingOverride 我有这样的东西:

public class UserAutomappingOverride : IAutoMappingOverride<User>
{
    public void Override(AutoMapping<User> mapping)
    {
        mapping.HasManyToMany(x => x.Roles).Cascade.SaveUpdate();
    }
}

这会导致 NHibernate 创建一个名为 RoleToUser 的链接表。但是,此表没有 PK,因此没有聚集索引。这是在 SQL Azure 中使用的无效表配置。

我尝试过像这样使用来自非流利 NHibernate 的数据库对象:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<nhibernate-mapping>
    <database-object>
        <create>create clustered index ix on RoleToUser(User_id, Role_id)</create>
        <drop>drop index RoleToUser.ix</drop>
    </database-object>
</nhibernate-mapping>

但尝试将非流利的 NHibernate 代码组合到流利的配置中是在黑暗中的尝试。但是它不起作用,因为错误提示“出于安全原因,此 XML 文档中禁止使用 DTD...”

注意:我使用 fluent NHibernate 进行代码优先数据库创建。所以我实际上是在使用我的实体和 AutomappingOverrides 在部署时生成数据库的架构。

任何帮助将不胜感激。

【问题讨论】:

    标签: c# azure fluent-nhibernate nhibernate-mapping azure-sql-database


    【解决方案1】:

    我有一个这样的结构,可以在 Azure 中工作

    CREATE TABLE [dbo].[ClientLabel](
        [ClientId] [bigint] NOT NULL,
        [LabelId] [bigint] NOT NULL,
     CONSTRAINT [PK_ClientLabel] PRIMARY KEY CLUSTERED 
    (
        [ClientId] ASC,
        [LabelId] ASC
    ) WITH (..) ON [PRIMARY]
    ) ON [PRIMARY]
    

    【讨论】:

    • 我很确定他理解他想要的最终结果,但主要是询问如何使用 nhibernate 和流利的 nhibernate 生成该脚本。
    • 是的,确切地说,我当然可以在 NHibernate 创建模式后向表中添加聚集索引,但我必须在 SQL 中手动执行此操作。我试图弄清楚如何在生成表时使用 fluent nhibernate 或 nhibernate 创建聚集索引。
    【解决方案2】:

    要使用主键生成映射表,您可以使用 IBag。根据我的研究,Fluent NHibernate 尚不支持此功能,但您可以使用 Fluent NHibernate 将 hbm 文件与您的类映射和/或自动映射一起映射,以获取 Fluent NHibernate 不直接支持的功能。

    这是一个将用户映射到角色的简单示例:

    Program.cs

    class Program
    {
        static void Main(string[] args)
        {
            DatabaseContextFactory.CreateSchema();
    
            var user = new User();
            user.Roles = new List<Role>();
            var role = new Role();
            user.Roles.Add(role);
    
            ISessionFactory sessionFactory = DatabaseContextFactory.CreateSessionFactory();
    
            using (ISession session = sessionFactory.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    session.SaveOrUpdate(role);
                    session.SaveOrUpdate(user);
                    transaction.Commit();
                }
            }
        }
    }
    

    DatabaseContextFactory.cs

    public static class DatabaseContextFactory
    {
        static ISessionFactory _sessionFactory;
        static Configuration _configuration;
    
        public static ISessionFactory CreateSessionFactory()
        {
            if (_sessionFactory == null)
            {
                _sessionFactory = Fluently.Configure()
                    .Database(MsSqlConfiguration.MsSql2008.ConnectionString(cs => cs.FromConnectionStringWithKey("SurrogateExample")))
                    .ExposeConfiguration(c => _configuration = c)
                    .Mappings(cfg => cfg.HbmMappings.AddFromAssemblyOf<Program>())
                    .BuildSessionFactory();
            }
    
            return _sessionFactory;
        }
    
        public static void CreateSchema()
        {
            CreateSessionFactory();
            new SchemaExport(_configuration).Execute(false, true, false);
        }
    }
    

    User.hbm.xml

    <?xml version="1.0" encoding="utf-8"?>
    
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                                         assembly="SurrogateManyToManyExample"
                       namespace="SurrogateManyToManyExample.Entities">
        <class name="User" table="[User]">
            <id name="Id">
                <generator class="guid.comb" />
            </id>
    
            <idbag name="Roles" table="UserInRole" lazy="true">
                <collection-id column="Id" type="Guid">
                    <generator class="guid.comb" />
                </collection-id>
                <key column="UserId" />
                <many-to-many column="RoleId" class="Role" fetch="join" />
            </idbag>
        </class>
    </hibernate-mapping>
    

    Role.hbm.xml

    <?xml version="1.0" encoding="utf-8"?>
    
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                                         assembly="SurrogateManyToManyExample"
                       namespace="SurrogateManyToManyExample.Entities">
        <class name="Role" table="[Role]">
            <id name="Id">
                <generator class="guid.comb" />
            </id>       
        </class>
    </hibernate-mapping>
    

    【讨论】:

    • idbag 正是我所需要的。不幸的是,NHibernate 的流利抽象还没有公开这一点,因为我讨厌必须将 hbm xml 文件添加到我的流利项目中。感谢您的回答!
    • 啊,一件事我直到现在才注意到...现在我必须为 hbm 文件的类节点内的实体添加所有属性,因为它就像 hbm 文件映射现在优先于我在 C# 实体上的自动映射。
    【解决方案3】:

    所以@Derek Greer 的回答很棒。但是,我不希望有太多混合的 nhibernate 和流畅的 nhibernate 环境造成的混乱。

    所以我最终做的是添加一个专门用于添加聚集索引的 hbm 文件,因为这些都是将聚集索引添加到 SQL Azure 链接表的小技巧。这样,每当在自动映射中流畅地向对象添加多对多关系时,开发人员都可以手动向文件添加一行,如下所示。这实际上非常接近我之前找到的答案,但我只是对非流利的 nhibernate 了解得不够多,无法知道我在加载 hbm 文件时做错了什么。所以,这里是:

    ManyToManyClusteredIndexes.hbm.xml

    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
    namespace="Bookstore.Data.HbmMappings"
    assembly="Bookstore.Data.HbmMappings">
        <database-object>
            <create>create clustered index ix on RoleToUser(User_id, Role_id)</create>
            <drop>drop index RoleToUser.ix</drop>
        </database-object>
        <database-object>
            <create>create clustered index ix on RoleToRoleGroup(RoleGroup_id, Role_id)</create>
            <drop>drop index RoleToRoleGroup.ix</drop>
        </database-object>
    </hibernate-mapping>
    

    【讨论】:

    • 这很好用。需要注意的是,xml 文件需要将“构建操作”设置为“嵌入”。有一天,我希望能够在没有 HBM 文件的情况下做到这一点……也许是方言?谁知道呢。
    【解决方案4】:

    我现在研究这个主题很长时间了,因为我不想改变流畅的 nhibernate 和 nhibernate 代码,所以我决定做这个解决方法:

    我已经有一个控制台应用程序正在初始化数据库环境(本地或天蓝色), 在流畅的 nhibernate db 创建结束后,我刚刚删除了 ManyToMany 表,并按照 azure 的预期重新创建了它们:

    drop table ProfileLikes
    CREATE TABLE ProfileLikes(
        [ProfileID] [bigint] NOT NULL,
        [LikeID] [bigint] NOT NULL,
        PRIMARY KEY CLUSTERED 
    (
        [ProfileID],[LikeID]  ASC
    )
    ) 
    
    ALTER TABLE ProfileLikes  WITH CHECK ADD  CONSTRAINT [FK6FB4BC1C85106EB3] FOREIGN KEY([LikeID])
    REFERENCES [dbo].[Likes] ([Id])
    ALTER TABLE ProfileLikes CHECK CONSTRAINT [FK6FB4BC1C85106EB3]
    
    ALTER TABLE ProfileLikes  WITH CHECK ADD  CONSTRAINT [FK6FB4BC1CA12A6EC5] FOREIGN KEY([ProfileID])
    REFERENCES Profiles ([Id])
    
    ALTER TABLE ProfileLikes CHECK CONSTRAINT [FK6FB4BC1CA12A6EC5]
    

    希望对您有所帮助。 阿米尔

    【讨论】:

      猜你喜欢
      • 2012-07-16
      • 1970-01-01
      • 2016-01-17
      • 2011-08-30
      • 2011-06-28
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 2010-11-22
      相关资源
      最近更新 更多