Драйвер C # Mongo DB - выражение с вызовом метода не работает - PullRequest
1 голос
/ 15 апреля 2019

Я пытаюсь запросить некоторые данные и проецировать их на класс с меньшим количеством свойств, отправив выражение (драйвер 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 Ответ

2 голосов
/ 15 апреля 2019

Первое (успешное) использование - это выражение, которое драйвер монго может просмотреть во время выполнения, чтобы узнать, что 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());
...