首页 > 解决方案 > MongoDb C# Driver with Group and Project using Aggregate() 查询给出异常

问题描述

我正在开发MongoDb用作数据库和.Net Core 3.0框架的应用程序。为了从数据库中获取数据,我创建了一个DbContext类并Aggregation()使用MongoDb. 我无法通过适当的投影。以下是代码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, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] 并且与成员类型 System.Object 不匹配。(参数'序列化器')"

标签: c#mongodblinqaggregation-framework

解决方案


我认为您尝试做的事情不可行。作为替代方案,我可以建议公开.Aggregate()dbContext 并从 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();
        }
    }
}

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

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

然后看看这个入门模板项目,看看它在使用中。


推荐阅读