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

Mapster如何编写带动态参数的表达式?EF Core实体映射遇问题

问题

在项目中使用Mapster将EF Core实体映射到DTO。原本在请求处理器中配置映射可正常工作,但根据Mapster建议,为避免性能问题,TypeAdapterConfig应仅在程序入口处定义一次。

原工作代码:

// original code
TypeAdapterConfig<ProductEntity, ProductDto>.NewConfig()
            .Map(d => d.Available, ProductExpression.AvailableForStoreId(request.ForStoreId));

public static Expression<Func<ProductEntity, bool>> AvailableForStoreId(DefaultIdType storeId)
{
    return s => s.ProductGroups.Any(gp => gp.storeRelProductGroup.Any(r => r.StoreId == storeId));
}

尝试改用MapContext传递动态参数并将配置移至入口时,启动项目立即抛出空引用错误——原因是MapContext.Current在TypeAdapterConfig定义时为空,表达式被提前调用:

// Parameters approach 
TypeAdapterConfig<ProductEntity, ProductDto>.NewConfig()
            .Map(d => d.HasPricing, ProductExpression.AvailableForStoreId((int)MapContext.Current.Parameters["storeId"]));

需要解决:如何保留AvailableForStoreId的表达式逻辑,同时按请求提供动态参数storeId,且符合Mapster仅在入口配置一次的要求?

解决方案

方法1:直接在映射配置中使用上下文参数

在入口配置时,通过Mapster提供的上下文参数ctx直接引用动态值,避免提前调用表达式生成方法:

// 程序入口处的映射配置
TypeAdapterConfig<ProductEntity, ProductDto>.NewConfig()
    .Map(d => d.HasPricing, (src, dest, ctx) => 
        src.ProductGroups.Any(gp => gp.storeRelProductGroup.Any(r => r.StoreId == (DefaultIdType)ctx.Parameters["storeId"])));

请求处理时传递参数:

var dto = productEntity.Adapt<ProductDto>(new MapContext { Parameters = { ["storeId"] = request.ForStoreId } });

方法2:修改表达式生成方法支持延迟参数解析

调整AvailableForStoreId方法,让它接受一个代表storeId的表达式参数,实现延迟解析上下文值:

// 修改后的表达式生成方法
public static Expression<Func<ProductEntity, bool>> AvailableForStoreId(Expression<Func<DefaultIdType>> storeIdExpr)
{
    var productParam = Expression.Parameter(typeof(ProductEntity), "s");
    var storeIdValue = storeIdExpr.Body;

    // 拼接Any嵌套的表达式逻辑
    var storeRelCheck = Expression.Lambda<Func<StoreRelProductGroup, bool>>(
        Expression.Equal(
            Expression.Property(Expression.Parameter(typeof(StoreRelProductGroup), "r"), nameof(StoreRelProductGroup.StoreId)),
            storeIdValue
        ),
        Expression.Parameter(typeof(StoreRelProductGroup), "r")
    );

    var groupCheck = Expression.Lambda<Func<ProductGroup, bool>>(
        Expression.Call(
            typeof(Enumerable), "Any", new[] { typeof(StoreRelProductGroup) },
            Expression.Property(Expression.Parameter(typeof(ProductGroup), "gp"), nameof(ProductGroup.storeRelProductGroup)),
            storeRelCheck
        ),
        Expression.Parameter(typeof(ProductGroup), "gp")
    );

    var finalExpr = Expression.Lambda<Func<ProductEntity, bool>>(
        Expression.Call(
            typeof(Enumerable), "Any", new[] { typeof(ProductGroup) },
            Expression.Property(productParam, nameof(ProductEntity.ProductGroups)),
            groupCheck
        ),
        productParam
    );

    return finalExpr;
}

入口配置时传入上下文参数的表达式:

// 程序入口处的映射配置
TypeAdapterConfig<ProductEntity, ProductDto>.NewConfig()
    .Map(d => d.HasPricing, AvailableForStoreId(() => (DefaultIdType)MapContext.Current.Parameters["storeId"]));

请求处理时传递参数:

var dto = productEntity.Adapt<ProductDto>(new MapContext { Parameters = { ["storeId"] = request.ForStoreId } });

方法3:简化的上下文参数传递(推荐)

使用Mapster的简化语法,在调用时直接注入参数:

// 入口配置
TypeAdapterConfig<ProductEntity, ProductDto>.NewConfig()
    .Map(d => d.HasPricing, (src, ctx) => 
        src.ProductGroups.Any(gp => gp.storeRelProductGroup.Any(r => r.StoreId == (DefaultIdType)ctx.Parameters["storeId"])));

调用映射时:

var dto = productEntity.Adapt<ProductDto>(ctx => ctx.Parameters["storeId"] = request.ForStoreId);

内容的提问来源于stack exchange,提问作者C TC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 08:17:55