Fluent NHibernate - HiLo 方案的 PersistenceSpecification

Posted

技术标签:

【中文标题】Fluent NHibernate - HiLo 方案的 PersistenceSpecification【英文标题】:Fluent NHibernate - PersistenceSpecification of HiLo scheme 【发布时间】:2011-04-12 08:05:25 【问题描述】:

不确定我问的问题是否正确,所以请多多包涵!有点 NHibernate 菜鸟。

我们正在使用 Fluent NH,并为所有表提供以下 id 生成方案

public class IdGenerationConvention : IIdConvention

    public void Apply(IIdentityInstance instance)
    
        var where = string.Format("TableKey = '0'", instance.EntityType.Name);
        instance.GeneratedBy.HiLo("HiloPrimaryKeys", "NextHighValue", "1000", x => x.AddParam("where", where));
    

我们有一个 SQL 脚本,它生成 HiloPrimaryKeys 表并使用在部署期间运行的数据为其播种。这工作正常。

我现在正在尝试编写单元测试来验证我们的持久层,最好在内存配置中使用 SQLite 以提高速度。这就是我为测试配置 NH 的方式:

[SetUp]
public void SetupContext()

    config = new SQLiteConfiguration()
            .InMemory()
            .ShowSql()
            .Raw("hibernate.generate_statistics", "true");

    var nhConfig = Fluently.Configure()
            .Database(PersistenceConfigurer)
            .Mappings(mappings =>
                 mappings.FluentMappings.AddFromAssemblyOf<DocumentMap>()
            .Conventions.AddFromAssemblyOf<IdGenerationConvention>());

    SessionSource = new SessionSource(nhConfig);
    Session = SessionSource.CreateSession();
    SessionSource.BuildSchema(Session);

问题是我不知道如何告诉 NHibernate 我们的部署脚本,以便它在测试期间生成正确的架构和种子数据。

我遇到的具体问题是在运行以下PersistenceSpecification 测试时:

[Test]
public void ShouldAddDocumentToDatabaseWithSimpleValues()

    new PersistenceSpecification<Document>(Session)
            .CheckProperty(x => x.CreatedBy, "anonymous")
            .CheckProperty(x => x.CreatedOn, new DateTime(1954, 12, 23))
            .CheckProperty(x => x.Reference, "anonymous")
            .CheckProperty(x => x.IsMigrated, true)
            .CheckReference(x => x.DocumentType, documentType)
            .VerifyTheMappings();

这会引发以下异常:

TestCase ... failed: 
Execute
NHibernate.Exceptions.GenericADOException: 
        could not get or update next value[SQL: ] 
        ---> System.Data.SQLite.SQLiteException: SQLite error
        no such column: TableKey

所以我的推断是它在检查持久性规范时没有运行部署脚本。

这种情况有现成的解决方案吗?我的 Google-fu 似乎在这方面抛弃了我。

【问题讨论】:

【参考方案1】:

正如 Brian 所说,您可以在构建架构后运行部署脚本。这段代码很适合我:

var config = new SQLiteConfiguration()
        .InMemory()
        .ShowSql()
        .Raw("hibernate.generate_statistics", "true");

var nhConfig = Fluently.Configure()
        .Database(config)
        .Mappings(mappings =>
             mappings.FluentMappings.AddFromAssemblyOf<DocumentMap>()
        .Conventions.AddFromAssemblyOf<IdGenerationConvention>());

var SessionSource = new SessionSource(nhConfig);
var Session = SessionSource.CreateSession();
SessionSource.BuildSchema(Session);

// run the deployment script
var deploymentScriptQuery = Session.CreateSQLQuery("ALTER TABLE HiloPrimaryKeys ADD COLUMN TableKey VARCHAR(255); INSERT INTO HiloPrimaryKeys (TableKey, NextHighValue) values ('Document', 1);");
deploymentScriptQuery.ExecuteUpdate();

部署脚本可以从文件等加载...

构建 FNH 配置和数据库架构是一项耗时的操作。如果使用模式的测试数量增加并且模式和配置是由每个测试类构建的,那么执行测试套件将花费不可接受的时间。配置和模式都应该在所有测试之间共享。 Here 是如何在不丢失测试隔离的情况下实现这一目标的。

编辑: 如果测试中需要多个会话实例,则应打开连接池,或者应通过同一连接创建两个会话。详情here...

【讨论】:

【参考方案2】:

免责声明:我不是 NHibernate 用户...

...但是一种可能的解决方法是在测试的 Setup 方法中运行部署脚本(或它的某些变体)(使用 shell 执行/Process.Start),或者在您之前的构建脚本中运行它运行这些测试。在这种情况下,如果您希望每次测试都有一个新数据库,您可能需要添加清理。

【讨论】:

是的,我试过了,但似乎PersistenceSpecification 仅适用于 NH 生成的架构,而不是您可能所做的任何更改(据我所知)【参考方案3】:

我们有一个 SQL 脚本,它生成 HiloPrimaryKeys 表并使用在部署期间运行的数据为其播种。这工作正常。

您能否创建一个被映射的实体来表示此 HiloPrimaryKeys 表并在测试开始之前填充此表?您可以将它放在所有其他测试都继承自的基类中,这样您就不必将它添加到每个测试类中。

这与 Brian 的解决方案类似,但在您执行自动映射时将创建此表,就像其他表一样。

【讨论】:

以上是关于Fluent NHibernate - HiLo 方案的 PersistenceSpecification的主要内容,如果未能解决你的问题,请参考以下文章

获取NHibernate以生成HiLo字符串ID

NHibernate 2 + Fluent Nhibernate 中等信任

NHibernate + Fluent NHibernate 异常

NHibernate 为新实体生成 INSERT 和 UPDATE

用 Fluent Nhibernate 定义 NHibernate 过滤器的语法?

Fluent NHibernate and Mysql,SQLite