【问题标题】:Nhibernate, updating a child gives new parentNhibernate,更新一个孩子给新的父母
【发布时间】:2013-09-08 13:35:40
【问题描述】:

我是休眠新手。当我通常更新记录(没有子项)时,我只是创建一个新对象,设置旧 ID,更改所需值并更新记录。这行得通。

当我对我的孩子做同样的事情时,我需要设置父母记录,否则我会得到一个 无法执行批处理命令。[SQL: SQL 不可用] 错误。

为此,我创建了一个新的父级并设置了父级的 ID。我希望这能解决问题。没有抛出异常,但现在我在我的数据库中获得了一条新的父记录。

在更新之前我应该​​总是阅读要更新的对象还是有其他方法可以做到这一点? (更新前阅读会消耗一些性能)

【问题讨论】:

    标签: c# nhibernate


    【解决方案1】:

    您正在与 NHibernate 战斗。这不是更新内容的正确方法。与其自己实例化对象,不如让 NHibernate 这样做,让它从 DB 加载现有数据并将数据填充到对象中:

    // do something
    // this will create an object, and populate data from database:
    var vehicle = session.Get<Vehicle>(vehicleId);
    // change the owner:
    vehicle.Owner = "John Smith";
    

    编辑 1: 误读你的帖子。您确实说过“在更新之前阅读会消耗一些性能”。我认为这里的性能损失并不重要,除非代码用于绝对关键的目的。

    编辑 2: 在这种情况下需要考虑许多参数。因为你没有在这里发布你的映射和数据模型类,所以我不知道你的代码有什么问题,这是我有根据的猜测。 如果我是你,我会使用这样的东西:

    public class Child
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Parent Parent { get; set; }
    }
    
    public class Parent
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }
    

    和映射:

    <class name="Child">
        <id name="Id" unsaved-value="0"><generator class="identity" /></id>
        <property name="Name" />
        <many-to-one name="Parent"/>
    </class>
    <class name="Parent">
        <id name="Id" unsaved-value="0"><generator class="identity" /></id>
        <property name="Name" />
    </class>
    

    要在不加载旧数据的情况下更新 Parent,这可行:

    session.Update(new Parent { Id = parentId, Name = "Parent 1" });
    

    这确实会生成 UPDATE 而不会生成 SELECT。 现在,如果您知道孩子的 id、父母 id 和孩子的新名称,您可以更新孩子而不会产生任何 SELECT:

    session.Update(
        new Child
            {
                Id = childId, 
                Name = "new name", 
                Parent = session.Load<Parent>(parentId)
            });
    

    说明:通过使用 session.Load,我明确告诉 NHibernate 不要访问具有 key parentId 的父记录的数据库,而是给我一个未初始化的代理。

    所以可以实现你想要的,但我认为这不是一件好事,迟早这段代码会回来咬你,因为当对象模型增长更多时,这段代码会产生一些意想不到的行为复杂。

    【讨论】:

    • 谢谢。我想你是对的。也许我试图在错误的点上节省一些 cpu 周期......
    • 我的回答没有完成。至少有一种方法可以强制 NHibernate 在不考虑任何情况下更新实体:使用 StatelessSession。但是,这种方式会破坏任何未准备使用无状态会话的应用程序的会话管理系统。
    • 感谢您提供的额外信息...而且我认为您对咬人的部分是正确的,所以我现在先加载然后更新;)
    • +1 用于“Parent = session.Load(parentId)”技巧。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    • 1970-01-01
    • 2017-10-11
    相关资源
    最近更新 更多