Zev*_*itz 8 entity-framework entity-framework-6
背景
我们有一个类库,它有一个带有刷新功能的网格(继承自WPF DataGrid).网格有一个IQueryable Query属性,可以刷新.每个网格的查询不是在类库中定义的,而是在引用的end-project中定义的:
var dg = new RefreshableDataGrid();
dg.Query = () => new ProjectDbContext().Persons;
Run Code Online (Sandbox Code Playgroud)
每个网格还有一个文本框用于文本过滤.在筛选器中输入文本时,将生成一个表达式,该表达式检查是否有任何字符串属性或字符串可转换属性(使用SqlFunctions.StringConvert)包含筛选字符串.然后将表达式作为参数附加到原始查询Where,因此仅返回包含匹配字符串的记录.
//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)
Run Code Online (Sandbox Code Playgroud)
在某些情况下,过滤器逻辑在实体类型的最终项目中定义.例如:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
此表达式树使用项目特定上下文的实例,该实例与原始查询的实例不同.查询不能使用来自多个上下文的组件(至少不在实体框架中).我可以重写表达式树以使用特定的实例,但我需要从查询中提取原始实例.
很明显,查询包含对上下文实例的一些引用,否则查询将无法返回结果.
我不想将上下文实例传递给类库.
因此:
给定查询,如何获取DbContext用于创建查询的强类型实例?
换句话说,这种方法的主体是什么:
DbContext GetDbContext<TSource>(IQueryable<TSource> qry) {
// ???
}
Run Code Online (Sandbox Code Playgroud)
显然,查询保留了对上下文实例的一些引用,否则查询将无法返回结果。
确实如此,但它是特定于实现的细节,并且在 EF 中封装在内部成员/类/接口中。
另外考虑到DbContext是建立在 之上的ObjectContext,持有对 的引用DbContext并不是非常必要的。幸运的是事实并非如此:)
以下使用最新 EF6.1.3 的反射和实现细节(如果您不使用某些第三方扩展(例如LinqKit和类似的替换查询提供程序的扩展),则经过测试和工作):
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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
201 次 |
| 最近记录: |