我试图通过发送表达式(C#mongo驱动程序版本2.7.3)来查询一些数据并投影到具有较少属性的类。 我试图理解为什么特定表达式失败。 失败极大地限制了用户编写通用投影,并迫使他在每次调用中内联写入投影。 这是一个简化的示例:
private IMongoCollection<MyOriginalClass> _collection;
class MyOriginalClass // imagine this class has many more properties
{
public int ID { get; set; }
}
class MyProjectedClass
{
public int ID { get; set; }
}
void DoWork()
{
var data1 = GetData(lib => new MyProjectedClass { ID = lib.ID }); // succeeds
var data2 = GetData(lib => ToProjected(lib)); // Fails in mongo driver: Index was out of range. Must be non-negative and less than the size of the collection.Parameter name: index
}
IEnumerable<MyProjectedClass> GetData(Expression<Func<MyOriginalClass, MyProjectedClass>> projection)
{
return _collection
.Aggregate()
.Project(Builders<MyOriginalClass>.Projection.Expression(projection))
.ToList();
}
MyProjectedClass ToProjected(MyOriginalClass orig)
{
return new MyProjectedClass {ID = orig.ID};
}
答案 0 :(得分:2)
第一个(成功的)用法是mongo驱动程序可以在运行时查看以使其知道ID = lib.ID的表达式。具体是NewExpression。
例如Visual Studio允许在调试器下可视化表达式,并且第一个显示:
.Lambda #Lambda1<System.Func`2[ConsoleApp1.Program+MyOriginalClass,ConsoleApp1.Program+MyProjectedClass]>(ConsoleApp1.Program+MyOriginalClass $lib)
{
.New ConsoleApp1.Program+MyProjectedClass(){
ID = $lib.ID
}
}
第二个(失败的)用法是仅调用ToProjected的表达式,ToProjected正在编译为IL,并且在运行时mongo驱动程序无法检索ID = lib.ID的知识(至少不是这样简单的方法)以及表达式)。这里特别是MethodCallExpression。第二个表达式的可视化是:
.Lambda #Lambda1<System.Func`2[ConsoleApp1.Program+MyOriginalClass,ConsoleApp1.Program+MyProjectedClass]>(ConsoleApp1.Program+MyOriginalClass $lib)
{
.Call ConsoleApp1.Program.ToProjected($lib)
}
ToProject可以重写为:
Expression<Func<MyOriginalClass, MyProjectedClass>> ToProjected()
{
return lib => new MyProjectedClass { ID = lib.ID };
}
并用作:
var data2 = GetData(ToProjected());