Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在T上进行反射以构建查询的表达式树?_C#_Linq_Entity Framework_Reflection_Expression Trees - Fatal编程技术网

C# 如何在T上进行反射以构建查询的表达式树?

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

我正在尝试构建一个泛型类来处理EF中的实体。这个类与存储库对话,但正是这个类创建了发送到存储库的表达式。无论如何,我只是想实现一个虚拟方法,作为普通查询的基础。具体地说,它将接受一个
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,我爱你!这太棒了,我需要