从任意查询中提取强类型的数据上下文实例 [英] Extract strongly-typed data context instance from arbitrary query

查看:93
本文介绍了从任意查询中提取强类型的数据上下文实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

我们有一个具有刷新功能的网格(继承自WPF DataGrid)的类库。网格有一个 IQueryable Query 属性,它启用刷新。每个网格的查询不是在类库中定义的,而是在引用的最终项目中定义:

We have a class library which has a grid (inherits from WPF DataGrid) with refresh functionality. The grid has a IQueryable Query property, which enables the refresh. Each grid's query is defined not in the class library, but in the referencing end-project:

var dg = new RefreshableDataGrid();
dg.Query = () => new ProjectDbContext().Persons;

每个网格还有一个用于文本过滤的文本框。当在过滤器中输入文本时,将生成一个表达式,用于检查是否有任何字符串属性或字符串可转换属性(使用 SqlFunctions.StringConvert )包含过滤器字符串。然后,该表达式作为 Where 的参数附加到原始查询,因此只返回包含匹配字符串的记录。

Each grid also has a textbox for text filtering. When text is entered in the filter, an expression is generated which checks if any string property or string-convertible property (using SqlFunctions.StringConvert) contains the filter string. The expression is then appended to the original query as an argument to Where, and thus only the records containing matching strings are returned.

//within the class library
//pseudo-code -- this is actually done via reflection, because at compile time the
//actual type of the grid is not known, and there is no generic placeholder
this.ItemsSource = this.Query.Where(filterExpression)

在某些情况下,过滤器逻辑在终端项目中定义,在实体类型上。例如:

In some cases, the filter logic is defined in end-projects, on the entity type. For example:

public interface IFilterable {
    public Expression<Func<String, Boolean>> TextSearchExpression();
}

public class Email {
    public int ID {get;set;}
    public int PersonID {get;set;}
    public string Address {get;set;}
}

public class Person : IFilterable
    public int ID {get;set;}
    public string LastName {get;set;}
    public string FirstName {get;set;}
    public Expression<Func<String, Boolean>> TextSearchExpression() {
        Dim ctx = new ProjectDbContext();
        return phrase => LastName.Contains(phrase) || FirstName.Contains(phrase) || 
            ctx.Emails.Where(x => x.PersonID = ID && x.Address.Contains(prase).Any();
    }
}

此表达式树使用特定于项目的上下文的实例,该实例与原始查询的实例不同。查询不能使用多个上下文中的组件(至少不在Entity Framework中)我可以重写表达式树以使用特定的实例,但是我需要从查询中提取原始实例。

This expression tree uses an instance of the project-specific context, which is a different instance from that of the original query. Queries cannot use components from multiple contexts (at least not in Entity Framework). I can rewrite the expression tree to use a specific instance, but I need to extract the original instance from the query.

很明显,该查询对上下文实例有一些引用,否则查询将无法返回结果。

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

我不想将上下文实例传递给类库。

I do not want to pass the context instance to the class library.

因此:

给定一个查询,如何我得到用于创建查询的强类型 DbContext 实例

Given a query, how can I get the strongly-typed DbContext instance used to create the query?

换句话说,这种方法的主体是什么:

In other words, what goes in the body of this method:

DbContext GetDbContext<TSource>(IQueryable<TSource> qry) {
    // ???
}


推荐答案


看起来很明显,该查询对上下文实例有一些引用,否则查询将无法返回结果。

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

真实的,但它的实现具体细节和EF封装在内部成员/类/接口内。

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

同时考虑到 DbContext 是建立在 ObjectContext ,持有对 DbContext 的引用并不是很有必要。幸运的是不是这样:)

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 :)

以下使用最新的EF6.1.3的反射和实现细节(如果您不使用某些第三方扩展名 LinqKit 和类似的替换查询提供程序):

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;
}

这篇关于从任意查询中提取强类型的数据上下文实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