如何在没有泛型类型的情况下进行查询?

发布于 2024-12-11 22:03:45 字数 670 浏览 1 评论 0原文

我将从一段代码开始:

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<>() 的通用变体,但我显然无法使用它。我可能忽略了一些东西......

I'll start with piece of code:

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
}

I am not even sure if i am building that expression correctly. However simply put, i need to call dynamically SingleOrDefault() on that table to find entity by primary key. Every example i had found is using generic variant of GetTable<>(), but i cannot use that obviously. I am probably overlooking something...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

只想待在家 2024-12-18 22:03:45

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

() => 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函数的主体。

(未经测试)

编辑:参数化数据上下文和值

现在我们正在构建此函数:

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

Whenever I build expression trees, I like to start off with an example of what I'm building:

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

From that, we can easily dissect the target expression. You are partway there; you just need to include a call to the GetTable method in the expression tree and then build an outer lambda expression to call the whole thing:

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

We have to convert the SingleOrDefault call to have a return type of object so it can serve as the body of the Func<object> function.

(Untested)

Edit: Parameterizing the data context and value

Now we are building this function:

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

You would change the constants to parameters and add those parameters to the function you compile:

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);    
}
我只土不豪 2024-12-18 22:03:45

如果您使用的是 .NET 4,您可以尝试将返回的对象转换为动态,这样您就可以像这样进行查询。

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

If you are using .NET 4, you could try casting your returned objects as dynamic, so you could then query like this.

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");
}
别想她 2024-12-18 22:03:45

我仍然不完全确定你的整个问题(我怀疑关于dynamic的答案也将解决部分问题)。不过,还是简单回答一下:

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

对于任何 TTable 实现(以及其他接口) ) ITableITable。前者是通用类型的,后者不是。

表单 GetTable() 返回这样一个 Table。但是,GetTable(Type t) 表单返回一个 ITable。由于ITable继承自IQueryable,因此您可以查询它。如果您需要对该查询执行某些通常需要了解类型的操作(例如比较给定的属性),那么根据 Steve Danner 之前给出的答案,dynamic 允许这种情况发生。

I'm still not entirely sure as to the whole of your problem (and I suspect the answer about dynamic is going to solve part of what will come up too). Still, just to answer:

Every example i had found is using generic variant of GetTable<>(), but i cannot use that obviously

For any T, Table<T> implements (among other interfaces) ITable<T> and ITable. The former is generically typed, the latter not.

The form GetTable<T>() returns such a Table<T>. However, the form GetTable(Type t) returns an ITable. Since ITable inherits from IQueryable you can query it. If you need to do something with that query that would normally require knowledge of the type (such as comparing on a given property) then dynamic as per the previous answer given by Steve Danner allows that to happen.

笑,眼淚并存 2024-12-18 22:03:45

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

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

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


编辑:可以从 Microsoft 下载 LINQ 动态查询库,网址为 http://msdn。 microsoft.com/en-us/vcsharp/bb894665.aspx - 只需将 DynamicLINQ.cs 包含在您的项目中即可。

I'd do it using Reflection and the LINQ dynamic query library, personally.

You can get the list of all the keys for a table with dataContext.Mapping.GetMetaType(objectType).IdentityMembers, then access the data with something along the lines of dataContext.GetTable(objectType).Where(key.Name + "==@0", id).

Obviously, I left out a few steps in there - if you have multiple keys, you'll need to build a fuller predicate with a loop over .IdentityMembers, and if you always just have the one key, you can use .First() on it. I haven't tested it either, but it should be pretty close. It'd probably be 6-7 lines of code total - I can write it up (and test) if you need it.


Edit: The LINQ Dynamic Query Library can be downloaded from Microsoft at http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx - just include DynamicLINQ.cs in your project and you're good.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文