在Nhibernate中保存和查询元素

时间:2018-05-03 08:53:36

标签: c# sqlite nhibernate fluent-nhibernate queryover

我有两个非常简单的类,一个是Store类,编码如下

商品

class Store
{
    public virtual int StoreID { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<Item> ItemID { get; set; }
}

以下内容用于存储将要存储在商店中的商品

物品

class Item
{
    public virtual int ItemID { get; set; }
    public virtual string Name { get; set; }
    public virtual double Price { get; set; }
    public virtual int Quantity { get; set; }
    public virtual Store StoreID { get; set; }        
}

Fluent Nhiberate的映射如下

StoreMap

class StoreMap : ClassMap<Store>
{
   public StoreMap()
   {
       Id(x => x.StoreID).Column("idStore").GeneratedBy.Assigned();
       Map(x => x.Name).Column("Name").Not.Nullable();

       HasMany(x => x.ItemID).KeyColumn("idItem").Inverse().Table("Item").AsSet().Cascade.SaveUpdate();
    }
}

ItemMap

class ItemMap : ClassMap<Item>
{
    public ItemMap()
    {
       Id(x => x.ItemID).Column("idItem").GeneratedBy.Assigned();
       Map(x => x.Name).Column("Name").Not.Nullable();
       Map(x => x.Price).Column("Price").Default("0");
       Map(x => x.Quantity).Column("Quantity").Default("0");
       References(x => x.StoreID).Column("idStore");
    }
}

现在,当我想要保存两个项目和一个新商店时,我会使用以下内容进行保存,但我不知道是否有一个简单/更好的方法可以这样做

Store s = new Store{...}
Item i1 = new Item {
     Name = "Item 1",
     ItemID = 1,
     Price = 100,
     Quantity = 1,
     StoreID = s
};
Item i2 = new Item {
     Name = "Item 2",
     ItemID = 2,
     Price = 100,
     Quantity = 1,
     StoreID = s
};
trans = session.BeginTransaction();
session.SaveOrUpdate(s);
session.SaveOrUpdate(i2);
session.SaveOrUpdate(i1);
//Commit changes
trans.Commit();
session.Flush();
session.Close();

当我查询从商店获取所有数据时,只有第一个项目显示在项目列表中......

Store s = session.QueryOver<Store>().Where(x => x.StoreID == 1).SingleOrDefault<Store>();

所以我的问题是我应该如何查询和保存以获得尽可能少的代码行并将两个项目都放在商店列表中?

1 个答案:

答案 0 :(得分:0)

  • 为了保存,由于您映射实体的方式, 特别是因为级联选项集 (.Cascade.SaveUpdate()),你可以愉快地删除 session.SaveOrUpdate(i2);session.SaveOrUpdate(i1);。只是 保存s会自动保存这些内容。

  • 要维护OO语义,您需要将item添加到store。实际上,这意味着要添加这两行:

    s.ItemID.Add(i1);
    s.ItemID.Add(i2);
    
  • 您可以使用using语句简化会话创建和销毁(结束)。

最终代码如下:

    Store s = // as defined earlier;
    Item i1 = // as defined earlier;
    Item i2 = // as defined earlier;

    s.ItemID.Add(i1);
    s.ItemID.Add(i2);

    using (var session = NhConfig.GetSession())
    {
        var trans = session.BeginTransaction();
        try
        {
            session.SaveOrUpdate(s);

            trans.Commit();
        }
        catch (Exception)
        {
            trans.Rollback();
            throw;
        }
    }

    // Later when you need to query
    using (var session = NhConfig.GetSession())
    {
        Store store = session.QueryOver<Store>().Where(x => x.StoreID == 1).SingleOrDefault();
        foreach (var item in store.ItemID) // store.ItemID.Count == 2.
        {
            Console.WriteLine($"Item - Id: {item.ItemID}. Name: {item.Name}. Store ID: {item.StoreID.StoreID}.");
        }
        /* The above loop will print:
           Item - Id: 1. Name: Item 1. Store ID: 1.
           Item - Id: 2. Name: Item 2. Store ID: 1.
        */
    }

在地图文件上......

ItemMap可以保持您定义它的方式。但是,StoreMap有一个小问题需要修复。

更改行:

HasMany(x => x.ItemID).KeyColumn("idItem").Inverse().Table("Item").AsSet().Cascade.SaveUpdate();

HasMany(x => x.ItemID).KeyColumn("idStore").Inverse().AsSet().Cascade.SaveUpdate();

注意改变了什么:.KeyColumn现在名为“idStore”而不是“idItem”。 .HasMany(...)侧的键列名称必须与.References(...)侧的列名称相对应。

.Table("Item")是多余的,因为默认情况下,“Item”将是名为Item的类的表名。由于您没有使用ItemMap中的表名,因此默认规则适用(除非您为类/表名实现了Convention)。

最终说明:

  1. NHibernate现在通过IQueryable<T>支持session.Query<T>(); 所以你可以使用它而不是session.QueryOver<T>()。如果你是 已经习惯于编写Linq查询或者来自EF 世界,您可以继续像您一样编写Linq查询 通常这样做。有几次Linq无法满足您的需求,您必须使用QueryOverQueryOver无法满足您的需求且您必须使用CreateCriteria的次数更少。有时,这些都不会对你有好处,你必须编写原始的sql。但大多数时候,包括在这种情况下,Linq会让你到达目的地。
  2. NHibernate现在也支持async/await模式。您只需添加using NHibernate.Linq;即可使用。对于此代码,您可以使用SaveOrUpdateAsync()SingleOrDefaultAsync() API代替非异步版本。
  3. 由于您使用的是Fluent NHibernate,请考虑使用AutoMapping。相信我,编写映射文件并不好玩,你只想在必要的时候写一个。