Как отсоединить объект данных LINQ-to-SQL от механизма отслеживания DataContext? - PullRequest
9 голосов
/ 09 марта 2011

Задав этот вопрос , где мне сообщили о том, как работает метод Table<T>.Attach(), у меня возник другой вопрос.

Как отсоединить объект данных LINQ-to-SQL от механизма отслеживания состояния DataContext?По сути, я хочу получить запись и изменить данные в записи.Но когда я вызываю SubmitChanges() в том же экземпляре DataContext, я не хочу, чтобы запись обновлялась, если я не вызвал явно Attach().Как это достигается?

Ответы [ 5 ]

9 голосов
/ 09 марта 2011

Я настоятельно рекомендую, чтобы, если вы собираетесь использовать LINQ to SQL, , вы должны изменить свой дизайн, чтобы приспособить поведение LINQ to SQL к отправке изменений на все присоединенные измененные объекты .По моему опыту, попытка обойти эту функцию приведет только к боли.

7 голосов
/ 01 ноября 2011

С этого сайта , объясняющего, как отсоединить объект linq , добавьте этот метод к объекту, который вы хотите отсоединить:

public void Detach()
{
    GetType().GetMethod("Initialize", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this, null);
}
1 голос
/ 09 марта 2011

К сожалению, вы не можете явно отделить сущности от предыдущего DataContext без сериализации и десериализации сущностей.

Что вы можете сделать для своей цели, - это создать копию объекта, который вы извлекли из БД, и работать с этой копией. В этом случае ваш оригинальный объект остается нетронутым. Когда придет время обновить БД, вы можете просто прикрепить копию к вашему DataContext.

0 голосов
/ 11 декабря 2015

Самым простым решением во многих случаях будет сериализация / десериализация объекта для его простого клонирования. Какой метод сериализации / клонирования вы используете, решать только вам. Этот вопрос содержит несколько предложений на этот счет.

Мне нравится использовать Newtonsoft JSON.NET для сериализации, потому что он очень прост в использовании, имеет минимальные требования (например, не требуются атрибуты компилятора), и я уже использую его для других вещей в моих проектах. В зависимости от вашего варианта использования (например, отсоединение сущности LINQ / SQL для использования в модели пользовательского интерфейса) вы можете стереть идентификаторы базы данных. Простой способ сделать это - передать пользовательский класс DefaultContractResolver в JSON.NET, который исключит свойства идентификатора:

    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();
        }
    }
0 голосов
/ 08 апреля 2011

Я клонировал объекты, запрошенные из DataContext, используя Serialize / Deserialize, и без проблем отправил новый объект в тот же DataContext.Если есть какие-либо присоединенные объекты, их необходимо будет запросить с помощью идентификаторов перед отправкой клона.

/// <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;
            }
        }
    }
}
...