【问题标题】:MongoDb C# Driver with Group and Project using Aggregate() query giving exceptionMongoDb C# Driver with Group and Project using Aggregate() 查询给出异常
【发布时间】:2019-11-26 08:41:05
【问题描述】:

我正在开发使用MongoDb 作为数据库和.Net Core 3.0 作为框架的应用程序。为了从数据库中获取数据,我创建了一个DbContext 类并使用MongoDbAggregation() 功能。我无法通过适当的投影。以下是DbContext.cs的代码

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using Microsoft.Extensions.Options;
    using MongoDB.Driver;

    namespace Test.DbContext
    {
        /// <summary>
        /// Standard CRUD Operations with MongoDb  
        /// </summary>
        public class MongoDbContext   
        {
            #region Properties
            private readonly IMongoClient _mongoDbClient = null;

            private readonly IMongoDatabase _mongoDb = null;
            #endregion

            #region Constructor
            public MongoDbContext(IOptions<MongoSetting> mongoConfigs)
            {
                _mongoDbClient = new MongoClient(mongoConfigs.Value.ConnectionString);
                _mongoDb = _mongoDbClient.GetDatabase(mongoConfigs.Value.DatabaseName);
            }
            #endregion

            #region Grouping
            public IList<TProjection> GroupBy<TDocument, TGroupKey, TProjection> 
            (FilterDefinition<TDocument> filter, 
             Expression<Func<TDocument, TGroupKey>> selector, 
             Expression<Func<IGrouping<TGroupKey, TDocument>, TProjection>> projection){
                   return _mongoDb.GetCollection<TDocument>("collectionName").Aggregate().Match(filter).Group(selector, projection).ToList();
               }   
            #endregion
        }
    }

要调用函数GroupBy(),我必须传递过滤器、选择器和投影,但我无法构建适当的表达式。以下是数据模型和调用函数:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.Extensions.Options;
using MongoDB.Driver;

namespace Test 
{
    [BsonIgnoreExtraElements]
    public class Employee   
    {
        [BsonId]
        [BsonElement("_id")]
        [BsonRepresentation(BsonType.ObjectId)]
        public ObjectId Id { get; set; }

        [BsonElement("type")]
        [JsonProperty("type")]
        public string Type { get; set; }

        [BsonElement("id")]
        public string CustomerId { get; set; }

        [BsonElement("name")]
        public string CustomerName { get; set; }
    }
}

我将客户存储库中的 dbContext 称为:

using System;
using System.Linq.Expressions;
using MongoDB.Driver;

namespace Test.Repositories
{
    public class CustomerRepository : ICustomerRepository
    {
        #region Properties
        private readonly IMongoDbContext _dbContext = null;
        #endregion

        #region Constructor
        public CustomerRepository(IMongoDbContext dbContext)
        {
            _dbContext = dbContext;
        }
        #endregion

        #region Methods
        public EmployeeCollection GetSpecificData()
        {

            Expression<Func<Employee, dynamic>> filter = x => x.Employee.CustomerId == "11";
            Expression<Func<Employee, dynamic>> selector = x => new { typeName = x.Employee.Type };
            Expression<Func<IGrouping<dynamic, Employee>, dynamic>> projection = x => new
            {
                Key = x.Key,
                count = x.Count(),
                avgValue = x.Average(x => Convert.ToInt32(x.Employee.CustomerId))
            };


            var result = _dbContext.GroupBy<Employee, dynamic, dynamic>(filter, selector, projection);

            // Giving exception
            // "Value type of serializer is <>f__AnonymousType0`1[[System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, 
            //PublicKeyToken=7cec85d7bea7798e]] and does not match member type System.Object. (Parameter 'serializer')"
        }
        #endregion
    }
}

例外:

"序列化器的值类型是f__AnonymousType0`1[[System.String, System.Private.CoreLib,版本=4.0.0.0,文化=中性, PublicKeyToken=7cec85d7bea7798e]] 与成员类型不匹配 系统对象。 (参数'序列化器')"

【问题讨论】:

    标签: c# mongodb linq aggregation-framework


    【解决方案1】:

    我认为您尝试做的事情不可行。作为替代方案,我可以建议从 dbContext 中公开 .Aggregate() 并从如下所示的 repo 中查询。

    员工类

    using MongoDB.Bson;
    using MongoDB.Bson.Serialization.Attributes;
    
    namespace Test
    {
        [BsonIgnoreExtraElements]
        public class Employee
        {
            [BsonId]
            [BsonElement("_id")]
            [BsonRepresentation(BsonType.ObjectId)]
            public ObjectId Id { get; set; }
    
            [BsonElement("type")]
            public string Type { get; set; }
    
            [BsonElement("id")]
            [BsonRepresentation(BsonType.String)] // to avoid manual conversion
            public int CustomerId { get; set; }
    
            [BsonElement("name")]
            public string CustomerName { get; set; }
        }
    }
    

    数据库上下文

    using MongoDB.Driver;
    using System.Linq;
    
    namespace Test.DbContext
    {
        public class MongoDbContext
        {
            private readonly IMongoClient _mongoDbClient = null;
    
            private readonly IMongoDatabase _mongoDb = null;
    
            public MongoDbContext()
            {
                _mongoDbClient = new MongoClient("mongodb://localhost");
                _mongoDb = _mongoDbClient.GetDatabase("test");
            }
    
            public IAggregateFluent<TDocument> Aggregate<TDocument>() =>
                _mongoDb.GetCollection<TDocument>(nameof(TDocument)).Aggregate();
    
        }
    }
    

    存储库

    using MongoDB.Driver;
    using System.Collections.Generic;
    using System.Linq;
    using Test.DbContext;
    
    namespace Test.Repositories
    {
        public class CustomerRepository
        {
            private static readonly MongoDbContext _dbContext = new MongoDbContext();
    
            public List<dynamic> GetSpecificData()
            {
                var result = _dbContext.Aggregate<Employee>()
                                 .Match(e => e.CustomerId == 11)
                                 .Group(e => e.Type, g => new { Key = g.Key, Count = g.Count(), Average = g.Average(e => e.CustomerId) })
                                 .ToList();
    
                return result.Cast<dynamic>().ToList();
            }
        }
    }
    

    我还建议您不要将匿名类型转换为动态。因此,创建并使用另一个类(用于组结果)以保持类型安全。

    我还可以建议您查看我编写的 library,它消除了编写自己的 dbContext 的需要。

    然后看看this starter 模板项目,看看它在使用中。

    【讨论】:

      猜你喜欢
      • 2022-06-15
      • 2020-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-29
      • 1970-01-01
      相关资源
      最近更新 更多