Доступ к 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);
}