【问题标题】:Access LINQ-2-SQL DataContext in entity class在实体类中访问 LINQ-2-SQL DataContext
【发布时间】:2008-12-15 16:31:25
【问题描述】:

有什么简单的方法可以访问 linq2sql 实体类中的DataContext

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

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

【问题讨论】:

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


    【解决方案1】:

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

    首先,为所有要实现的实体创建一个接口,该接口继承自 INotifyPropertyChanging。这用于连接一些扩展方法并保持我们的实现独立。在我的例子中,这个接口被称为 ISandboxObject:

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

    然后创建一个新的静态类来包含一个扩展方法来获取DataContext。这是通过在附加到 INotifyPropertyChanging.PropertyChanging 事件的 LINQ 更改跟踪器上查找事件处理程序来实现的。找到更改跟踪器后,我们可以从那里获取 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。在愤怒使用它之前,请做更多的错误检查!

    【讨论】:

      【解决方案2】:

      基本上没有。

      EntitySet&lt;T&gt; 类有一个由数据上下文分配的内部Source 属性,这是它按需获取数据的方式。但是,数据类本身没有任何相似之处。

      但是,我相信 Entity Framework 有更多的访问权限,但以强制对象层次结构为代价。

      与实体框架不同,LINQ-to-SQL(按设计)可以与常规的、不了解持久性的类一起使用 - 因此它不假定它可以访问此类数据。

      【讨论】:

        【解决方案3】:

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

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

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

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

        【讨论】:

        • 我有同样的问题,虽然我理解你对此的论点(相信我,我赞成它),但我对此有实际需求。在我们的一些实体部分类中,我们添加了一些属性,这些属性必须根据实体的属性来查询数据库,以获取在 SQL Server 中不直接关联的其他实体的一些集合。这真的很难看,因为我们在调用这些属性时创建了一个新的数据上下文(其中一些在循环中)。
        【解决方案4】:

        我完全明白你的意思。我们应该在实体的部分类中进行计算/验证,但如果实体无法访问数据上下文,那么我们能做多少?例如,在我的 SalesOrder 对象中,每当“Ship To”地址发生更改时,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,尤其是在分离实体时。

        【讨论】:

          【解决方案5】:

          基本上,您可以通过一些技巧来做到这一点。 DataCONtext 将 StandardChangeTracker 附加到您的实体:

          数据上下文上下文 = null; object changeTracker = (from i in o1.GetInvocationList() where i.Target.GetType().FullName == "System.Data.Linq.ChangeTracker+StandardChangeTracker" 选择 i.Target).FirstOrDefault(); if (changeTracker != null) // DataCONtext 通过 StandardChangeTracker 跟踪我们的更改 { 对象服务 = Reflector.GetFieldValue(changeTracker, "services"); context = (DataContext)Reflector.GetFieldValue(services, "context"); }

          Reflector.GetFieldValue 等于

          公共静态对象GetFieldValue(对象实例,字符串propertyName) { return instance.GetType().GetField(propertyName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instance); }

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多