首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NHibernate SchemaExport无法删除表....有时

NHibernate SchemaExport无法删除表....有时
EN

Stack Overflow用户
提问于 2009-04-08 16:14:44
回答 4查看 7.2K关注 0票数 4

在执行单元测试之前,我使用NHibernate作为应用程序的DAL,并在particlular NHibernate的SchemaExport函数中删除/重新创建我的数据库模式。我遇到的问题是,当我运行单元测试并执行SchemaExport时,我的一个表每隔一次都无法删除。这会告诉我,有某种外键问题阻止了SchemaExport删除我的表--但是我不能确定。我的模式非常简单-一个person表、一个Address表和一个PersonAddress表来支持这两者之间的多对多关系。

代码语言:javascript
复制
public class Person
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<Address> Addresses {get;set;}

    public Person()
    {
        this.Addresses = new List<Address>();
    }

}

public class Address
{
    public virtual int Id { get; set; }
    public virtual string Street1 { get; set; }
    public virtual string Street2 { get; set; }
    public virtual string Postcode { get; set; }

}

还有我的NHibernate映射文件。

代码语言:javascript
复制
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="MyHibernate"
               namespace="MyHibernate"
               >
<class name="Person" table="Person.Person">
    <id name="Id" column="Id">
        <generator class="native" ></generator>
    </id>
    <property name="Name" column="Name" length="50"></property>
    <bag name="Addresses" table="[Person].[PersonAddress]" lazy="false" cascade="all">
        <key column="PersonId" foreign-key="FK_Person_Person_Id"></key>
        <many-to-many class="Address" column="AddressId"></many-to-many>
    </bag>
</class>

代码语言:javascript
复制
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
               assembly="MyHibernate"
               namespace="MyHibernate"
               >
<class name="Address" table="Person.Address">
    <id name="Id" column="Id">
        <generator class="native" ></generator>
    </id>
    <property name="Street1" column="Street1" length="50"></property>
    <property name="Street2" column="Street2" length="50"></property>
    <property name="Postcode" column="Postcode" length="50"></property>
</class>

当我运行` `var cfg = new Configuration();cfg.Configure();cfg.AddAssembly(typeof(Person).Assembly);

代码语言:javascript
复制
        new SchemaExport(cfg).Execute(false, true, false, false)

我得到一个SQL异常,说:

MyHibernate.Tests.GenerateSchemaFixture.Can_Generate_Schema: NHibernate.HibernateException :数据库中已存在名为“Person”的对象。-> System.Data.SqlClient.SqlException :数据库中已存在名为Person的对象。

有什么想法吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-04-16 14:32:17

找到了解决这个问题的方法。我刚刚把SchemaExport的用法分成了两个调用。第一个删除现有的模式,第二个重新创建它。

代码语言:javascript
复制
 var cfg = new Configuration();
 cfg.Configure();
 cfg.AddAssembly(typeof(Person).Assembly);

 SchemaExport se = new SchemaExport(cfg);
 //drop database 
 se.Drop(true, true);
 //re-create database
 se.Create(true, true);

在我的测试类的TestFixtureSetUp中使用上面的代码效果很好。我现在有了一个干净的数据库模式,可以用于集成测试。

票数 9
EN

Stack Overflow用户

发布于 2011-06-30 22:28:18

很长一段时间以来,这一直是我反复遇到的问题。执行drop first或使用execute方法( drop方法是执行Execute方法的快捷方法)不能解决此问题。

在查看了NHibernate源代码之后,我找到了问题的根源。NHibernate使用哈希码在数据库中存储外键名称。然而,hashcode的问题是,它们会随着时间、clr版本和appdomain而变化。您不能依赖hashcode来实现等价性。(参考:http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx)这就是为什么NHibernate不能总是删除外键,因此不能删除表。

这是NHibernate源码的快照,用于创建唯一的外键名称:

代码语言:javascript
复制
public string UniqueColumnString(IEnumerable iterator, string referencedEntityName)
{
    // NH Different implementation (NH-1339)
    int result = 37;
    if (referencedEntityName != null)
    {
        result ^= referencedEntityName.GetHashCode();
    }
    foreach (object o in iterator)
    {
        result ^= o.GetHashCode();
    }
    return (name.GetHashCode().ToString("X") + result.GetHashCode().ToString("X"));
}

所以这个问题不是NHibernate能解决的,你必须自己来解决。在创建模式之前,我通过执行以下方法解决了这个问题。该方法仅从使用NHibernate映射的表中删除所有外键:

代码语言:javascript
复制
private static void DropAllForeignKeysFromDatabase()
{
  var tableNamesFromMappings = Configuration.ClassMappings.Select(x => x.Table.Name);

  var dropAllForeignKeysSql =
    @"
      DECLARE @cmd nvarchar(1000)
      DECLARE @fk_table_name nvarchar(1000)
      DECLARE @fk_name nvarchar(1000)

      DECLARE cursor_fkeys CURSOR FOR
      SELECT  OBJECT_NAME(fk.parent_object_id) AS fk_table_name,
              fk.name as fk_name
      FROM    sys.foreign_keys fk  JOIN
              sys.tables tbl ON tbl.OBJECT_ID = fk.referenced_object_id
      WHERE OBJECT_NAME(fk.parent_object_id) in ('" + String.Join("','", tableNamesFromMappings) + @"')

      OPEN cursor_fkeys
      FETCH NEXT FROM cursor_fkeys
      INTO @fk_table_name, @fk_name

      WHILE @@FETCH_STATUS=0
      BEGIN
        SET @cmd = 'ALTER TABLE [' + @fk_table_name + '] DROP CONSTRAINT [' + @fk_name + ']'
        exec dbo.sp_executesql @cmd

        FETCH NEXT FROM cursor_fkeys
        INTO @fk_table_name, @fk_name
      END
      CLOSE cursor_fkeys
      DEALLOCATE cursor_fkeys
    ;";

    using (var connection = SessionFactory.OpenSession().Connection)
    {
      var command = connection.CreateCommand();
      command.CommandText = dropAllForeignKeysSql;
      command.ExecuteNonQuery();
    }
  }

对我来说太完美了。我希望其他人也能使用它。这就是我获取sql脚本以删除所有外键的地方:http://mafudge.mysite.syr.edu/2010/05/07/dropping-all-the-foreign-keys-in-your-sql-server-database/

票数 12
EN

Stack Overflow用户

发布于 2009-10-18 13:37:39

我也收到了这个错误消息;然而,这是因为我删除了一个与另一个类具有多对一关系的类。因此,没有任何东西告诉NHibernate在下一次测试运行时删除现在已孤立但仍被引用的表。

我只是简单地用手把它扔掉,一切都很好。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/730725

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档