【问题标题】:Saving and querying elements in Nhibernate在 Nhibernate 中保存和查询元素
【发布时间】:2018-05-03 08:53:36
【问题描述】:

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

商店

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

以下是用于存储将要存储在 Store 中的 Items

物品

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 的映射如下

商店地图

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();
    }
}

项目地图

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>();

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

【问题讨论】:

  • 需要注意的一点是,另一种方法是将项目添加到商店 Items 集合中,然后您只需要保存商店实体(感谢商店中的 Cascade.SaveUpdate()项目映射)。
  • 你已经正确地使用了cascade (我确实将所有用于孤儿,但是..)。这意味着,无需在项目上调用会话保存。它们将被持久化.. 只要我们也将它们添加到 Store 的集合中 Items
  • 好的,我已经改变了将 Item 元素添加到 Store 列表的列表。但是当我查询以使用 Store s = session.QueryOver&lt;Store&gt;().Where(x =&gt; x.StoreID == 1).SingleOrDefault&lt;Store&gt;(); 获取 Store 元素时,我仍然不能在列表中同时拥有这两个项目

标签: c# sqlite nhibernate fluent-nhibernate queryover


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

  • 要保持OO语义,需要在`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&lt;T&gt; 到session.Query&lt;T&gt;(); 所以你可以用它来代替session.QueryOver&lt;T&gt;()。如果你是 已经习惯于编写 Linq 查询,或者如果您来自 EF 世界,你可以像你一样继续写 Linq 查询 通常会。有时 Linq 无法满足您的需求,您必须使用 QueryOver。 QueryOver 无法满足您的需求而您必须使用CreateCriteria 的次数更少。有时,这些都不适合您,您必须编写原始 sql。但在大多数情况下,包括在这种情况下,Linq 会带你去你要去的地方。
  2. NHibernate 现在也支持async/await 模式。您只需要添加using NHibernate.Linq;,它们就会变得可用。对于此代码,您可以使用 SaveOrUpdateAsync() 和 SingleOrDefaultAsync() API,而不是非异步版本。
  3. 由于您使用的是 Fluent NHibernate,因此请考虑使用 AutoMapping。相信我,编写映射文件并不好玩,您只想在绝对必要时才编写一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 2010-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多