C# Mongo 数据库驱动程序 - 方法调用的表达式不起作用
C# Mongo DB driver - expression with method call not working
我正在尝试查询一些数据并通过发送表达式(C# mongo 驱动程序版本 2.7.3)投影到属性较少的 class。
我试图理解为什么特定表达式失败。
失败极大地限制了用户编写通用投影,并迫使他在每次调用中都以内联方式编写投影。
这是一个简化的例子:
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};
}
第一次(成功)使用是一个表达式,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());
我正在尝试查询一些数据并通过发送表达式(C# mongo 驱动程序版本 2.7.3)投影到属性较少的 class。 我试图理解为什么特定表达式失败。 失败极大地限制了用户编写通用投影,并迫使他在每次调用中都以内联方式编写投影。 这是一个简化的例子:
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};
}
第一次(成功)使用是一个表达式,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());