我正在开发一个使用 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=""TestTbl"">
<id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name=""Id"" 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=""StringValue"" not-null="true" />
</property>
<property name="StringValue2" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name=""StringValue2"" not-null="false" />
</property>
<property name="DateTimeValue" type="System.DateTime, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name=""DateTimeValue"" not-null="true" />
</property>
<property name="IntValue" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name=""IntValue"" />
</property>
<property name="BoolValue" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name=""BoolValue"" />
</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/