C# 如何在T上进行反射以构建查询的表达式树?
我正在尝试构建一个泛型类来处理EF中的实体。这个类与存储库对话,但正是这个类创建了发送到存储库的表达式。无论如何,我只是想实现一个虚拟方法,作为普通查询的基础。具体地说,它将接受一个C# 如何在T上进行反射以构建查询的表达式树?,c#,linq,entity-framework,reflection,expression-trees,C#,Linq,Entity Framework,Reflection,Expression Trees,我正在尝试构建一个泛型类来处理EF中的实体。这个类与存储库对话,但正是这个类创建了发送到存储库的表达式。无论如何,我只是想实现一个虚拟方法,作为普通查询的基础。具体地说,它将接受一个int,只需要对相关实体的主键执行查询 我一直在胡闹,我已经建立了一个反射,这可能有效,也可能无效。我之所以这么说是因为我得到了一个带有LINQ to Entities消息的NotSupportedException,它无法识别方法'System.Object GetValue(System.Object,Syste
int
,只需要对相关实体的主键执行查询
我一直在胡闹,我已经建立了一个反射,这可能有效,也可能无效。我之所以这么说是因为我得到了一个带有LINQ to Entities消息的NotSupportedException
,它无法识别方法'System.Object GetValue(System.Object,System.Object[])方法,并且该方法无法转换为存储表达式。因此,我尝试了另一种方法,它产生了相同的异常,但错误是LINQ表达式节点类型“ArrayIndex”在LINQTo实体中不受支持。我知道这是因为EF不会像L2S那样解析表达式
无论如何,我希望有一个更有经验的人能给我指出正确的方向。我用我的两次尝试发布了整个课程
public class Provider<T> where T : class {
protected readonly Repository<T> Repository = null;
private readonly string TEntityName = typeof(T).Name;
[Inject]
public Provider(
Repository<T> Repository) {
this.Repository = Repository;
}
public virtual void Add(
T TEntity) {
this.Repository.Insert(TEntity);
}
public virtual T Get(
int PrimaryKey) {
// The LINQ expression node type 'ArrayIndex' is not supported in
// LINQ to Entities.
return this.Repository.Select(
t =>
(((int)(t as EntityObject).EntityKey.EntityKeyValues[0].Value) == PrimaryKey)).Single();
// LINQ to Entities does not recognize the method
// 'System.Object GetValue(System.Object, System.Object[])' method,
// and this method cannot be translated into a store expression.
return this.Repository.Select(
t =>
(((int)t.GetType().GetProperties().Single(
p =>
(p.Name == (this.TEntityName + "Id"))).GetValue(t, null)) == PrimaryKey)).Single();
}
public virtual IList<T> GetAll() {
return this.Repository.Select().ToList();
}
protected virtual void Save() {
this.Repository.Update();
}
}
公共类提供程序,其中T:class{
受保护的只读存储库=null;
私有只读字符串TEntityName=typeof(T).Name;
[注入]
公共提供者(
存储库(存储库){
this.Repository=Repository;
}
公共虚拟空添加(
(张力){
this.Repository.Insert(tenty);
}
公共虚拟机无法获取(
int主密钥){
//中不支持LINQ表达式节点类型“ArrayIndex”
//LINQ对实体的访问。
返回this.Repository.Select(
t=>
((int)(t作为EntityObject.EntityKey.EntityKeyValues[0].Value)==PrimaryKey)).Single();
//LINQ to实体无法识别该方法
//'System.Object GetValue(System.Object,System.Object[])方法,
//并且此方法无法转换为存储表达式。
返回this.Repository.Select(
t=>
((int)t.GetType().GetProperties().Single(
p=>
(p.Name==(this.TEntityName+“Id”)).GetValue(t,null))==PrimaryKey().Single();
}
公共虚拟IList GetAll(){
返回此.Repository.Select().ToList();
}
受保护的虚拟void Save(){
this.Repository.Update();
}
}
更新@Gabe的
这就是我的存储库类的外观:
public class Repository<T> where T : class {
protected readonly ObjectContext ObjectContext = null;
private readonly IObjectSet<T> ObjectSet = null;
[Inject]
public Repository(
ObjectContext ObjectContext) {
this.ObjectContext = ObjectContext;
this.ObjectSet = this.ObjectContext.CreateObjectSet<T>();
}
public virtual void Delete(
T Entity) {
this.ObjectSet.DeleteObject(Entity);
}
public virtual void Insert(
T Entity) {
this.ObjectSet.AddObject(Entity);
}
public virtual IQueryable<T> Select() {
return this.ObjectSet;
}
public virtual IQueryable<T> Select(
Expression<Func<T, bool>> Selector) {
return this.ObjectSet.Where(Selector);
}
public virtual void Update() {
this.ObjectContext.SaveChanges();
}
}
公共类存储库,其中T:class{
受保护的只读ObjectContext=null;
私有只读IObjectSet ObjectSet=null;
[注入]
公共存储库(
对象上下文(ObjectContext){
this.ObjectContext=ObjectContext;
this.ObjectSet=this.ObjectContext.CreateObjectSet();
}
公共虚拟无效删除(
(T实体){
this.ObjectSet.DeleteObject(实体);
}
公共虚拟空间插入(
(T实体){
this.ObjectSet.AddObject(实体);
}
公共虚拟IQueryable Select(){
返回此.ObjectSet;
}
公共虚拟IQueryable选择(
表达式选择器){
返回this.ObjectSet.Where(选择器);
}
公共虚拟空间更新(){
this.ObjectContext.SaveChanges();
}
}
方法的名称是基于SQL函数的,而不是基于LINQ方法的,这就是我认为您对我的存储库如何工作感到困惑的地方。正如Pauli所提到的,您需要手动创建
表达式
树,尽管在这种情况下不需要反射。下面是编写Get
函数的方法:
public virtual T Get(
int PrimaryKey)
{
var param = Expression.Parameter(typeof(T));
// create expression for param => param.TEntityNameId == PrimaryKey
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(param, TEntityName + "Id"),
Expression.Constant(PrimaryKey)),
param);
return this.Repository.Single(lambda);
}
公共虚拟机无法获取(
int主密钥)
{
var param=表达式参数(typeof(T));
//为param=>param.TEntityNameId==PrimaryKey创建表达式
var lambda=表达式.lambda(
表达式。相等(
Expression.Property(param,TEntityName+“Id”),
表达式.常量(PrimaryKey)),
参数);
返回此.Repository.Single(lambda);
}
另外,请注意,
GetAll
函数不需要Select
--returnrepository.ToList()代码>也同样有效。正如Pauli所提到的,您需要手动创建表达式
树,尽管在这种情况下不需要反射。下面是编写Get
函数的方法:
public virtual T Get(
int PrimaryKey)
{
var param = Expression.Parameter(typeof(T));
// create expression for param => param.TEntityNameId == PrimaryKey
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.Property(param, TEntityName + "Id"),
Expression.Constant(PrimaryKey)),
param);
return this.Repository.Single(lambda);
}
公共虚拟机无法获取(
int主密钥)
{
var param=表达式参数(typeof(T));
//为param=>param.TEntityNameId==PrimaryKey创建表达式
var lambda=表达式.lambda(
表达式。相等(
Expression.Property(param,TEntityName+“Id”),
表达式.常量(PrimaryKey)),
参数);
返回此.Repository.Single(lambda);
}
另外,请注意,GetAll
函数不需要Select
--returnrepository.ToList()代码>也同样有效。。。。这一定是我的新年决心,学会像那样编写表达式树而不会感到头痛:)@PauliØsterø:是的,这将产生更好的代码与EF无法理解的表达方式相比,我只能看到代码要好得多:)@Gabe,我爱你!这太棒了,我需要学习如何更多/更好地使用这些表达式。哦,在代码简单的日子里,你不必成为“语言律师”来编写代码:(…这一定是我的新年决心,学习编写表达式树就像那样而不会头痛:)@PauliØsterø:是的,这将产生更好的代码与EF无法理解的表达方式相比,我只能看到代码要好得多:)@Gabe,我爱你!这太棒了,我需要