sqlite - NHibernate SchemaUpdate 从不更新我的架构

标签 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\"");
            }
        }
    }
}

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

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

根据我在互联网上阅读的理解,我期待一个“更改表”而不是“创建表”,但除此之外,从未创建新列,并且由于缺少“StringValue2”,以下插入语句失败包含以下消息的列:

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

我取消注释行“.ExportTo(@"C:\delme\")”后得到的 NHibernate xml 文件是:

<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:

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

第 2 关: (我注释掉了 Pass#1 中的行,并向我的实体对象添加了一个新的可为空的列)

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

在第 2 关,我得到了

alter table dbo.MyEntity
  add MyNewColumn DATETIME

附加:

我得到了与您相同的结果,直到我将“ map ”更改为非分隔值。 如下所示。 也许那些额外的斜杠搞砸了“比较”,它会去创建而不是改变。

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
    }
}

通过上述内容,我得到了所需的“alter table add StringTwoRules nvarchar(255)”语句。

偏离主题,但很有帮助。

您可以添加一些如下所示的属性,以在命令窗口中查看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);
    }

关于sqlite - NHibernate SchemaUpdate 从不更新我的架构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25041610/

相关文章:

java - Hibernate 每用户数据库

nhibernate - 如何将对象从反射转换为通用集合?

vb.net - 如何告诉 Fluent NHibernate 在不进行自动映射的情况下忽略特定属性?

.net - NHibernate 3.2 LINQ n+1 求解

.net - FluentNHibernate 为 bool 设置默认列值

java - 错误 : sqlite returned: error code = 1, msg = 没有这样的表

ios - sqlite 3 "SQL error ' 内存不足' (7)"objc

php - 如何在本地数据库中保存距离矩阵?

NHibernate session 管理

c# - 流畅的 nHibernate 配置