Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access LINQ-2-SQL DataContext in entity class

Is there any simple way to access the DataContext in a linq2sql entity class.

I'm trying to create something like EntitySet but I cannot figure out how the EntitySet has access to the context that created the entity object in the first place.

I want to have a regular linq2sql entity class with a way for the class to access the DataContext that created it. I know it's possible because when you have an entity class with a primary key linq2sql gives you the option to load all children without creating a new DataContext.

like image 400
Bobby Z Avatar asked Dec 15 '08 16:12

Bobby Z


3 Answers

I've just had to do exactly the same thing. Here's my solution (albeit probably not the best approach, but is at least quite elegant):

Firstly, Create an interface for all your entities to implement that inherits from INotifyPropertyChanging. This is used to hook up some extension methods and keep our implementation nice seperate. In my case the interface is called ISandboxObject:

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

Then Create a new static class to contain an extension method to obtain the DataContext. This is achieved by looking for an event handler on the LINQ Change Tracker attached to the INotifyPropertyChanging.PropertyChanging event. Once we've found the change tracker, we can obtain the DataContext from there:

    /// <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");
    }

Now you have a nice extension method that will provide you with a DataContext from any object implementing ISandboxObject. Please do put some more error checking in this before using it in anger!

like image 184
Dan Avatar answered Nov 20 '22 23:11

Dan


Basically, no.

The EntitySet<T> class has an internal Source property that is assigned by the data-context, which is how it gets at the data on-demand. However, there is nothing similar for the data classes themselves.

However, I believe that Entity Framework has a lot more access to this, at the cost of the enforced object hierarchy.

Unlike Entity Framework, LINQ-to-SQL (by design) can be used with regular, persistence-ignorant classes - so it doesn't assume that it has access to this type of data.

like image 32
Marc Gravell Avatar answered Nov 20 '22 22:11

Marc Gravell


An Entity class should not be aware of the data context as its just a mapping of the table but the data context has the knowledge of all the entities and the connection properties

You are able to link to the child table through the parent entity class because of the entity relationship and not through the data context

The data context class will be used at the end where the entities are consumed, I don't see a need for the entities to be aware of the context,

If you can tell the specific scenario we can try another approach.

like image 1
Rony Avatar answered Nov 20 '22 23:11

Rony