如何使用Mapster映射自参考?

时间:2020-06-11 12:18:13

标签: c# asp.net .net mapster

我有一个列表,其中包含自参考项。 例如:
型号

public class Stock{
  public int StockId { get; set; }
  public int? ParentStockId { get; set; }
  public int Level { get; set; }
  public string Name { get; set; }
}

ViewModel

public class StockViewModel {
  public int Level { get; set; }
  public string Name { get; set; }
  public IEnumerable<StockViewModel> SubStock { get; set; }
}

样本数据

var stocks = new List<Stock> {
    new Stock{ StockId = 1, Level = 10, Name = "Root1" },
    new Stock{ StockId = 2, Level = 10, Name = "Root2" },
    new Stock{ StockId = 3, ParentStockId = 1, Level = 20, Name = "Area1" },
    new Stock{ StockId = 4, ParentStockId = 2, Level = 20, Name = "Area2" },
    new Stock{ StockId = 5, ParentStockId = 3, Level = 30, Name = "Box11" },
    new Stock{ StockId = 6, ParentStockId = 3, Level = 30, Name = "Box12" },
    new Stock{ StockId = 7, ParentStockId = 4, Level = 30, Name = "Box21" }
};

我使用类似的代码来实现所需的结果。但我确定这是错误的。我必须在每个新请求之前进行配置。

        var mapper = new Mapper(); 
        TypeAdapterConfig<Stock, StockViewModel>
            .NewConfig()
            .Map(dst => dst.SubStock, src => stocks.Where(x => x.ParentStockId == src.StockId).ToList());
        var viewStocks = mapper.Map<IEnumerable<Stock>, IEnumerable<StockViewModel>>(stocks.Where(x => x.ParentStockId == null));
        // Sample output
        foreach (var stock in viewStocks){
            Console.WriteLine(stock.Level.ToString() + " " + stock.Name);
            if (stock.SubStock != null) 
                foreach (var stock1 in stock.SubStock){
                    Console.WriteLine("  " + stock1.Level.ToString() + " " + stock1.Name);
                    if (stock1.SubStock != null) 
                        foreach (var stock2 in stock1.SubStock){
                            Console.WriteLine("    " + stock2.Level.ToString() + " " + stock2.Name);
                        }
                }
        }

Fiddle
如何映射viewStocks层级? 与

相同
10 Root1
  20 Area1
    30 Box11
    30 Box12
10 Root2
  20 Area2
    30 Box21

2 个答案:

答案 0 :(得分:1)

您无需为每个新请求配置Mapster配置。根据{{​​3}}:

配置应仅设置一次,并重新用于映射。 因此,我们不应将配置和映射保留在同一位置 位置。配置应保留在诸如Main函数或Global.asax.csStartup.cs之类的入口点。

因此您可以将该映射移至入口点:

TypeAdapterConfig<Stock, StockViewModel>
    .NewConfig()
    .Map(dst => dst.SubStock, src => stocks.Where(x => x.ParentStockId == src.StockId).ToList());

此外,为了分隔您的配置和映射实例而不是

 var viewStocks = mapper.Map<IEnumerable<Stock>, IEnumerable<StockViewModel>>(stocks.Where(x => x.ParentStockId == null));

我更喜欢按以下方式使用Adapt

var socksWithoutParent = stocks.Where(x => x.ParentStockId == null);
var viewStocks = socksWithoutParent.Adapt<List<StockViewModel>>();

完整示例https://github.com/MapsterMapper/Mapster/wiki/Config-location,它将为您提供相同的输出:

10 Root1
  20 Area1
    30 Box11
    30 Box12
10 Root2
  20 Area2
    30 Box21

答案 1 :(得分:0)

为了正确地分离配置和映射,我用stocks传递参数

var viewStocks = stocks.Where(x => x.ParentStockId == null)
            .BuildAdapter()
            .AddParameters("paramKey", stocks)
            .AdaptToType<List<StockViewModel>>();

和我的配置

TypeAdapterConfig<Stock, StockViewModel>
            .NewConfig()
            .Map(dst => dst.SubStock, 
                 src => ((IEnumerable<Stock>)MapContext.Current.Parameters["paramKey"])
                 .Where(x => x.ParentStockId == src.StockId)
                 .BuildAdapter()
                 .AddParameters("paramKey", MapContext.Current.Parameters["paramKey"])
                 .AdaptToType<List<StockViewModel>>());

full example

现在在我的配置中,我不需要了解stocks