Extract strongly-typed data context instance from arbitrary query

纵饮孤独 提交于 2019-12-05 03:19:49

It seems obvious that the query holds some reference to the context instance, otherwise the query would not be able to return results.

That's true, but it's implementation specific detail and in EF is encapsulated inside internal members/classes/interfaces.

Also taking into account that DbContext is build on top of the ObjectContext, holding a reference to the DbContext is not strongly necessary. Fortunately that's not the case :)

The following uses reflection and implementation details of the latest EF6.1.3 (tested and working if you don't use some 3rd party extensions like LinqKit and similar that replace the query provider):

public static DbContext GetDbContext<TSource>(this IQueryable<TSource> query)
{
    const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
    var provider = query.Provider;
    var internalContextProperty = provider.GetType().GetProperty("InternalContext", flags);
    if (internalContextProperty == null) return null;
    var internalContext = internalContextProperty.GetValue(provider, null);
    if (internalContext == null) return null;
    var ownerProperty = internalContext.GetType().GetProperty("Owner", flags);
    if (ownerProperty == null) return null;
    var dbContext = (DbContext)ownerProperty.GetValue(internalContext, null);
    return dbContext;
}

I would recommend passing an instance of MyDataContext into your query function

public class DACPerson
{
    public static IQueryable<Person> GetAllAsQueryable(MyDataContext db)
    {
        return db.People.AsQueryable();
    }


}

This allows you to do the following in the calling function:

public List<Person> UpdateListofPeople(string term)
{
    using(DataContext db = new DataContext())
    {
        var people = DACPerson.GetAllAsQueryable(db);
        var result = people.Where(x=>x.Username.Contains(term)).

        //call other Data Access Component FUnctions here using same DB....
    }
}

i.e. you can bring the filtering to the layer above the data access class.

Some people may not like to do this. You may get the advice that its best to keep all entityframeowrk functionality within the same layer and just return the DTO. I like the above approach though. It depends on who will have to maintain each part of your application in the future.

Hope this helps at least

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!