如何使用AutoMapper将配方与配料映射

时间:2018-10-18 17:15:13

标签: c# entity-framework asp.net-core automapper

我有以下RecipeModel,IngredientModel和RecipePartModel类,它们代表前端用户的DTO类:

public class RecipeModel
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string ImageUrl { get; set; }
    public string Description { get; set; }
    public IEnumerable<RecipePartModel> RecipeParts { get; set; }
}

public class IngredientModel
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

public class RecipePartModel
{
    public Guid Id { get; set; }
    public IngredientModel Ingredient { get; set; }
    public string Unit { get; set; }
    public decimal Quantity { get; set; }
}

这是我的实体类:

public class Recipe : BaseEntity
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string ImageUrl { get; set; }
    public string Description { get; set; }
    public virtual IEnumerable<RecipePart> RecipeParts { get; set; }
}

public class Ingredient : BaseEntity
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public Guid Id { get; set; }
    public string Name { get; set; }
    public int Amount { get; set; }
    public virtual IEnumerable<RecipePart> RecipeParts { get; set; }
}

public class RecipePart : BaseEntity
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public Guid Id { get; set; }
    public Ingredient Ingredient { get; set; }
    public Recipe Recipe { get; set; }
    public string Unit { get; set; }
    public decimal Quantity { get; set; }
}

我的问题是-如何使用AutoMapper将配方映射到RecipeModel?我尝试过类似的操作,但我认为这很不好,因为它只是加入了整个数据库的所有RecipeParts,对吗?

public class DomainProfile : Profile
{
    public DomainProfile()
    {
        CreateMap<Ingredient, IngredientModel>().ReverseMap();
        CreateMap<Recipe, RecipeModel>()
            .ForMember(x => x.RecipeParts, opt => opt.MapFrom(src => src.RecipeParts));
    }
}

2 个答案:

答案 0 :(得分:1)

此映射没有什么不好的。实际上,您甚至不需要ForMember调用,因为这是默认约定。映射将简单地将实体子集合中的每个元素转换为相应的模型对象。

当然,是否以有效的方式加载实体是另一回事。如果您加载大量的Recipe实体,而懒惰地为每个实体加载RecipeParts集合,则将遇到主要的“ SELECT N + 1”问题。但这不是AutoMapper的错。

答案 1 :(得分:1)

要回答有关如何使用AutoMapper将一个类型映射到另一个类型的问题,有很多方法可以这样做。文档在这里:http://docs.automapper.org/en/stable/Getting-started.html

我编写了一个控制台应用程序,并使用您的代码以最快的方式使它运行。当我调试此代码并检查recipeModel内部时,它使用单个RecipePartModel引用了RecipePartModels列表。在该RecipePartModel中,它引用了IngredientModel。

    static void Main(string[] args)
    {
        var profile = new DomainProfile();

        Mapper.Initialize(cfg => cfg.AddProfile(profile));

        var recipe = new Recipe
        {
            RecipeParts = new List<RecipePart>
            {
                new RecipePart()
                {
                    Ingredient = new Ingredient()
                }
            }
        };

        var recipeModel = Mapper.Map<Recipe, RecipeModel>(recipe);

        Console.ReadKey();
    }

要回答有关从数据库获取所有配方的问题,如果使用的是Entity Framework,则取决于是否打开了延迟加载。延迟加载可确保从数据库中获取配方时,配方部分不会被加载。仅当您稍后在程序流中直接访问配方零件时,才会加载它们。默认情况下,延迟加载是打开的,因此这是默认行为。如果您将其关闭,则启用了预先加载功能,可以加载所有配方部分并依次加载其成分。

这可能会有所帮助:http://www.entityframeworktutorial.net/lazyloading-in-entity-framework.aspx