我正在开发一个使用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=""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)
非常感谢任何帮助!
答案 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);
}