NHibernate SchemaUpdate永远不会更新我的架构

时间:2014-07-30 16:03:21

标签: sqlite nhibernate fluent-nhibernate

我正在开发一个使用NHibernate和FluentNHibernate的项目(我是两种技术的新手),我需要更新我的SQLite生产数据库的模式。 我阅读了许多帖子,这些帖子清楚地表明SchemaUpdate可以实现这一点(假设更新不具有破坏性,例如添加新的可空列而不删除它们),但我从未设法实现它。

我需要使用SQLite,但我也使用Postgres 9.3和SQL Server 2008 R2测试它总是失败。

为了简单起见,我创建了以下简单程序,以便创建一个简单的表,并在我第一次启动它时填充它。在第二次启动之前,我使用" StringValue2"取消注释了这三行。结果我期望用新列" StringValue2"扩展我的简单表。但表格从未更新。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SQLite;
using NHibernate;
using FluentNHibernate.Cfg.Db;
using System.Diagnostics;
using FluentNHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;
using FluentNHibernate.Mapping;

namespace SchemaUpdatePOC
{
    class Program
    {
        static ISessionFactory sessionFactory = null;

        static void Main(string[] args)
        {
            try
            {
                sessionFactory = CreateSessionFactory();
                AddRow("aaa1", 10, DateTime.Now, true, "123");
                AddRow("bbb1", 20, DateTime.Now.AddHours(1), false, "456");
                AddRow("ccc1", 30, DateTime.Now, true, "789");
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        private static ISessionFactory CreateSessionFactory()
        {
            try
            {
                // SQLite
                string connString = "Data Source=TestDB.s3db;Version=3;";
                IPersistenceConfigurer configurer = SQLiteConfiguration.Standard.ConnectionString(connString);

                // Postgres
                //string connString = "Server=localhost;database=TestDB;user id=postgres;password=postgres";
                //IPersistenceConfigurer configurer = PostgreSQLConfiguration.Standard.ConnectionString(connString);

                // SQL Server 2008
                //string connString = @"data source=.\SQLEXPRESS;initial catalog=TestDB;Integrated Security=True;";
                //IPersistenceConfigurer configurer = MsSqlConfiguration.MsSql2008.ConnectionString(connString);

                return Fluently.Configure()
                               .Database(configurer)
                               .Mappings(m => m.FluentMappings.Add(typeof(TestTblMap))
                               //.ExportTo(@"C:\delme\")
                               )
                               .ExposeConfiguration(BuildSchema)
                               .BuildSessionFactory();
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        private static void BuildSchema(NHibernate.Cfg.Configuration config)
        {
            //new SchemaExport(config).Create(true, true);
            new SchemaUpdate(config).Execute(true, true);
        }

        public static void AddRow(string stringValue, int intValue, DateTime datetimeValue, bool boolValue, string stringValue2)
        {
            try
            {
                using (var session = sessionFactory.OpenSession())
                {
                    using (var transaction = session.BeginTransaction())
                    {
                        TestTbl item = new TestTbl();
                        item.BoolValue = boolValue;
                        item.IntValue = intValue;
                        item.StringValue = stringValue;
                        item.DateTimeValue = datetimeValue;
                        //item.StringValue2 = stringValue2; // UNCOMMENT THIS LINE THE SECOND TIME YOU LAUNCH THE APPLICATION
                        session.Save(item);
                        transaction.Commit();
                    }
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public class TestTbl
        {
            public virtual int Id { get; protected set; }
            public virtual string StringValue { get; set; }
            //public virtual string StringValue2 { get; set; } // UNCOMMENT THIS LINE THE SECOND TIME YOU LAUNCH THE APPLICATION
            public virtual DateTime DateTimeValue { get; set; }
            public virtual int IntValue { get; set; }
            public virtual bool BoolValue { get; set; }
        }

        public class TestTblMap : ClassMap<TestTbl>
        {
            public TestTblMap()
            {
                Table("\"TestTbl\"");
                //Id(x => x.Id).CustomSqlType("Serial").Column("\"Id\"").Not.Nullable(); // use with postgres
                Id(x => x.Id).Column("\"Id\"").Nullable();
                Map(x => x.StringValue).Column("\"StringValue\"").Not.Nullable();
                //Map(x => x.StringValue2).Column("\"StringValue2\"").Nullable(); // UNCOMMENT THIS LINE THE SECOND TIME YOU LAUNCH THE APPLICATION
                Map(x => x.DateTimeValue).Column("\"DateTimeValue\"").Not.Nullable();
                Map(x => x.IntValue).Column("\"IntValue\"");
                Map(x => x.BoolValue).Column("\"BoolValue\"");
            }
        }
    }
}

当我第二次启动应用程序时(在使用&#34; StringValue2&#34;取消注释三行之后),我在控制台上获得的脚本始终如下:

create table "TestTbl" (
    "Id"  integer primary key autoincrement,
    "StringValue" TEXT not null,
    "StringValue2" TEXT,
    "DateTimeValue" DATETIME not null,
    "IntValue" INT,
    "BoolValue" BOOL
)

据我所知,在互联网上阅读我期待的是一个&#34; alter table&#34;而不是&#34;创建表&#34;,但除此之外,新列从未创建,并且由于缺少&#34; StringValue2&#34;以下插入语句失败。包含以下消息的列:

could not insert: [SchemaUpdatePOC.Program+TestTbl][SQL: INSERT INTO "TestTbl" ("StringValue", "StringValue2", "DateTimeValue", "IntValue", "BoolValue") VALUES (?, ?, ?, ?, ?); select last_insert_rowid()]

SQL logic error or missing database
table TestTbl has no column named StringValue2

NHibernate xml文件我取消了对该行的注释&#34; .ExportTo(@&#34; C:\ delme \&#34;)&#34;是:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="SchemaUpdatePOC.Program+TestTbl, SchemaUpdatePOC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="&quot;TestTbl&quot;">
    <id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="&quot;Id&quot;" not-null="false" />
      <generator class="identity" />
    </id>
    <property name="StringValue" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="&quot;StringValue&quot;" not-null="true" />
    </property>
    <property name="StringValue2" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="&quot;StringValue2&quot;" not-null="false" />
    </property>
    <property name="DateTimeValue" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="&quot;DateTimeValue&quot;" not-null="true" />
    </property>
    <property name="IntValue" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="&quot;IntValue&quot;" />
    </property>
    <property name="BoolValue" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="&quot;BoolValue&quot;" />
    </property>
  </class>
</hibernate-mapping>

我做错了什么? 现在整整一周,我都在努力解决这个非常基本的问题而且我疯了! :( 我试过的数据库是否支持UpdateSchema?

我使用的库的版本是:

NHibernate.dll 3.3.3.4000
FluentNHibernate.dll 1.3.0.733
System.Data.SQLite.dll 1.0.93.0 (when using SQLite)
npgsql.dll 2.0.13.91 (when using Postgres)

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

我刚检查了我的概念证据。

传递#1:

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

传递#2: (我在Pass#1中注释掉了这些行,并为我的实体对象添加了一个新的可空列)

        new SchemaUpdate(cfg).Execute(true, true);

在Pass#2上,我得到了

alter table dbo.MyEntity
  add MyNewColumn DATETIME

APPEND:

我得到了相同的结果,直到我改变了#34; Map&#34;到非分隔值。 如下所示。 也许那些额外的斜线搞砸了&#34;比较&#34;它创造而不是改变。

public class TestTblMap : ClassMap<TestTbl>
{
    public TestTblMap()
    {
        Table("TestTbl");
        //Id(x => x.Id).CustomSqlType("Serial").Column("\"Id\"").Not.Nullable(); // use with postgres
        Id(x => x.Id).Column("Id").Nullable();
        Map(x => x.StringValue).Column("StringValue").Not.Nullable();

        Map(x => x.DateTimeValue).Column("DateTimeValue").Not.Nullable();
        Map(x => x.IntValue).Column("IntValue");
        Map(x => x.BoolValue).Column("BoolValue");

        Map(x => x.StringValue2).Column("StringTwoRules").Nullable(); // UNCOMMENT THIS LINE THE SECOND TIME YOU LAUNCH THE APPLICATION
    }
}

通过上述内容,我得到了所需的&#34; alter table add StringTwoRules nvarchar(255)&#34;言。

偏离主题,但很有帮助。

您可以添加一些属性,如下所示,以在命令窗口中查看sql。

    private static void BuildSchema(NHibernate.Cfg.Configuration config)
    {

        // set parameters here like this:
        config.Properties["show_sql"] = "true";
        config.Properties["prepare_sql"] = "true";



        //new SchemaExport(config).Drop(true, true);
        ////re-create database
        //new SchemaExport(config).Create(true, true);


        new SchemaUpdate(config).Execute(true, true);
    }
相关问题