使用AutoMapper将关系dto模型转换为多态域模型

时间:2019-01-22 20:01:59

标签: .net-core automapper

在我的数据库中,我有一个包含2个明细表的基表,该基表中的每个记录将只有一个明细记录。我正在尝试将这3个表映射到从共享基本域模型继承的两个域模型。在EntityFramework中,这通常称为按类型继承表,但在EntityFrameworkCore中未实现。

我的dto模型看起来像

public class SourceBase
{
   public int Id {get;set;}
   public string Value {get;set;}
   public SourceA A {get;set;}
   public SourceB B {get;set;}
}

public class SourceA
{
    public string ValueA {get;set;}
}

public class SourceB
{
    public string ValueB {get;set;}
}

我想要的域模型如下

public class TargetBase
{
    public int Id {get;set;}
    public string Value {get;set;}
}

public class TargetA : TargetBase 
{
    public string ValueA {get;set;}
}

public class TargetB : TargetBase
{
    public string ValueB {get;set;}
}

我如何设置映射以完成此操作?


我最成功的尝试是:

CreateMap<SourceBase, TargetBase>().ConvertUsing<CustomTypeConverter>();
CreateMap<SourceA, TargetA>();
CreateMap<SourceB, TargetB>();

使用CustomTypeConverter:

public class CustomTypeConverter : ITypeConverter<SourceBase, TargetBase>
{
    public TargetBase Convert(SourceBase source, TargetBase destination, ResolutionContext context)
   {
       if (source.A == null)
       {
           return context.Mapper.Map<SourceB, TargetB>(source.B);
       }
       else if (source.B == null)
       {
           return context.Mapper.Map<SourceA, TargetA>(source.A);
       }
       return null;
    }
}

可以正确地给我TargetA或TargetB类型,但是没有TargetBase值被映射。

3 个答案:

答案 0 :(得分:1)

为此找到的最简单的方法是使用ConstructUsingAfterMap以避免递归:

public class Program
{
    public static void Main()
    {
        AutoMapper.Mapper.Reset();
        AutoMapper.Mapper.Initialize(cfg =>
        {
            cfg.CreateMap<SourceBase, TargetBase>().ConstructUsing(x => Convert(x)).AfterMap(Transform);
            cfg.CreateMap<SourceA, TargetA>();
            cfg.CreateMap<SourceB, TargetB>();
        });

        var src = new SourceBase
        {
            Id = 3,
            Value = "Asd",
            A = new SourceA
            {
                ValueA = "Qwe"
            }
        };
        var a = AutoMapper.Mapper.Map<SourceBase, TargetBase>(src);
        a.Dump(); // Code for LinqPad to show the result
    }

    public static TargetBase Convert(SourceBase source)
    {
        if (source.A == null)
        {
            return new TargetB();
        }
        else if (source.B == null)
        {
            return new TargetA();
        }

        return null;
    }

    public static void Transform(SourceBase source, TargetBase target)
    {
        if (source.A == null)
        {
            AutoMapper.Mapper.Map<SourceB, TargetB>(source.B, (TargetB)target);
        }
        else if (source.B == null)
        {
            AutoMapper.Mapper.Map<SourceA, TargetA>(source.A, (TargetA)target);
        }
    }
}

public class SourceBase
{
   public int Id {get;set;}
   public string Value {get;set;}
   public SourceA A {get;set;}
   public SourceB B {get;set;}
}

public class SourceA
{
    public string ValueA {get;set;}
}

public class SourceB
{
    public string ValueB {get;set;}
}

public class TargetBase
{
    public int Id {get;set;}
    public string Value {get;set;}
}

public class TargetA : TargetBase 
{
    public string ValueA {get;set;}
}

public class TargetB : TargetBase
{
    public string ValueB {get;set;}
}

您显然可以将转换方法放入自己的类中

答案 1 :(得分:0)

我敢肯定还有其他方法,但是它几乎可以像您尝试的那样工作。

ActiveSheet.PageSetup.BlackAndWhite = False
ActiveWindow.SelectedSheets.PrintOut Copies:=1, ActivePrinter:="\\printer\printer1", Collate:=True, _
        IgnorePrintAreas:=False
    Sheets("REPORT").Select

如果您遵循the naming convention或使用an extension method,则不需要MapFroms。

答案 2 :(得分:0)

与卢西安的答案非常相似。我更喜欢这样做,因为它可以明确表明它选择了特定的派生类映射,但实际上是相同的答案。

<input name="IsEmptyString" type="hidden"/>