如何在 IEnumerable上创建动态多属性选择在运行时?
我问了一个非常相似的问题 昨天,但直到今天我才意识到我接受的答案并不能解决我所有的问题。我有以下代码:
public Expression<Func<TItem, object>> SelectExpression<TItem>(string fieldName)
{
var param = Expression.Parameter(typeof(TItem), "item");
var field = Expression.Property(param, fieldName);
return Expression.Lambda<Func<TItem, object>>(field,
new ParameterExpression[] { param });
}
其用法如下:
string primaryKey = _map.GetPrimaryKeys(typeof(TOriginator)).Single();
var primaryKeyExpression = SelectExpression<TOriginator>(primaryKey);
var primaryKeyResults = query.Select(primaryKeyExpression).ToList();
这允许我从 IQueryable
中提取主键。问题是此代码仅适用于单个主键,我需要添加对多个 PK 的支持。
那么,有什么方法可以调整上面的 SelectExpression
方法来获取 IEnumerable
(这是我的主键属性名称列表)并让该方法返回选择这些键的表达式?
即鉴于以下情况:
var knownRuntimePrimaryKeys = new string[] { "CustomerId", "OrderId" }`
我的选择需要执行以下操作(在运行时):
var primaryKeys = query.Select(x=> new { x.CustomerId, x.OrderId });
I asked a very similar question yesterday, but it wasn't until today I realised the answer I accepted doesn't solve all my problems. I have the following code:
public Expression<Func<TItem, object>> SelectExpression<TItem>(string fieldName)
{
var param = Expression.Parameter(typeof(TItem), "item");
var field = Expression.Property(param, fieldName);
return Expression.Lambda<Func<TItem, object>>(field,
new ParameterExpression[] { param });
}
Which is used as follows:
string primaryKey = _map.GetPrimaryKeys(typeof(TOriginator)).Single();
var primaryKeyExpression = SelectExpression<TOriginator>(primaryKey);
var primaryKeyResults = query.Select(primaryKeyExpression).ToList();
This allows me to pull out the primary keys from an IQueryable<TUnknown>
. The problem is that this code only works with a single primary key and I need to add support for multiple PKs.
So, is there any way I can adapt the SelectExpression
method above to take an IEnumerable<string>
(which is my list of primary key property names) and have the method return an expression that selects those keys?
I.e. Given the following:
var knownRuntimePrimaryKeys = new string[] { "CustomerId", "OrderId" }`
My Select needs to do the following (at runtime):
var primaryKeys = query.Select(x=> new { x.CustomerId, x.OrderId });
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
没有简单的方法可以完全满足您的要求,因为它需要您动态创建新类型(匿名类型是在静态已知时由编译器创建的)。虽然它当然可行,但它可能不是最简单的选择...
您可以使用 元组:
There is no easy way to do exactly what you want, because it would require you to create a new type dynamically (anonymous types are created by the compiler when they're known statically). While it is certainly feasible, it's probably not the easiest option...
You can achieve a similar result using tuples:
您可以使用
Tuple<>
因为匿名类型必须在编译时已知:然后:
将生成以下表达式:
You could use
Tuple<>
because anonymous types must be known at compile time:and then:
will generate the following expression:
正如有人已经指出的那样,您本质上是在尝试获取在运行时构造的匿名类型,这是行不通的。
这实际上取决于你的意思。明显的答案是使用运行时构造,例如字典、元组等。但是您自己可能完全意识到这一点,所以我假设您想要一个具有真实字段名称的编译时类型结果,以便任何在编译过程中会发现
primaryKeys
的错误使用。如果是这样,那么恐怕你唯一的选择就是在编译之前生成相关代码。这并不像听起来那么糟糕,但并不完全透明:当您更改架构时,您必须以某种方式重新运行代码生成。
在我们公司,我们正是这样做的,受到 SubSonic 的启发,但发现 SubSonic 本身并不完全是我们想要的。在我看来,效果相当好。
As someone has already pointed out, you are essentially trying to get an anonymous type constructed at runtime, which is not going to work.
This really depends on what you mean. The obvious answers are to use runtime constructs, such as a dictionary, a tuple, etc. But you are probably fully aware of this yourself, so I assume that you want a compile-time-typed result with real field names, so that any mis-use of
primaryKeys
gets caught during compilation.If so, then I'm afraid your only option is to generate the relevant code before compilation. This isn't as bad as it might sound, but is not completely transparent: when you change the schema, you have to re-run the code generation somehow.
At our company we've done exactly that, being inspired by SubSonic but finding that SubSonic itself wasn't quite what we wanted. It worked out rather well in my opinion.