2009-03-12 38 views
12

Điều gì sẽ được coi là thực hành tốt nhất trong nhân bản [nhân bản] một thực thể LINQ to SQL dẫn đến một bản ghi mới trong cơ sở dữ liệu?Nhân bản LINQ to SQL thực thể/bản ghi?

Ngữ cảnh là tôi muốn tạo một hàm trùng lặp cho các bản ghi trong lưới của quản trị viên. trang web và sau khi thử một vài điều và rõ ràng, đọc dữ liệu, thay đổi ID = 0, thay đổi tên, submitChanges() và nhấn một ngoại lệ, lol. Tôi nghĩ tôi có thể dừng lại và hỏi một chuyên gia.

Tôi muốn bắt đầu với lần đầu tiên đọc bản ghi, thay đổi tên bằng cách bắt đầu bằng "Bản sao của" và sau đó lưu dưới dạng bản ghi mới.

Trả lời

11

Tạo một phiên bản mới và sau đó sử dụng các lớp ánh xạ LINQ cùng với sự phản ánh để sao chép các giá trị thành viên.

Ví dụ:

public static void CopyDataMembers(this DataContext dc, 
            object sourceEntity, 
            object targetEntity) 
{ 
    //get entity members 
    IEnumerable<MetaDataMember> dataMembers = 
     from mem in dc.Mapping.GetTable(sourceEntity.GetType()) 
           .RowType.DataMembers 
     where mem.IsAssociation == false 
     select mem; 

    //go through the list of members and compare values 
    foreach (MetaDataMember mem in dataMembers) 
    { 
     object originalValue = mem.StorageAccessor.GetBoxedValue(targetEntity); 
     object newValue = mem.StorageAccessor.GetBoxedValue(sourceEntity); 

     //check if the value has changed 
     if (newValue == null && originalValue != null 
      || newValue != null && !newValue.Equals(originalValue)) 
     { 
      //use reflection to update the target 
      System.Reflection.PropertyInfo propInfo = 
       targetEntity.GetType().GetProperty(mem.Name); 

      propInfo.SetValue(targetEntity, 
           propInfo.GetValue(sourceEntity, null), 
           null); 

      // setboxedvalue bypasses change tracking - otherwise 
      // mem.StorageAccessor.SetBoxedValue(ref targetEntity, newValue); 
      // could be used instead of reflection 
     } 
    } 
} 

... hoặc bạn có thể sao chép nó bằng cách sử dụng DataContractSerializer:

internal static T CloneEntity<T>(T originalEntity) where T : someentitybaseclass 
{ 
    Type entityType = typeof(T); 

    DataContractSerializer ser = 
     new DataContractSerializer(entityType); 

    using (MemoryStream ms = new MemoryStream()) 
    { 
     ser.WriteObject(ms, originalEntity); 
     ms.Position = 0; 
     return (T)ser.ReadObject(ms); 
    } 
} 
+0

sẽ có một cái nhìn Kristofer. – GONeale

+0

Câu trả lời hay! Điều này đang làm việc, tôi đã suy ngẫm về sự phản chiếu. Bạn cảm thấy thế nào về giải pháp này? Tôi cho rằng bất kỳ Clone() nào mà tôi mong đợi sẽ thực hiện một thao tác tương tự. – GONeale

+1

Nếu bạn có các thuộc tính chỉ đọc trong thực thể, bạn cần kiểm tra xem thuộc tính có setter trước khi gọi propInfo.SetValue hay không. Bạn có thể làm điều đó kiểm tra của tôi nếu propInfo.GetSetMethod() trả về một giá trị không null. – pbz

3

tôi đã bị mắc kẹt với cùng một vấn đề và mã Kristofer của làm việc một cách hoàn hảo, cảm ơn nhiều!

Trong trường hợp ai đó quan tâm, tôi đã sửa đổi mã của anh ta để thay vì chấp nhận thực thể đích làm tham số, nó tạo một đối tượng mới và trả về nó. Ngoài ra tôi đã thực hiện các tham số sourceEntity để được chung chung:

public static T CloneEntity<T>(this DataContext dc, T sourceEntity) where T:class, new() 
{ 
    var targetEntity = new T(); 
    //... original method code... 
    return targetEntity; 
} 

Sau đó, tôi có thể làm như sau:

dataContext.MyEntities.Attach(dataContext.CloneEntity(theEntity)); 
11

Nếu bạn tải tổ chức từ DataContext với bộ ObjectTrackingEnabled false sau đó bạn có thể chèn tổ chức này như mới trong một DataContext khác

DataContext db1 = new DataContext(); 
DataContext db2 = new DataContext(); 

db2.ObjectTrackingEnabled = false; 

MyEntity entToClone = db2.Single(e => e.Id == id); 

// ... change some data if it is needed 

db1.MyEntities.InsertOnSubmit(entToClone); 
db1.SubmitChanges(); 
+0

Cảm ơn bạn Rất nhiều, Đây là giải pháp tốt nhất. – JanBorup

+0

Vâng, đây là giải pháp tốt nhất. Cảm ơn! – Rudy

+0

Tôi thấy rằng nó cũng nhân bản các đối tượng con, một cái gì đó mà tôi không muốn. Tôi vẫn nghĩ đây là giải pháp tốt nhất. LINQ to SQL nên có một phương pháp được xây dựng trong thanh lịch cho việc này. – Rudy

0

Đây là giải pháp tương tự như Peter K., cho bản sao LINQ-to-Sql trong VB.Net.

Dim DC As New DataContext 
    Dim DCI As New DataContext 
    DC.ObjectTrackingEnabled = False 

     Dim RGF As sf_RuleGroup = (From G In DC.sf_RuleGroups _ 
            Where G.RuleGroupID = CInt(e.CommandArgument) _ 
            Select G).First() 
     DCI.sf_RuleGroups.InsertOnSubmit(RGF) 
     DCI.SubmitChanges() 
0

Trong Entity framework 6 bạn có thể làm điều này

Dim WorkoutNew As New Workout 'create a record 
ff7db.Workouts.Add(WorkoutNew) 'add it to the table (workout) 
ff7db.Entry(WorkoutNew).CurrentValues.SetValues(WorkoutsPost) ' update its values with a class with the same properties