如何使查询没有泛型类型

本文关键字:泛型类型 查询 何使 | 更新日期: 2023-09-27 18:12:22

我将从一段代码开始:

var objectType = typeof(Department); // Department is entity class from linqdatacontext
using (var dataContext = new DataModel.ModelDataContext())
{
    var entity = Expression.Parameter(objectType, "model");
    var keyValue = Expression.Property(entity, "Id");
    var pkValue = Expression.Constant(reader.Value);
    var cond = Expression.Equal(keyValue, pkValue);
    var table = dataContext.GetTable(objectType);
    ... // and here i don't how to proceed
}

我甚至不确定我是否正确地构建了这个表达式。然而,简单地说,我需要在该表上动态调用SingleOrDefault()以通过主键查找实体。我发现的每个例子都是使用GetTable<>()的通用变体,但我不能明显地使用它。我可能忽略了一些东西…

如何使查询没有泛型类型

每当我构建表达式树时,我喜欢从我正在构建的示例开始:

() => dataContext.GetTable<TEntity>().SingleOrDefault(entity => entity.Id == 1);

由此,我们可以很容易地解剖目标表达式。你已经成功了一半;你只需要在表达式树中包含对GetTable方法的调用,然后构建一个外部lambda表达式来调用整个东西:

using(var dataContext = new DataModel.ModelDataContext())
{
    var getTableCall = Expression.Call(
        Expression.Constant(dataContext),
        "GetTable",
        new[] { entityType });
    var entity = Expression.Parameter(entityType, "entity");
    var idCheck = Expression.Equal(
        Expression.Property(entity, "Id"),
        Expression.Constant(reader.Value));
    var idCheckLambda = Expression.Lambda(idCheck, entity);
    var singleOrDefaultCall = Expression.Call(
        typeof(Queryable),
        "SingleOrDefault",
        new[] { entityType },
        getTableCall,
        Expression.Quote(idCheckLambda));
    var singleOrDefaultLambda = Expression.Lambda<Func<object>>(
        Expression.Convert(singleOrDefaultCall, typeof(object)));
    var singleOrDefaultFunction = singleOrDefaultLambda.Compile();
    return singleOrDefaultFunction();    
}

我们必须将SingleOrDefault调用转换为具有返回类型的对象,以便它可以作为Func<object>函数的主体。

(未测试)

Edit:参数化数据上下文和值

现在我们正在构建这个函数:

(dataContext, value) => dataContext.GetTable<TEntity>().SingleOrDefault(entity => entity.Id == value);

您可以将常量更改为参数,并将这些参数添加到您编译的函数中:

var dataContextParameter = Expression.Parameter(typeof(ModelDataContext), "dataContext");
var valueParameter = Expression.Parameter(typeof(object), "value");
var getTableCall = Expression.Call(
    dataContextParameter,
    "GetTable",
    new[] { entityType });
var entity = Expression.Parameter(entityType, "entity");
var idCheck = Expression.Equal(
    Expression.Property(entity, "Id"),
    valueParameter);
var idCheckLambda = Expression.Lambda(idCheck, entity);
var singleOrDefaultCall = Expression.Call(
    typeof(Queryable),
    "SingleOrDefault",
    new[] { entityType },
    getTableCall,
    Expression.Quote(idCheckLambda));
var singleOrDefaultLambda =
    Expression.Lambda<Func<ModelDataContext, object, object>>(
        Expression.Convert(singleOrDefaultCall, typeof(object)),
        dataContextParameter,
        valueParameter);
var singleOrDefaultFunction = singleOrDefaultLambda.Compile();
// Usage
using(var dataContext = new DataModel.ModelDataContext())
{
    return singleOrDefaultFunction(dataContext, reader.Value);    
}

如果你使用的是。net 4,你可以尝试将返回的对象转换为dynamic,这样你就可以像这样查询了。

using (var dataContext = new DataModel.ModelDataContext())
{
   var entity = Expression.Parameter(objectType, "model");
   var keyValue = Expression.Property(entity, "Id");
   var pkValue = Expression.Constant(reader.Value);
   var cond = Expression.Equal(keyValue, pkValue);
   var table = dataContext.GetTable(objectType);
   var result = table.Where(ent => ((dynamic)ent).SomeField == "SomeValue");
}

我仍然不完全确定你的整个问题(我怀疑关于dynamic的答案将解决部分问题)。仍然,只是为了回答:

我发现的每个例子都是使用GetTable<>()的通用变体,但我不能明显使用

对于任何T, Table<T>实现(除其他接口外)ITable<T>ITable。前者是泛型的,后者不是。

形式GetTable<T>()返回这样一个Table<T>。但是,表单GetTable(Type t)返回一个ITable。因为ITable继承自IQueryable,所以你可以查询它。如果您需要对该查询做一些通常需要类型知识的事情(例如对给定属性进行比较),那么根据Steve Danner给出的先前答案,dynamic允许这种情况发生。

我个人会使用反射和LINQ动态查询库。

您可以获取具有dataContext.Mapping.GetMetaType(objectType).IdentityMembers的表的所有键的列表,然后使用沿dataContext.GetTable(objectType).Where(key.Name + "==@0", id)行的内容访问数据。

显然,我在那里遗漏了几个步骤—如果您有多个键,则需要在.IdentityMembers上构建一个更完整的谓词,并且如果您总是只有一个键,则可以在其上使用. first()。我也没有测试过,但应该很接近。可能总共有6-7行代码——如果你需要的话,我可以写出来(并测试)。


编辑:LINQ动态查询库可以从微软下载http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx -只要在你的项目中包含DynamicLINQ.cs,你就很好了。