NHibernate - 一对多只是不使用SQLite

时间:2015-11-12 08:09:01

标签: sqlite nhibernate

TL; DR;
NHibernate Azure-SQLMSSQL2012正在使用SQLite反向关系,FluentMigrator

说明
我目前正在对我的Asp.Net MVC应用程序进行单元测试,并在SQLite上使用Product设置我的Unittest。

创建数据库后,我设置了一些我需要的基本条目 其中一个是产品 ProductSuppliers有很多ProductSupplierProductSupplierPrices有很多public class Product { public virtual long Id { get; set; } public virtual string Number { get; set; } public virtual string Name { get; set; } public virtual string Description { get; set; } //more properties public virtual IList<ProductSupplier> Suppliers { get; set; } //more properties } public class ProductSupplier { public virtual long Id { get; set; } public virtual Product Product { get; set; } public virtual Supplier Supplier { get; set; } public virtual IList<ProductSupplierPrice> Prices { get; set; } } public class ProductSupplierPrice : IHaveId { public virtual long Id { get; set; } public virtual ProductSupplier ProductSupplier { get; set; } public virtual decimal FromAmount { get; set; } public virtual decimal Price { get; set; } }

Product product = this.session.Load<Product>((long)1);
ProductSupplier productSupplier = product.Suppliers.First(); //<-- Suppliers are null; therefore throws an exception

设定:

  1. 创建供应商
  2. 创建产品
  3. 创建ProductSupplier
  4. 创建ProductSupplierPrice
  5. 测试

    productSupplierPrice.ProductSupplier <--- Correct Supplier
    
    productSupplier.Prices <-- Null 
    productSupplier.Product <-- Product with Id 1
    
    product.Suppliers <-- Null
    

    如果我单独加载它们以检查关系:

    Azure-SQL

    所以对我而言,多对一方向似乎是正确的,但是一对多(反向关系)不起作用。

    问题仅存在于我的Unittest(SQLite)中,App本身在public class ProductMap : ClassMap<Product> { public ProductMap() { Id(x => x.Id); HasMany(x => x.Suppliers).Inverse().Cascade.DeleteOrphan().BatchSize(20); //many more mappings } } public ProductSupplierMap() { Id(x => x.Id); References(x => x.Product); References(x => x.Supplier); Map(x => x.IsMainSupplier); Map(x => x.SupplierProductNumber); Map(x => x.CopperSurcharge); HasMany(x => x.Prices).Inverse().Cascade.DeleteOrphan().BatchSize(20); } public ProductSupplierPriceMap() { Id(x => x.Id); References(x => x.ProductSupplier); Map(x => x.FromAmount); Map(x => x.Price); } 上运行且工作正常。

    修改
    与FluentnHibernate的映射

    Product product = new Product()
    {
        Type = ProductType.Purchase,
        Dispatcher = session.Load<Employee>(employeeId),
        Number = "100.10-1000",
        Name = "Testproduct",
        //Lots of Properties
        Suppliers =  new List<ProductSupplier>()
    };
    session.SaveOrUpdate(product);
    
    ProductSupplier productSupplier = new ProductSupplier()
    {
        Product = product,
        Supplier = session.Load<Supplier>((long)1),
        IsMainSupplier = true,
        SupplierProductNumber = "Artikel123456",
        CopperSurcharge = CopperSurchargeType.DEL700,
        Prices = new List<ProductSupplierPrice>()
    };
    session.Save(productSupplier);
    
    ProductSupplierPrice productSupplierPrice = new ProductSupplierPrice()
    {
        ProductSupplier = productSupplier,
        FromAmount = 1,
        Price = 5
    };
    session.Save(productSupplierPrice);
    

    Edit2 - 创建数据库条目:

    public static ISession InitializeDatabase()
    {
        NHibernateSessionHolder.CreateSessionFactory();
        session = NHibernateSessionHolder.OpenSession();
        CreateBaseEntries(); //Creates Employees, Supplier, Customer etc
        return session;
    }
    

    编辑3.1:

    forcePrincipalAsString

2 个答案:

答案 0 :(得分:5)

基于Ayende's article,您需要清除插入/更新和查询之间的会话:

session.Clear();

似乎是一个会话管理,我不确定为什么会话应该是干净的,但是会话提供了你的原始实例(你提供的保存,存储在会话缓存中)而不是lazy的代理 - 负荷。

private long CreatePurchaseOrder()
{
    session.Clear();

    var product = this.session.Load<Product>((long)1);
    var productSupplier = product.Suppliers.First();
    var productSupplierPrice = productSupplier.Prices.First();
    return 0;
}

答案 1 :(得分:1)

对不起,迟到的回复

在单元测试中,您使用相同的会话来创建和获取实体。这是不对的,因为后续提取会从第一级缓存返回实体,而这些实体没有正确设置其图形。

所以....要么使用不同的会话 OR 作为快速修复,我在“DatabaseSetUpHelper”的方法“InitializeDatabase()”中添加了“session.Clear()”。清除会话将清除第一级缓存并强制NH再次从DB获取数据,并且生成的实体已正确设置其图形。

    public static ISession InitializeDatabase()
    {
        NHibernateSessionHolder.CreateSessionFactory();
        session = NHibernateSessionHolder.OpenSession();
        CreateBaseEntries();
        session.Clear(); // notice this!!! this clears first level cache of session, thus forcing fetching of data from DB
        return session;
    }

注意:我的快速修复不是最终解决方案,它只是显示会话的行为方式。在适当的解决方案中,您必须使用不同的会话