2015-06-12 69 views
5

我試圖根據多場關鍵的集合中選擇最新的記錄爲每個組,使用流暢聚合接口:蒙戈C#驅動程序2.0彙總羣異常

 var matches = await Collection.Aggregate() 
      .Match(x => x.EffectiveDate >= minEffectiveDate) 
      .SortByDescending(x => x.LastUpdate) 
      .Group(key => new { key.EffectiveDate, key.ProductOid, key.InstrumentParentOid, key.ComponentOid, key.EventSummary }, g => g.First()) 
      .ToListAsync(); 

但是,我得到的以下例外:

System.InvalidCastException occurred 
    HResult=-2147467262 
    Message=Unable to cast object of type 'MongoDB.Driver.Linq.Expressions.SerializationExpression' to type 'System.Linq.Expressions.MethodCallExpression'. 
    Source=MongoDB.Driver 
    StackTrace: 
    at MongoDB.Driver.Linq.Processors.GroupSerializationInfoBinder.GetBodyFromSelector(MethodCallExpression node) 
    at MongoDB.Driver.Linq.Processors.GroupSerializationInfoBinder.GetAggregationArgument(MethodCallExpression node) 
    at MongoDB.Driver.Linq.Processors.GroupSerializationInfoBinder.VisitMethodCall(MethodCallExpression node) 
    at MongoDB.Driver.Linq.Translators.AggregateProjectionTranslator.BindSerializationInfo(SerializationInfoBinder binder, LambdaExpression node, IBsonSerializer parameterSerializer) 
    at MongoDB.Driver.Linq.Translators.AggregateProjectionTranslator.TranslateGroup[TKey,TDocument,TResult](Expression`1 idProjector, Expression`1 groupProjector, IBsonSerializer`1 parameterSerializer, IBsonSerializerRegistry serializerRegistry) 
    at MongoDB.Driver.IAggregateFluentExtensions.GroupExpressionProjection`3.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry) 
    at MongoDB.Driver.AggregateFluent`2.<>c__DisplayClass1`1.<Group>b__0(IBsonSerializer`1 s, IBsonSerializerRegistry sr) 
    at MongoDB.Driver.DelegatedPipelineStageDefinition`2.Render(IBsonSerializer`1 inputSerializer, IBsonSerializerRegistry serializerRegistry) 
    at MongoDB.Driver.PipelineStageDefinition`2.MongoDB.Driver.IPipelineStageDefinition.Render(IBsonSerializer inputSerializer, IBsonSerializerRegistry serializerRegistry) 
    at MongoDB.Driver.PipelineStagePipelineDefinition`2.Render(IBsonSerializer`1 inputSerializer, IBsonSerializerRegistry serializerRegistry) 
    at MongoDB.Driver.MongoCollectionImpl`1.<AggregateAsync>d__7`1.MoveNext() 
--- End of stack trace from previous location where exception was thrown --- 
    at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
    at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
    at MongoDB.Driver.IAsyncCursorSourceExtensions.<ToListAsync>d__14`1.MoveNext() 

好的。因此,出於某種原因它不喜歡IEnumerable擴展方法。所以我儘量抽出LINQ擴展方法:

 var matches = await Collection.Aggregate() 
      .Match(x => x.EffectiveDate >= minEffectiveDate) 
      .SortByDescending(x => x.LastUpdate) 
      .Group(key => new { key.EffectiveDate, key.ProductOid, key.InstrumentParentOid, key.ComponentOid, key.EventSummary }, g => g) 
      .ToListAsync(); 
     return matches.Select(x => x.First()); 

但是:

System.InvalidCastException occurred 
    HResult=-2147467262 
    Message=Unable to cast object of type 'MongoDB.Bson.Serialization.Serializers.ArraySerializer`1[SPMO.Providers.Audit.Messages.ProductAdjustmentAuditDataDb]' to type 'MongoDB.Bson.Serialization.IBsonSerializer`1[System.Linq.IGrouping`2[<>f__AnonymousType0`5[System.Nullable`1[System.DateTime],System.Nullable`1[System.Int32],System.Nullable`1[System.Int32],System.Nullable`1[System.Int32],System.String],SPMO.Providers.Audit.Messages.ProductAdjustmentAuditDataDb]]'. 
    Source=MongoDB.Driver 
    StackTrace: 
     at MongoDB.Driver.Linq.Translators.AggregateProjectionTranslator.TranslateGroup[TKey,TDocument,TResult](Expression`1 idProjector, Expression`1 groupProjector, IBsonSerializer`1 parameterSerializer, IBsonSerializerRegistry serializerRegistry) 
     at MongoDB.Driver.IAggregateFluentExtensions.GroupExpressionProjection`3.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry) 
     at MongoDB.Driver.AggregateFluent`2.<>c__DisplayClass1`1.<Group>b__0(IBsonSerializer`1 s, IBsonSerializerRegistry sr) 
     at MongoDB.Driver.DelegatedPipelineStageDefinition`2.Render(IBsonSerializer`1 inputSerializer, IBsonSerializerRegistry serializerRegistry) 
     at MongoDB.Driver.PipelineStageDefinition`2.MongoDB.Driver.IPipelineStageDefinition.Render(IBsonSerializer inputSerializer, IBsonSerializerRegistry serializerRegistry) 
     at MongoDB.Driver.PipelineStagePipelineDefinition`2.Render(IBsonSerializer`1 inputSerializer, IBsonSerializerRegistry serializerRegistry) 
     at MongoDB.Driver.MongoCollectionImpl`1.<AggregateAsync>d__7`1.MoveNext() 
    --- End of stack trace from previous location where exception was thrown --- 
     at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
     at MongoDB.Driver.IAsyncCursorSourceExtensions.<ToListAsync>d__14`1.MoveNext() 
    --- End of stack trace from previous location where exception was thrown --- 
     at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) 
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) 
     at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() 

