Determine the source DataContext for a Linq to Sql

2020-03-24 08:08发布

问题:

In my application I have several DataContexts that connects to different databases with different schemas. In a custom user control I display the results of the query and let the user edit them, and when the user edits the data I want to persist the changes to the database. To do that I need a reference to the source DataContext (or at least the source datacontext type) so I can do a DataContext.SubmitChanges();

Is there any way to determine which DataContext a query comes from? The DataQuery class itself is marked as internal, so I can't access its context property without resorting to ugly reflection hacks, so I'm looking for a cleaner approach.

There are (several) ways around this problem, passing along a reference to the source DataContext for instance, but I imagine there must be a simpler way to do this.

Edit: The following code works, but it's ugly:

FieldInfo contextField = query.GetType().GetField("context", BindingFlags.Instance | BindingFlags.NonPublic);
if (query != null)
{
  queryContext = contextField.GetValue(value) as DataContext;
}

回答1:

I think you're going to have to simply pass the DataContext to the code (manually). Sorry.



回答2:

Yes - using reflection is about the only way to determine the DataContext to which the query belongs. It's the same with the Data Objects that are created when the query is triggered.

What follows doesn't strictly answer Rune's question, but may be helpful if you want to use reflection to determine whether a Data Object as attached to and monitored by a Data Context:

The following code defines a Context property which can be placed onto a data object, and then used to return the DataContext (if any) that the object is attached to.

Private Const StandardChangeTrackerName As String = "System.Data.Linq.ChangeTracker+StandardChangeTracker"

Private _context As DataClasses1DataContext
Public Property Context() As DataClasses1DataContext
    Get
        Dim hasContext As Boolean = False
        Dim myType As Type = Me.GetType()
        Dim propertyChangingField As FieldInfo = myType.GetField("PropertyChangingEvent", BindingFlags.NonPublic Or BindingFlags.Instance)
        Dim propertyChangingDelegate As PropertyChangingEventHandler = propertyChangingField.GetValue(Me)
        Dim delegateType As Type = Nothing

        For Each thisDelegate In propertyChangingDelegate.GetInvocationList()
            delegateType = thisDelegate.Target.GetType()
            If delegateType.FullName.Equals(StandardChangeTrackerName) Then
                propertyChangingDelegate = thisDelegate
                hasContext = True
                Exit For
            End If
        Next

        If hasContext Then
            Dim targetField = propertyChangingDelegate.Target
            Dim servicesField As FieldInfo = targetField.GetType().GetField("services", BindingFlags.NonPublic Or BindingFlags.Instance)
            If servicesField IsNot Nothing Then

                Dim servicesObject = servicesField.GetValue(targetField)

                Dim contextField As FieldInfo = servicesObject.GetType.GetField("context", BindingFlags.NonPublic Or BindingFlags.Instance)

                _context = contextField.GetValue(servicesObject)

            End If
        End If

        Return _context
    End Get
    Set(ByVal value As DataClasses1DataContext)

        _context = value

    End Set

End Property

Take care to note that the object can only locate it's DataContext if it is currently attached to the context with ChangeTracking switched on. This property relies on the fact that the DataContext has subscribed to the object's OnPropertyChanging event to monitor changes over the lifespan of the object.

If this was helpful, please up-vote this post.

For more info on using reflection to find event handlers: http://weblogs.asp.net/avnerk/archive/2007/03/29/reflecting-over-an-event.aspx http://www.bobpowell.net/eventsubscribers.htm