在实体类中访问LINQ-2-SQL DataContext

9
有没有简单的方法可以在linq2sql实体类中访问DataContext?我正在尝试创建类似于EntitySet的东西,但是我无法弄清楚EntitySet如何访问首先创建实体对象的上下文。我想要一个普通的linq2sql实体类,并且希望该类有一种方式可以访问创建它的DataContext。我知道这是可能的,因为当你有一个带有主键的实体类时,linq2sql会给你加载所有子项的选项,而不需要创建新的DataContext。
5个回答

7

我刚刚也不得不做同样的事情。这是我的解决方案(可能不是最好的方法,但至少相当优雅):

首先,创建一个接口,让所有实体都实现它,该接口继承自INotifyPropertyChanging。这用于连接一些扩展方法并保持我们的实现很好地分离。在我的情况下,该接口称为ISandboxObject:

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

接下来创建一个新的静态类,包含一个扩展方法来获取DataContext。这是通过查找附加到INotifyPropertyChanging.PropertyChanging事件的LINQ Change Tracker上的事件处理程序来实现的。一旦我们找到了变化跟踪器,就可以从那里获取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");
    }

现在您有一个很好的扩展方法,可以从实现ISandboxObject接口的任何对象中提供DataContext。在使用之前,请确保进行更多的错误检查!

3
基本上不行。
EntitySet<T>类有一个内部的Source属性,由数据上下文分配,这是它按需获取数据的方式。然而,对于数据类本身没有类似的东西。
但是,我相信Entity Framework可以更多地访问这个,代价是强制对象层次结构。
与Entity Framework不同,LINQ-to-SQL(按设计)可以与常规的持久性无关类一起使用,因此它不会假定它可以访问此类型的数据。

1

实体类不应该意识到数据上下文,因为它只是表的一个映射,但是数据上下文知道所有实体和连接属性的相关信息。

由于实体关系,您可以通过父实体类链接到子表而不是通过数据上下文。

数据上下文类将在消耗实体的最后使用,我不认为实体需要了解上下文的情况。

如果您能描述具体场景,我们可以尝试其他方法。


1
我有同样的问题,虽然我理解你对此的论点(相信我,我支持它),但我确实需要这个功能来满足现实需求。在我们的一些实体部分类中,我们添加了一些属性,这些属性必须根据其实体的某个属性查询数据库,以获取一些其他实体的集合,这些实体在SQL Server中没有直接关联。这真的很丑陋,因为在调用这些属性时(其中一些在循环中),我们正在创建一个新的数据上下文。 - Thiago Silva

0

基本上,您可以通过一些技巧来实现这一点。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通过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);
        }

0

我完全明白你的意思。我们应该在实体的部分类中进行计算/验证,但如果实体没有访问数据上下文,则我们能做多少呢?例如,在我的SalesOrder对象中,每当“Ship To”地址更改时,SalesOrder需要查询数据库以查找是否适用于该州/邮政编码的税。我一直在为此而奋斗,但今天我崩溃了,采用了丑陋的方法,但目前为止还不错。基本上,我所做的就是在我的部分类中创建一个“Context”属性,并在创建实体时将其设置为数据上下文。

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
...

可能会因为你分离实体而有所不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接