我的B計劃就是忘掉總結,做一個簡單的查找(),然後在香草做的GroupBy() LINQ,但我想在數據庫上工作,因爲它會更有效率。

+1

您是否嘗試過在地方的匿名類型的命名類型的集合? – lobsterism

+0

感謝您的建議。我在這裏交叉發佈到MongoDB C#Google用戶組 - https://groups.google.com/forum/#!topic/mongodb-csharp/nmSYSiyBzOo - 它看起來像在不支持整個對象上的.First() ;你必須定義一個投影。我現在正和我的計劃B一起進行。 – ultra909

回答

4

我遇到了同樣的問題。我的解決方法是不同的:而不是使用LINQ GroupBy()客戶端,我做了兩個服務器調用。

  1. 獲取我希望檢索的文檔的MongoDB ObjectIds,即我希望Group()將作爲POCO發佈給我的文檔。
  2. 做一個find()方法與載有()反對的ObjectID的從第1步

代碼演示此

public static class WidgetWorker 
{ 
    public static void Main() 
    { 
     //setup 
     var widgetCollection = new MongoClient("mongodb://localhost:27017") 
      .GetDatabase("WidgetDatabase") 
      .GetCollection<Widget>("Widget"); 
     widgetCollection.DeleteManyAsync(x => true).Wait(); //remove all existing rows 

     //create widgets and add to DB; 2 SKUs, each with multiple revisions 
     var widgetA1 = new Widget() { SKU = "aaaa", Revision = 1M, Cost = 10 }; 
     var widgetA2 = new Widget() { SKU = "aaaa", Revision = 2.1M, Cost = 20 }; 
     var widgetA3 = new Widget() { SKU = "aaaa", Revision = 2.2M, Cost = 30 }; 
     var widgetB1 = new Widget() { SKU = "bbbb", Revision = 1M, Cost = 40 }; 
     var widgetB2 = new Widget() { SKU = "bbbb", Revision = 1.1M, Cost = 50 }; 
     widgetCollection.InsertManyAsync(new[] { widgetA1, widgetA2, widgetA3, widgetB1, widgetB2 }).Wait(); 

     //get the ObjectId of the most Recent revision of each SKU 
     var r = widgetCollection 
      .Aggregate() 
      .SortByDescending(x => x.Revision) 
      .Group(x => x.SKU, g => new { Id = g.First().Id }) 
      .ToListAsync() 
      .Result; 

     //get the Widget objects for the list of ids just collected 
     var ids = r.Select(x => x.Id).ToArray(); 
     var widgets = widgetCollection 
      .Find(x => ids.Contains(x.Id)) 
      .ToListAsync() 
      .Result; 

     //check results 
     Debug.Assert(widgets.Count() == 2); 
     Debug.Assert(widgets.Single(x => x.SKU == "aaaa").Revision == 2.2M); 
     Debug.Assert(widgets.Single(x => x.SKU == "bbbb").Revision == 1.1M); 
    } 
} 

public class Widget 
{ 
    [BsonId] 
    public ObjectId Id { get; set; } 
    public string SKU { get; set; } 
    public decimal Revision { get; set; } 
    public decimal Cost { get; set; } 
} 
+0

對於大型結果集和/或大型對象,這幾乎肯定會是一種更高效的方法。謝謝。 – ultra909