Доступ к DataContext LINQ-2-SQL в классе сущностей

Есть ли простой способ доступа к DataContext в классе сущности linq2sql.

Я пытаюсь создать что-то вроде EntitySet, но я не могу понять, как EntitySet имеет доступ к контексту, который создал объект сущности в первую очередь.

Я хочу иметь обычный класс сущностей linq2sql с возможностью доступа класса к DataContext, который его создал. Я знаю, это возможно, потому что, когда у вас есть класс сущности с первичным ключом, linq2sql дает вам возможность загружать всех детей без создания нового DataContext.

Ответ 1

Мне просто нужно было сделать то же самое. Здесь мое решение (хотя, вероятно, не самый лучший подход, но, по крайней мере, довольно элегантный):

Во-первых, создайте интерфейс для всех ваших сущностей для реализации, которые наследуются от INotifyPropertyChanging. Это используется для подключения некоторых методов расширения и сохранения нашей реализации в отдельности. В моем случае интерфейс называется ISandboxObject:

public interface ISandboxObject : INotifyPropertyChanging
{
    // This is just a marker interface for Extension Methods
}

Затем создайте новый статический класс, чтобы содержать метод расширения для получения DataContext. Это достигается путем поиска обработчика событий в отслеживании изменений LINQ, связанного с событием INotifyPropertyChanging.PropertyChanging. Как только мы найдем трекер изменений, мы можем получить DataContext отсюда:

    /// <summary>
    /// Obtain the DataContext providing this entity
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static DataContext GetContext(this ISandboxObject obj)
    {
        FieldInfo fEvent = obj.GetType().GetField("PropertyChanging", BindingFlags.NonPublic | BindingFlags.Instance);
        MulticastDelegate dEvent = (MulticastDelegate)fEvent.GetValue(obj);
        Delegate[] onChangingHandlers = dEvent.GetInvocationList();

        // Obtain the ChangeTracker
        foreach (Delegate handler in onChangingHandlers)
        {
            if (handler.Target.GetType().Name == "StandardChangeTracker")
            {
                // Obtain the 'services' private field of the 'tracker'
                object tracker = handler.Target;
                object services = tracker.GetType().GetField("services", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(tracker);

                // Get the Context
                DataContext context = services.GetType().GetProperty("Context").GetValue(services, null) as DataContext;
                return context;
            }
        }

        // Not found
        throw new Exception("Error reflecting object");
    }

Теперь у вас есть хороший метод расширения, который предоставит вам DataContext из любого объекта, реализующего ISandboxObject. Пожалуйста, сделайте еще несколько ошибок в этом, прежде чем использовать его в гневе!

Ответ 2

В принципе, нет.

Класс EntitySet<T> имеет внутреннее свойство Source, которое присваивается контекстом данных, каким образом он получает данные по запросу. Однако для самих классов данных ничего подобного нет.

Однако, я считаю, что Entity Framework имеет гораздо больший доступ к этому за счет иерархии принудительных объектов.

В отличие от Entity Framework, LINQ-to-SQL (по дизайну) может использоваться с обычными, несовместимыми с персистентностью классами, поэтому он не предполагает, что он имеет доступ к данным этого типа.

Ответ 3

Класс Entity не должен знать контекст данных как просто отображение таблицы, но контекст данных имеет знание всех объектов и свойств соединения

Вы можете ссылаться на дочернюю таблицу через родительский класс сущности из-за отношения объекта, а не через контекст данных.

Класс контекста данных будет использоваться в конце, где сущности будут потреблены, я не вижу необходимости, чтобы сущности знали о контексте,

Если вы можете сказать конкретный сценарий, мы можем попробовать другой подход.

Ответ 4

Я точно знаю, что вы имеете в виду. Мы должны выполнять наши вычисления/валидацию внутри частичного класса сущности, но если у объекта нет доступа к datacontext, то сколько мы можем сделать? Например, в моем объекте SalesOrder, когда изменяется адрес "Корабль", SalesOrder должен запрашивать базу данных, чтобы узнать, применяется ли налог к ​​этому состоянию /zip. Я боролся с этим некоторое время, но сегодня я сломался и пошел с уродливым методом, но пока все хорошо. По сути, все, что я делаю, это создать свойство "Контекст" в моем частичном классе и установить его с помощью datacontext всякий раз, когда создается сущность.

Partial Class SalesOrder
    Private moContext As L2S_SalesOrdersDataContext

    Friend Property Context() As L2S_SalesOrdersDataContext
        Get
            Return moContext
        End Get
        Set(ByVal value As L2S_SalesOrdersDataContext)
            moContext = value
        End Set
    End Property
...

YMMV, особенно если вы отсоединяете свои объекты.

Ответ 5

В принципе, вы можете сделать это с небольшим взломом. DataCOntext присоединяет к вашему объекту стандартную привязку:

            DataContext context = null;
            object changeTracker = (from i in o1.GetInvocationList() where i.Target.GetType().FullName == "System.Data.Linq.ChangeTracker+StandardChangeTracker" select i.Target).FirstOrDefault();
            if (changeTracker != null) // DataCOntext tracks our changes through StandardChangeTracker
            {
                object services = Reflector.GetFieldValue(changeTracker, "services");
                context = (DataContext)Reflector.GetFieldValue(services, "context");
            }

Где Reflector.GetFieldValue равно

        public static object GetFieldValue(object instance, string propertyName)
        {
            return instance.GetType().GetField(propertyName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instance);
        }