Linq to sql, copy original entity to new one and save

前端 未结 6 1548
失恋的感觉
失恋的感觉 2020-12-16 10:51

I have a situation when I cant just update original record in database, but instead make a new record, copy all fields from old and apply changes to new one. (something like

相关标签:
6条回答
  • 2020-12-16 11:31

    It might be better if you create a stored proc and copy the objects in there instead of wasting time on linq-sql limitations. You can handle errors and other problems easily in sql syntax.

    0 讨论(0)
  • 2020-12-16 11:42

    You may also want to look into PLINQO. It has the ability to clone, detach, attach, serialize to xml, serialize to binary, many to many relationships, etc... all right out of the box so you don't have to deal with these features that should've been included in the first place.

    http://www.plinqo.com/

    0 讨论(0)
  • 2020-12-16 11:43

    Is it possible to make it work without manually copying every field?

    Yes - don't manually copy every field:

    You could use AutoMapper.

    Set up somewhere (called once at program start):

    AutoMapper.Mapper.CreateMap<MyObject, MyObject>()
    // don't map the id to stop conflicts when adding into db
        .ForMember(a => a.Id, a => a.Ignore()); 
    

    Then call:

    var newObject = AutoMapper.Mapper.Map<MyObject>(oldObject);
    
    0 讨论(0)
  • 2020-12-16 11:50

    You could use reflection to iterate over the properties and set them

      foreach (var prop in original.GetType().GetProperties())
      {
         prop.SetValue(newTest, prop.GetValue(original,null), null);
      }
    

    Obviously this will need to be expanded to be less error prone, but it could be a good start.

    This will certainly have a slower runtime than if the properties were written out manually, I'd imagine.

    0 讨论(0)
  • 2020-12-16 11:52

    This should work:

    Generic Clone() Method

    This method will create a full clone of any object by serializing it. The original idea came from both here and here.

    /// <summary>
    /// Clones any object and returns the new cloned object.
    /// </summary>
    /// <typeparam name="T">The type of object.</typeparam>
    /// <param name="source">The original object.</param>
    /// <returns>The clone of the object.</returns>
    public static T Clone<T>(this T source) {
        var dcs = new DataContractSerializer(typeof(T));
        using(var ms = new System.IO.MemoryStream()) {
            dcs.WriteObject(ms, source);
            ms.Seek(0, System.IO.SeekOrigin.Begin);
            return (T)dcs.ReadObject(ms);
        }
    }
    

    Your Code Example

    Now with the help of the above extension method, your code should work if tweaked a little bit:

    var original = from _orig in context.Test where _orig.id == 5 select _orig;
    Test newTest = original.Clone();
    newTest.id = 0;
    context.Test.InsertOnSubmit(newTest);
    context.SubmitChanges();
    original.parent_id = newTest.id;
    original.isActive = 0;
    
    0 讨论(0)
  • 2020-12-16 11:56

    Using Reflection, you can easily copy each attribute that is not DbGenerated. This method is probably not very performant, but it will work in a pinch.

    public static T Clone<T>(this T source)
    {
        var clone = (T)Activator.CreateInstance(typeof(T));
        var cols = typeof(T).GetProperties()
            .Select(p => new { Prop = p, Attr = (ColumnAttribute)p.GetCustomAttributes(typeof(ColumnAttribute), true).SingleOrDefault() })
            .Where(p => p.Attr != null && !p.Attr.IsDbGenerated);
        foreach (var col in cols)
            col.Prop.SetValue(clone, col.Prop.GetValue(source, null), null);
        return clone;
    }
    
    0 讨论(0)
提交回复
热议问题