C#Mongo DB驱动程序-带有方法调用的表达式不起作用

时间:2019-04-15 13:53:11

标签: c# database mongodb linq-expressions mongodb-csharp-2.0

我试图通过发送表达式(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};
}

1 个答案:

答案 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());