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

时间:2008-12-15 16:31:25

标签: c# .net linq linq-to-sql

是否有任何简单的方法可以访问linq2sql实体类中的DataContext

我正在尝试创建类似EntitySet的内容,但我无法弄清EntitySet如何访问创建实体对象的上下文。

我希望有一个常规的linq2sql实体类,让类可以访问创建它的DataContext。我知道这是可能的,因为当你有一个带有主键的实体类时,linq2sql可以让你选择在不创建新DataContext的情况下加载所有子项。

5 个答案:

答案 0 :(得分:6)

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

首先,为所有实体创建一个接口,以实现从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。在愤怒地使用它之前,请先对此进行更多错误检查!

答案 1 :(得分:3)

基本上没有。

EntitySet<T>类具有由数据上下文分配的内部Source属性,它是按需获取数据的方式。但是,数据类本身并没有类似的东西。

但是,我认为实体框架可以以强制对象层次结构为代价获得更多访问权限。

与Entity Framework不同,LINQ-to-SQL(按设计)可以与常规的,持久性无知的类一起使用 - 因此它不会假设它可以访问这种类型的数据。

答案 2 :(得分:1)

实体类不应该知道数据上下文,因为它只是表的映射,但数据上下文具有所有实体和连接属性的知识

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

数据上下文类将在消耗实体的末尾使用,我不认为实体需要知道上下文,

如果您可以告诉具体情况,我们可以尝试另一种方法。

答案 3 :(得分:0)

我确切地知道你的意思。我们应该在实体的部分类中进行计算/验证,但如果实体无法访问datacontext,那么我们可以做多少?例如,在我的SalesOrder对象中,每当“Ship To”地址发生变化时,SalesOrder都需要查询数据库以查明税收是否适用于该州/邮政编码。我已经打了一段时间,但是今天我崩溃了,并且采用了丑陋的方法,但到目前为止还很好。基本上我所做的就是在我的部分类中创建一个“Context”属性,并在创建实体时使用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,特别是如果你要分离你的实体。

答案 4 :(得分: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 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);
        }