使用mapstruct将平面对象映射到组合对象

时间:2017-01-15 01:22:18

标签: mapstruct

当第二个映射函数向Mapstruct明确给出映射信息时,为什么不自动生成映射代码?

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;

namespace TestApp
{
    internal class Program
    {
        public static void Main(string[] p)
        {
            DeleteData();
            CreateRecipes();
            using (var db = new DbModel())
            {
                var recipe1 = (from x in db.recipeDS.OfType<ScrubRecipe>()
                                  .Include(x => x.steps)
                               select x).FirstOrDefault();

                //var recipe2 = (from x in db.recipeDS.OfType<ScrubRecipe>()
                //                  .Include(x => x.steps.OfType<ScrubStep>().Select(y => y.outputList))
                //               select x).FirstOrDefault();
            }
        }

        private static void DeleteData()
        {
            using (var db = new DbModel())
            {
                db.Database.ExecuteSqlCommand("DELETE FROM [StepOutputs]");
                db.Database.ExecuteSqlCommand("DELETE FROM [RecipeSteps]");
                db.Database.ExecuteSqlCommand("DELETE FROM [Recipes]");
            }
        }

        private static void CreateRecipes()
        {
            // Output to be saved.
            var stepOutput = new StepOutput();

            // Create a Recipe
            var scrubRecipe = new ScrubRecipe
            { steps = { new ScrubStep { outputList = { stepOutput } } } };

            // Create a Recipe
            var coatRecipe = new CoatRecipe
            { steps = { new CoatStep { outputList = { stepOutput } } } };

            // Save the Recipes
            using (var db = new DbModel())
            {
                db.scrubRecipeDS.AddOrUpdate(scrubRecipe);
                db.coatRecipeDS.AddOrUpdate(coatRecipe);
                db.SaveChanges();
            }
        }
    }

    public abstract class Recipe
    {
        [Key]
        public int ID { get; set; }

        public List<RecipeStep> steps { get; set; } = new List<RecipeStep>();
    }

    public class CoatRecipe : Recipe { }

    public class ScrubRecipe : Recipe { }

    public abstract class RecipeStep
    {
        [Key]
        public int ID { get; set; }

        public virtual Recipe recipe { get; set; }
    }

    public class CoatStep : RecipeStep
    {
        public List<StepOutput> outputList { get; set; } = new List<StepOutput>();
    }

    public class StepOutput
    {
        [Key]
        public int ID { get; set; }

        public virtual RecipeStep recipeStep { get; set; }
    }

    public class ScrubStep : CoatStep
    {
        public int value { get; set; }
    }

    public class DbModel : DbContext
    {
        public DbModel()
            : base("name=DbModelConn")
        {
            Database.SetInitializer(new CreateDatabaseIfNotExists<DbModel>());
        }

        public virtual DbSet<Recipe> recipeDS { get; set; }
        public DbSet<RecipeStep> recipeStepDS { get; set; }
        public DbSet<StepOutput> stepOutputDS { get; set; }

        public virtual DbSet<ScrubRecipe> scrubRecipeDS { get; set; }
        public virtual DbSet<ScrubStep> scrubRecipeStepDS { get; set; }
        public virtual DbSet<CoatRecipe> coatRecipeDS { get; set; }
        public virtual DbSet<CoatStep> coatRecipeStepsDS { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<ScrubStep>()
                .HasMany(x => x.outputList)
                .WithRequired(x => (ScrubStep)x.recipeStep);



        }
    }
}

Flat          Composed
----          --------
- String a    - String a
              - Sub
- String b      - String b
- String c      - String c

清晰用法:

@Mapper(uses = SubToFlatMapper.class)
public interface ComposedToFlatMapper {

    Flat map(Composed c); // Unmapped target properties: "b, c".
                          // Not OK because Sub mapping is defined in 
                          //    SubToFlatMapper and is used here :(
}

@Mapper
public interface SubToFlatMapper {

    Flat map(Sub s); // Unmapped target properties: "a".
                     //    (OK because 'a' is not in Sub)
}

Composed composed = new Composed(); Sub sub = new Sub(); composed.setA("A"); composed.setSub(sub); sub.setB("B"); sub.setC("C"); Flat flat = ComposedToFlatMapper.INSTANCE.map(composed); // flat.getA() is "A", OK! // flat.getB() is null, unexpected, should be "B" // flat.getC() also null, should be "C". "B"未映射到"C",因为生成代码不会为此创建方法。

我以为我已经向生成器提供了所需的映射信息。它应该在看到flat方法时在ComposedToFlatMapperImpl内生成。

修改

之前我没有提到过,但在最初的问题中,我也可以使用Flat map(Sub s) - 更灵活的方法。

现在,假设有一个新的update类型。 :

Sub2

@Mapper(uses = {SubToFlatMapper.class, Sub2ToFlatMapper.class})
public interface ComposedToFlatMapper {

    Flat map(Composed c);

    void update(Composed source, @MappingTarget Flat target);
}

@Mapper
public interface SubToFlatMapper {

    Flat map(Sub s); 

    void update(Sub source, @MappingTarget Flat target);
}

@Mapper
public interface Sub2ToFlatMapper {

    Flat map(Sub2 s); 

    void update(Sub2 source, @MappingTarget Flat target);
}

由于Flat Composed ---- -------- - String a - String a - Sub - String b - String b - String c - String c - Sub2 - String d - String e 没有Flat引用,因此请忽略它。无需生成映射代码。

1 个答案:

答案 0 :(得分:1)

您可以简单地展平嵌套的源结构,如下所示:

@Mapper
public interface ComposedToFlatMapper {

    @Mapping(target="b", source="sub.b")
    @Mapping(target="c", source="sub.c")
    Flat map(Composed c);
}