You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用LINQ查询MongoDB时RuleActions序列化错误求助

问题分析

错误Serializer for ABSRotas.Routing.Entities.Models.Integration does not have a member named RuleActions的核心原因:

  • Integration实体中,RuleActions是表达式体属性(public IReadOnlyList<RuleAction> RuleActions => _ruleActions;),MongoDB LINQ驱动无法将其识别为可查询的实体成员,驱动的元数据解析逻辑不兼容这种语法糖形式的属性。
  • 映射代码仅注册了私有字段_ruleActions的映射,但未将公共的RuleActions属性与该字段关联,导致驱动解析LINQ表达式i.RuleActions.Count时,找不到对应的序列化成员。

当改为List时,驱动默认识别了常规集合类型的属性,错误消失,但破坏了实体的封装性(对外暴露可修改的集合)。


解决方案

步骤1:调整实体属性定义(保持封装性)

将表达式体属性改为常规只读属性,确保驱动能识别为实体成员,同时保持集合的只读性:

using ABSCard.Extensions;
using ABSRotas.Common.Domain;

namespace ABSRotas.Routing.Entities.Models
{
    public class Integration : Entity, IAggregateRoot
    {
        public DateTime CreatedOn { get; private set; }
        public Guid CreatedBy { get; private set; }
        public bool Status { get; private set; }
        public string Name { get; private set; }

        private List<RuleAction> _ruleActions;
        // 改为常规只读属性
        public IReadOnlyList<RuleAction> RuleActions { get; }

        protected Integration()
        {
            _ruleActions = new List<RuleAction>();
            RuleActions = _ruleActions.AsReadOnly();
        }

        public Integration(Guid createdBy, bool status, string name)
        {
            CreatedOn = DateTime.Now.ToBrazilianTime();
            CreatedBy = createdBy;
            Status = status;
            Name = name;
            _ruleActions = new List<RuleAction>();
            RuleActions = _ruleActions.AsReadOnly();

            Validate();
        }
    }
}

使用AsReadOnly()返回只读包装器,既保证外部无法修改集合,又让驱动能识别为合法的属性成员。

步骤2:完善MongoDB映射配置

在IntegrationMapping中,将RuleActions属性与私有字段_ruleActions关联,并指定集合类型的序列化器:

using ABSRotas.Common.DataAccess.DatabaseFacades.MongoDb;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;

namespace ABSRotas.Routing.Entities.Models
{
    public class IntegrationMapping : IMongoMappings
    {
        public void Register()
        {
            BsonClassMap.RegisterClassMap<Integration>(cm =>
            {
                cm.AutoMap();
                // 映射私有字段到数据库的RuleActions元素
                cm.MapField("_ruleActions").SetElementName("RuleActions");
                // 映射公共属性到同一数据库元素,关联到私有字段
                cm.MapProperty(i => i.RuleActions)
                    .SetElementName("RuleActions")
                    .MapToField("_ruleActions")
                    // 指定用List<RuleAction>的序列化器处理IReadOnlyList类型
                    .SetSerializer(new EnumerableInterfaceImplementerSerializer<IReadOnlyList<RuleAction>, List<RuleAction>>());
                cm.MapCreator(i => new Integration(i.CreatedBy, i.Status, i.Name));
            });
        }
    }
}

EnumerableInterfaceImplementerSerializer用于告诉驱动,处理IReadOnlyList<RuleAction>时使用List<RuleAction>的序列化逻辑,避免类型不兼容问题。

步骤3:优化查询方法(可选但推荐)

当前Query方法会把所有数据加载到内存再转为IQueryable,存在性能问题,改为直接返回MongoDB的延迟查询IQueryable,让查询在服务器端执行:

public IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> queryExpression)
    where TEntity : Entity, IAggregateRoot
{
    var database = ConnectToDatabase();
    var collection = database.GetCollection<TEntity>(GetCollectionName(typeof(TEntity)));
    // 直接返回服务器端可执行的IQueryable
    return collection.AsQueryable().Where(queryExpression);
}

后续LINQ操作会尽可能转为MongoDB查询语句,而非在内存中过滤数据。


验证

完成上述修改后,重新运行LINQ查询,驱动就能正确解析i.RuleActions.Count表达式,同时保持实体的封装性和查询的性能。

内容的提问来源于stack exchange,提问作者Kelvyn Sinhorini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 18:45:41