How to detach a LINQ-to-SQL data object from the DataContext's tracking mechanism?

隐身守侯 提交于 2019-12-09 15:50:12

问题


After asking this question, where I was informed of how the Table<T>.Attach() method works, I have another question.

How do you detach a LINQ-to-SQL data object from the DataContext's state tracking mechanism? Basically, I want to pull a record and change the data on the record. But, when I call SubmitChanges() on the same DataContext instance, I do not want the record to be updated unless I have explicitly called Attach(). How is this accomplished?


回答1:


From this site explaining how to detach a linq object add this method to the object you want to detach:

public void Detach()
{
    GetType().GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this, null);
}



回答2:


I strongly recommend that if you're going to use LINQ to SQL, you should change your design to accommodate LINQ to SQL's behavior of submitting changes on all attached modified entities. In my experience, attempting to work around this feature will only lead to pain.




回答3:


Unfortunately, you cannot explicitly detach entities from previous DataContext, without serializing and deserializing the entities.

What you can do for your purpose is to create a copy of the object you pulled out of the DB and work with the copy. In this case your original object is untouched. When the time comes to update the DB, you can simply attach the copy to your DataContext.




回答4:


I have cloned objects queried from a DataContext using Serialize/Deserialize and submitted the new object to the same DataContext without problems. If there are any attached entities, they will need to be requeried using the IDs before submitting the clone.

/// <summary>Used for serializing and de-serializing objects.</summary>
public static class Serializer
{
    /// <summary>Clones an object.</summary>
    /// <typeparam name="T">The type of object to be cloned.</typeparam>
    /// <param name="source">The object to be cloned.</param>
    /// <returns>A clone of the specified object.</returns>
    public static T Clone<T>(T source)
    {
        return Deserialize<T>(Serialize(source));
    }

    /// <summary>Serializes an object as an XML string.</summary>
    /// <param name="value">A System.Object representing the object to be serialized.</param>
    /// <returns>A System.String representing an XML representation of the specified object.</returns>
    public static string Serialize(object value)
    {
        if (value.GetType() == typeof(string))
        {
            return value.ToString();
        }

        StringWriter stringWriter = new StringWriter();
        using (XmlWriter writer = XmlWriter.Create(stringWriter))
        {
            DataContractSerializer serializer = new DataContractSerializer(value.GetType());
            serializer.WriteObject(writer, value);
        }

        return stringWriter.ToString();
    }

    /// <summary>Creates an object from an XML representation of the object.</summary>
    /// <typeparam name="T">The type of object to be created.</typeparam>
    /// <param name="serializedValue">A System.String representing an XML representation of an object.</param>
    /// <returns>A new object.</returns>
    public static T Deserialize<T>(string serializedValue)
    {
        Type type = typeof(T);
        using (StringReader stringReader = new StringReader(serializedValue))
        {
            using (XmlReader reader = XmlReader.Create(stringReader))
            {
                DataContractSerializer serializer = new DataContractSerializer(type);
                object deserializedValue = serializer.ReadObject(reader);
                return (T)deserializedValue;
            }
        }
    }
}



回答5:


The simplest solution in many cases will be to serialize/deserialze the object to do an easy clone of it. Which serialize/clone method you use is up to you. This question has a bunch of suggestions in that regard.

I like to use Newtonsoft JSON.NET for serialization because it is super-easy to use, has minimal requirements (e.g. no compiler attributes required) and I already use it for other stuff in my projects. Depending on your use case (e.g. detaching a LINQ/SQL entity to use within a UI model) you may want to wipe off the database IDs. An easy way to do that is to pass a custom DefaultContractResolver class to JSON.NET that will exclude the ID properties:

    return JsonConvert.SerializeObject(oModel, new JsonSerializerSettings() { ContractResolver = new DNSConfigurationModel.DNSConfigSerializer() });

    /// <summary>
    /// Helper class to ensure that we do not serialize the domainAdvancedDNS child objects 
    /// (we will create our own child collections for serialization). We also suppress serialization of the key ID's.
    /// </summary>
    public class DNSConfigSerializer : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
            return (from p in properties
                    where p.PropertyName != "DomainAdvancedDNS" &&
                          p.PropertyName != "domainAdvancedDNSSRVs" &&
                          !(p.DeclaringType.Name == "DomainAdvancedDN" && p.PropertyName == "domainAdvancedDNSConfigID") &&
                          p.PropertyName != "DomainAdvancedDNSID" &&
                          p.PropertyName != "domainAdvancedDNSSRVID"
                    select p).ToList();
        }
    }


来源:https://stackoverflow.com/questions/5244687/how-to-detach-a-linq-to-sql-data-object-from-the-datacontexts-tracking-mechanis

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!