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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
0
6 637
5

Ответы 5

В основном нет.

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

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

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

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

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

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

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

У меня такая же проблема, и хотя я понимаю ваши аргументы в пользу этого (поверьте мне, я за это), у меня есть реальная потребность в этом. В некоторые из наших частичных классов сущностей мы добавили некоторые свойства, которые должны запрашивать базу данных на основе свойства их сущности, чтобы захватить некоторую коллекцию других сущностей, которые напрямую не связаны в SQL Server. Это действительно уродливо, потому что мы создаем новый контекст данных при вызове этих свойств (некоторые из них в цикле).

Thiago Silva 18.04.2010 08:02

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

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, особенно если вы отключаете свои сущности.

По сути, вы можете сделать это с помощью небольшого взлома. DataCOntext прикрепляет StandardChangeTracker к вашей сущности:

            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);
        }

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

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

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

Затем создайте новый статический класс, содержащий метод расширения для получения DataContext. Это достигается путем поиска обработчика событий в LINQ Change Tracker, прикрепленном к событию 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. Пожалуйста, сделайте еще несколько проверок на ошибки, прежде чем использовать это в гневе!

Другие вопросы по теме