Nibernate Fluent和基于界面的域模型

时间:2018-02-15 01:33:35

标签: nhibernate fluent-nhibernate

好的,这是一个相当令人沮丧的经历:)我正在尝试使用基于接口的域模型,我可以获得ALMOST所有工作,但实际保存数据的能力除外

这是我到目前为止所拥有的。

public interface IEntity {
     Guid Id {get;set;}
}

public interface IProduct : IEntity {
     string Name {get;set;}
     string SKU {get;set;}
     decimal MSRP {get;set;}
}

public class Product : IProduct {
     public virtual Guid Id {get;set;}
     public virtual string Name {get;set;}
     public virtual string SKU {get;set;}
     public virtual decimal MSRP {get;set;}
}

public interface IOrder : IEntity {
     DateTime CreatedOn {get;set;}
     IList<IOrderLine> Lines {get;set;}
}

public class Order : IOrder {
     public virtual Guid Id {get;set;}
     public virtual DateTime CreatedOn {get;set;}
     public virtual IList<IOrderLine> Lines {get;set;}
}

public interface IOrderLine : IEntity {
     IProduct Product {get;set;}
     int Qty {get;set;}
     decimal Price {get;set;}
}

public class OrderLine : IOrderLine {
     public virtual Guid Id {get;set;}
     public virtual IProduct Product {get;set;}
     public virtual int Qty {get;set;}
     public virtual decimal Price {get;set;}
}

public class ProductMap : ClassMap<IProduct>
{
     public ProductMap() {
         Id(x => x.Id);

         Map(x => x.Name);
         Map(x => x.SKU);
         Map(x => x.MSRP);
     }
}

public class OrderMap : ClassMap<IOrder>
{
     public OrderMap() {
         Id(x => x.Id);

         Map(x => x.CreatedOn);

         HasMany(x => x.Lines)
            .KeyColumns.Add("Id");
     }
}

public class OrderLineMap : ClassMap<IOrderLine>
{
     public OrderLineMap() {
         Id(x => x.Id);

         Map(x => x.Qty);
         Map(x => x.Price);

         References(x => x.Product)
             .PropertyRef(x => x.Id)
             .ForeignKey("productId");
     }
}

public static class NHibernateUtils
{
    public static ISessionFactory CreateSessionFactory(IPersistenceConfigurer persistenceConfigurer)
    {           
        return Fluently.Configure()
            .Database(persistenceConfigurer)
            .Mappings(m =>
            {
                m.FluentMappings.Add<ProductMap>();
                m.FluentMappings.Add<OrderLineMap>();
                m.FluentMappings.Add<OrderMap>();
            })
            .ExposeConfiguration(c => new SchemaExport(c).Create(false, true))
            .BuildConfiguration()
            .BuildSessionFactory();
    }
}

这可以创建一个有效的方案(我正在测试唱Sqlite并且可以看到正确创建的数据库)。问题是当我尝试保存实际实体时。

var p = new Product() { Name = "Product Sample", SKU = "12345", MSRP = 1.0 };
var sessionFactory = NHibernateUtils.CreateSessionFactory(...);

using (var session = sesionFactory.OpenSession())
{
    using (var transaction = session.BeginTransaction())
    {                   
        session.Save(p);

        transaction.Commit();
    }
}

此操作失败并显示错误“没有产品持久性”

好吧,我可以看到 - 所以接下来我尝试了这个

session.Save((IProduct)p);

这给了我错误“没有IP产品的持久性”

那么我错过了什么?

注意:这是指向实际在正在运行的控制台应用中显示问题的要点的链接 https://gist.github.com/ravensorb/14193136002adbb3ec2fac07c026f921

2 个答案:

答案 0 :(得分:3)

好像我已经成功了。尝试使用此重载object Save(string entityName, object obj);

这样的事情:

var p = new Product() { Name = "Product Sample" + i, SKU = "12345", MSRP = 1.0m };
session.Save(typeof(IProduct).FullName, p);

我调查了NHibernate持久性的源代码,发现持久性存储在Dictionary<string, IEntityPersister>中,其中密钥来自Configuration.ClassMappings.EntityName(在您的情况下为接口名称)。但是当你只调用Save(p)时,你的entityName将等于你的实体类名,而不是接口。

我希望这清楚地解释:

  

产品没有持久性

答案 1 :(得分:0)

这是工作映射:

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Id(x => x.Id).GeneratedBy.Guid();

        Map(x => x.Name);
        Map(x => x.SKU);
        Map(x => x.MSRP);
    }
}

public class OrderMap : ClassMap<Order>
{
    public OrderMap()
    {
        Id(x => x.Id).GeneratedBy.Guid();

        Map(x => x.CreatedOn);

        HasMany<OrderLine>(x => x.Lines).Cascade.SaveUpdate();
    }
}

public class OrderLineMap : ClassMap<OrderLine>
{
    public OrderLineMap()
    {
        Id(x => x.Id).GeneratedBy.Guid();

        Map(x => x.Qty);
        Map(x => x.Price);

        References<Product>(x => x.Product);
    }
}

一些注意事项:

  1. 您需要在映射中使用具体类作为泛型类型参数。
  2. 您必须在ReferencesHasMany映射中明确指定具体类。
  3. 在此方案中保存时,您无需转换为界面。
  4. 小事:

    1. 从程序集中添加所有映射更加容易:.AddFromAssemblyOf<ProductMap>()
    2. 我已经为映射添加了guid生成器和级联选项(可能你不想要它们)。
    3. .KeyColumns.Add(x => x.Id)没有这样的重载(至少在最新的Fluent Nhibernate版本中)。
    4. 您忘了拨打transaction.Commit()
    5. 看看非常相似的question

      以下是我测试保存的方法:

          using (var transaction = session.BeginTransaction())
          {
              for (int i = 0; i < 10; i++)
              {
                  Product p = new Product() { Name = "Product Sample" + i, SKU = "12345", MSRP = (1.0m + i) };
                  session.Save(p);
      
                  Order order = new Order
                  {
                      CreatedOn = DateTime.Now,
                      Lines = new List<IOrderLine> {
                          new OrderLine{ Price = 12, Qty = 2, Product = p}
                      }
                  };
                  session.Save(order);
              }
      
              transaction.Commit();
          }