【问题标题】:fluent nhibernate copy a full entity流利的nhibernate复制一个完整的实体
【发布时间】:2013-06-13 12:07:49
【问题描述】:

如何在 fluent nhibernate 3.3.1 中最好地复制实体实例; 我从数据库中读取了一个对象,我得到了一个对象,现在我更改了这个对象的一些值。我要保存这个改动不大的对象。

我尝试将 Id 设置为 0,这不起作用,我还在我的 Entityclass 中编写了一个 Clone 方法。这是我的方法。

public class Entity: ICloneable
{
    public virtual int Id { get; protected set; }

    object ICloneable.Clone()
    {
        return this.Clone();
    }

    public virtual Entity Clone()
    {
      return (Entity)this.MemberwiseClone();
    }
}

你能给我一些建议吗?

【问题讨论】:

  • 嗯,如果我理解这个权利,你想保存被更改的对象,对吗?然后在这些更改的生命周期内保持一个开放的会话,一切都会被保存,在这种情况下,我不需要克隆......
  • 是的,你明白我的意思;你能举个例子吗

标签: c# nhibernate fluent-nhibernate copy


【解决方案1】:

如果您的对象不可序列化并且您只是在寻找它们的快速一对一副本,您可以使用AutoMapper 轻松完成此操作:

// define a one-to-one map
// .ForMember(x => x.ID, x => x.Ignore()) will copy the object, but reset the ID
AutoMapper.Mapper.CreateMap<MyObject, MyObject>().ForMember(x => x.ID, x => x.Ignore());

然后当你复制方法时:

// perform the copy
var copy = AutoMapper.Mapper.Map<MyObject, MyObject>(original);

/* make copy updates here */

// evicts everything from the current NHibernate session
mySession.Clear();

// saves the entity
mySession.Save(copy); // mySession.Merge(copy); can also work, depending on the situation

我为自己的项目选择了这种方法,因为我与一些关于记录复制的奇怪要求有很多关系,我觉得这让我对它有更多的控制权。当然,我的项目中的实际实现会有所不同,但基本结构几乎遵循上述模式。

请记住,Mapper.CreateMap&lt;TSource, TDestination&gt;() 在内存中创建一个静态映射,因此只需要定义一次。再次为相同的TSourceTDestination 调用CreateMap 将覆盖已定义的映射。同样,调用Mapper.Reset() 将清除所有地图。

【讨论】:

  • 我应该粘贴这段代码吗 AutoMapper.Mapper.CreateMap().ForMember(x => x.ID, x => x.Ignore);在我的实体映射类中?
  • 我建议不要为此使用 AutoMapper - 它不是为克隆项目而设计的(尽管它可能在某些情况下工作)。查看此链接stackoverflow.com/questions/5713556/…。建议的方法是像我的示例一样使用 BinaryFormatter()。
  • @StephenBorg,就像我说的那样,这种方法对我有用,尽管我承认我仍在寻找替代方案。我最大的问题是有时 子对象/列表需要与父对象/列表一起复制,并且有时 副本需要引用原始关系。使用二进制格式化程序/逐出方法,NHibernate 会吓坏,因为它不会从会话中逐出集合。 Here's my SO question about it。也许我只是以错误的方式接近它?
  • @Higune,这是一个如何复制和忽略 ID 的示例,这将强制 NHibernate 分配一个新 ID(假设它是自动生成的)。您还可以链接它以对不同的属性执行特定操作(例如:CreateMap&lt;Ts, Td&gt;().ForMember(...).ForMember(...))并分配要在映射后执行的操作(CreateMap&lt;Ts, Td&gt;().AfterMap((source, target) =&gt; { target.Child = source.Child; target.Name += " Copy"; /* etc, etc */ }))。真的,你只需要玩弄它。
  • @valverij 使用 BinaryFormatter() 要容易得多。那些延迟加载的实体可能会出现问题,但您可以轻松识别这些实体,在这些情况下,您可以通过反射加载它们。
【解决方案2】:

你需要

  1. 用 NH 加载实体
  2. 使用以下方法克隆实体,并创建副本
  3. 驱逐主要实体
  4. 对副本进行更改
  5. 更新副本,不引用主要实体

克隆方法如下

         /// <summary>
     /// Clone an object without any references of nhibernate
     /// </summary> 
    public static object Copy<T>(this object obj)
    {
        var isNotSerializable = !typeof(T).IsSerializable;
        if (isNotSerializable)
            throw new ArgumentException("The type must be serializable.", "source");

        var sourceIsNull = ReferenceEquals(obj, null);
        if (sourceIsNull)
            return default(T);

        var formatter = new BinaryFormatter();
        using (var stream = new MemoryStream())
        {
            formatter.Serialize(stream, obj);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }

要使用它,您可以按如下方式调用它

object main;
var copy = main.Copy<object>();

要查看有关使用什么的其他意见,您也可以查看此链接Copy object to object (with Automapper ?)

【讨论】:

  • 我应该在哪里设置通用 Copy 方法?
  • 我遇到了这种方法的问题,即 NHibernate 代理被复制并丢弃所有内容
  • 我们已经在生产中使用这种方法超过 2 年了。我们从来没有遇到过实体没有延迟加载的问题。将要克隆的类也需要可序列化。 @valverij 创建另一个名为 Extensions 的类,并将此方法放在那里。然后在您当前的代码中,导入命名空间,所有对象都应该可以访问 Copy 方法。
  • @Higune 很高兴我能帮上忙。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多