【问题标题】:Nhibernate many-to-one problemNhibernate 多对一问题
【发布时间】:2010-01-20 11:40:04
【问题描述】:

我在以下代码中遇到了多对一映射问题:

...

<property name ="CustomerID"/>    

<!-- Many-to-one mapping: Customer -->
<many-to-one name="Customer" 
                 class="Customer" 
                 column="CustomerID"
                 insert="false" update="false"/>
<property name="Date" />

...

您可能会注意到我已将两个 CustomerID 映射到 Customer 表。我这样做的原因是,当我想创建一个订单时,我只需将值分配给 CustomerID 和其他需要的字段,然后保存。多对一映射,我只想获取每个客户 ID 的详细信息。

但是,问题在于:在我更新 Order 的 customerID 并使用 Session.Flush() 执行 SaveOrUpdate 之后(我正在使用 HibernateTemplate),我在访问 Order.Customer 时仍然得到旧数字。 即:

订单 = getOderByID(1);
Order.CustomerID=3 // 假设 CustomerId 的值为 1,现在我改为 3
保存或更新(订单);
Print(Order.Customer.CustomerID)// 它返回 1,这是错误的。应该是 3

请帮忙...

谢谢,

【问题讨论】:

    标签: nhibernate


    【解决方案1】:

    我建议您从 NHibernate 的角度来看这个问题。而不是从关系数据库视图。让我从我认为你应该做的事情开始。

    var customer = session.Load<Customer>(3);
    var order = session.Load<Order>(1);
    order.Customer = customer; 
    
    //assuming this is a one directional mapping. otherwise you might 
    //have to do some more steps to disassociate the order from the old 
    //customers collection and add it to the new customers collection
    
    session.SaveOrUpdate(order);
    

    现在,order.Customer.CustomerID 将返回 3。

    正如 Serkan 所建议的,使用对象而不是主键会更好、更可行。

    此外,这里确实不应该对性能产生任何影响。只要类具有虚拟公共方法,Nhibernate 就能够代理很多关联。正因为如此,只要只查询客户的Id,就不会产生单独的sql查询。 Id 已经与代理对象一起存在。

    关于最初的问题,我有一种预感。 NHibernate 为更新和插入动态生成 sql 查询。这里的这个案例是一个更新。您已将 CustomerID 属性显式设置为 3。但订单对象的 Customer 属性仍指向 ID 为 1 的客户对象。因此,当 NHibernate 生成 sql 查询时,它会尝试首先将值设置为 1,如您所问它到。然后它还看到 Customer 仍然指向旧对象,因此将 CustomerId 属性重置为 1。我认为 NHibernate 对双重映射感到困惑。

    您可以做两件事。首先在 NHibernate 配置中启用“show_sql”属性。

    <nhibernate>
      ...
      <add key="hibernate.show_sql" value="true" />
    </nhibernate>
    

    检查保存订单时生成的sql是什么。这将更好地解释事情。

    其次,保存订单后,做session.Refresh(order);你可以阅读有关Refresh()方法here。它接近第 9.2 节的末尾。它将使用数据库中的新值重新加载订单对象。调用 order.CustomerID 应该会显示您在数据库中存储的值。

    【讨论】:

    • +1 是的,我认为 session.Load() 绝对是 OP 需要的。
    【解决方案2】:

    我认为,如果您在完成 OR 映射后尝试忘记实体的 ID,从长远来看,您会感觉更快乐。你处于一个不同的层次,你应该只考虑对象。如果我是你,我会一起删除 CustomerId 属性。

    如果您遇到性能问题,请尝试以 NHibernate 方式、缓存等方式解决它们。

    【讨论】:

      【解决方案3】:

      尝试两件事

      1. 如果是 NH 2.x,则通过 Session.Dispose 刷新会话,否则使用 Flush()
      2. 将您的 ID 分配给客户端。

      NHibernate 将为您创建 ID 并尝试管理它们,除非您明确告诉它不要这样做。

      【讨论】:

      • 这非常快,但实际上我在 Flush() 之前和之后调用它仍然没有更新。还是非常感谢。其实这是我第一次尝试Nhibernate,只是代码量很少。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多