使用NHibernate保存子集合

使用NHibernate保存子集合,nhibernate,nhibernate-mapping,Nhibernate,Nhibernate Mapping,我正在学习NHibernate,所以请容忍我 我有一个Order类和一个Transaction类。订单与事务具有一对多关联。数据库中的事务表对OrderId外键具有NOTNULL约束 订单类别: public class Order { public virtual Guid Id { get; set; } public virtual DateTime CreatedOn { get; set; } public virtual decimal Total {

我正在学习NHibernate,所以请容忍我

我有一个Order类和一个Transaction类。订单与事务具有一对多关联。数据库中的事务表对OrderId外键具有NOTNULL约束

订单类别:

    public class Order {
    public virtual Guid Id { get; set; }
    public virtual DateTime CreatedOn { get; set; }
    public virtual decimal Total { get; set; }

    public virtual ICollection<Transaction> Transactions { get; set; }

    public Order() {
        Transactions = new HashSet<Transaction>();
    }
}
事务映射:

  <class name="Transaction" table="Transactions">
<cache usage="read-write"/>
<id name="Id" column="Id" type="Guid">
  <generator class="guid"/>
</id>
<property name="ExecutedOn" type="datetime"/>
<property name="Success" type="bool"/>
<many-to-one name="Order" class="Order" column="OrderId" not-null="true"/>
我的问题是,这将为订单集合上的每个事务发出更新(无论它是否已更改)

我试图解决的问题是,在保存订单之前必须显式保存事务,而只是将事务添加到订单中,然后保存订单:

        public void Can_add_transaction_to_existing_order()
    {
        var orderRepo = new OrderRepository();
        var order = orderRepo.GetById(new Guid("aa3b5d04-c5c8-4ad9-9b3e-9ce73e488a9f"));

        Transaction tx = new Transaction();
        tx.ExecutedOn = DateTime.Now;
        tx.Success = true;

        order.Transactions.Add(tx);

        orderRepo.Update(order);
    }
尽管我已经找到了很多关于一对多关联的文章,其中大部分都讨论了数据检索和不持久化

非常感谢,,
Ben

您需要在映射上设置cascade属性,以便将持久性级联到子对象:

<set name="Transactions" table="Transactions" lazy="false" inverse="true" cascade="all-delete-orphan">

这将导致在持久化订单时持久化事务对象。您可以使用
internal
修饰符在事务上公开Order属性,这样它就不会公开可见。

@Jamie-这当然有效,尽管它看起来仍然像是为属于订单的每个事务执行更新查询。我想NH会找出发生了什么变化,只会为任何新的交易发布插入,并为任何发生变化的交易发布更新。也许我要求太多了?:)不,这是它应该工作的方式。您可能有“重影”问题,即值意外更改。在事务映射中设置
dynamic update=“true”
,并查看正在发出的SQL(通过探查器或日志记录)。您可能会发现您的对象无意中更改了一个值。@Jamie我已经查看了生成的SQL,并且没有更改现有事务的任何值。我的示例代码检索现有订单,向订单添加新事务,然后保存订单。如果我为该订单创建了四个现有事务,那么执行的SQL总量如下1所示。从id=blah 2的顺序中选择*。从orderId=blah 3的事务中选择*。插入交易(新交易)4。更新顺序(将值设置为与原始值相同)5。更新事务1,2,3,4(将值设置为与以前相同),这是奇数。即使包含
dynamic update=“true”
,它也会更新所有列吗?我几乎总是将bag/IList初始化为列表实现,因此它可能与使用初始化为HashSet的set/ICollection有关。@Jamie-是的,我设置了dynamic update=“true”,它仍然会为每个事务发出更新。我将set/hashset换成了bag/I集合,遇到了同样的问题。你有一个基本的例子(或一个链接)说明这应该如何工作,也许我可以回顾一下我自己的代码。目前仅使用NH 2天,因此很难判断什么是错误,什么是设计错误:(
        public void Update(Order entity)
    {
        using (ISession session = NHibernateHelper.OpenSession()) {
            using (ITransaction transaction = session.BeginTransaction()) {
                session.Update(entity);

                foreach (var tx in entity.Transactions) {
                    tx.Order = entity;
                    session.SaveOrUpdate(tx);
                }
                transaction.Commit();
            }
        }
    }
        public void Can_add_transaction_to_existing_order()
    {
        var orderRepo = new OrderRepository();
        var order = orderRepo.GetById(new Guid("aa3b5d04-c5c8-4ad9-9b3e-9ce73e488a9f"));

        Transaction tx = new Transaction();
        tx.ExecutedOn = DateTime.Now;
        tx.Success = true;

        order.Transactions.Add(tx);

        orderRepo.Update(order);
    }
<set name="Transactions" table="Transactions" lazy="false" inverse="true" cascade="all-delete-orphan">
public void AddTransaction(Transaction txn)
{
    txn.Order = this;
    Transactions.Add(txn);
}