如何使用 AutoMapper 将 DTO 展开为 entity/object 属性
How to use AutoMapper to unflatten DTO to entity/object property
这可能是一个非常基本的问题,请原谅我的 AutoMapper 无知。我试图从文档和其他 SO 问题中找出答案,但到目前为止都失败了。也许我正在尝试使用 AutoMapper 来做一些我不应该做的事情。我想在扁平化 DTO 的对象 属性 上设置一个值。
鉴于这些;
public class Fruit
{
public int Id { get; set; }
public string Name { get; set; }
public int ColourId { get; set; }
public Colour Colour { get; set; }
}
public class Colour
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FruitDto
{
public string Name { get; set; }
public string ColourName { get; set; }
}
我可以创建一个扁平化的 DTO 没问题,
var db = _serviceScopeFactory.CreateScope()
.ServiceProvider.GetService<FruitDb>();
var fruitDtos = db.Fruits.ProjectTo<FruitDto>(_mapper.ConfigurationProvider);
foreach (var dto in fruitDtos)
{
Console.WriteLine($"db fruit {dto.Name} = {dto.ColourName}");
}
但是当我尝试从 DTO 映射回来时,我并不清楚我需要做什么来设置水果对象颜色 属性 和 Colour.Name 集。
var exampleDto = new FruitDto()
{
Name = "lime",
ColourName = "green"
};
var exampleFruit = _mapper.Map<FruitDto, Fruit>(exampleDto);
Console.WriteLine($"example fruit {exampleFruit.Name} = {exampleFruit.Colour?.Name}");
让 AutoMapper 将 exampleFruit.Colour 设置为名称为 属性 的新 Color 实例的正确方法是什么(这个问题的扩展,一旦设置,我应该如何设置colour.Id 属性 如果颜色已经存在于数据库中)?
这是上面片段的完整示例;
using System;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace EntityFrameworkAutomapConsole
{
public class Fruit
{
public int Id { get; set; }
public string Name { get; set; }
public int ColourId { get; set; }
public Colour Colour { get; set; }
}
public class Colour
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FruitDto
{
public string Name { get; set; }
public string ColourName { get; set; }
}
class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddAutoMapper(typeof(AutoMapperProfile));
services.AddDbContext<FruitDb>(options =>
{
options.UseNpgsql("conn string here");
});
services.AddHostedService<Worker>();
});
}
public class Worker : BackgroundService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IMapper _mapper;
public Worker(
IServiceScopeFactory serviceScopeFactory,
IMapper mapper)
{
_serviceScopeFactory = serviceScopeFactory;
_mapper = mapper;
var fruitDb = _serviceScopeFactory.CreateScope()
.ServiceProvider.GetService<FruitDb>();
fruitDb.Database.EnsureCreated();
}
protected override async Task ExecuteAsync(CancellationToken cancel)
{
var db = _serviceScopeFactory.CreateScope()
.ServiceProvider.GetService<FruitDb>();
var fruitDtos = db.Fruits.ProjectTo<FruitDto>(_mapper.ConfigurationProvider);
foreach (var dto in fruitDtos)
{
Console.WriteLine($"db fruit {dto.Name} = {dto.ColourName}");
}
var exampleDto = new FruitDto()
{
Name = "lime",
ColourName = "green"
};
var exampleFruit = _mapper.Map<FruitDto, Fruit>(exampleDto);
Console.WriteLine($"example fruit {exampleFruit.Name} = {exampleFruit.Colour?.Name}");
}
}
public class FruitDb : DbContext
{
public FruitDb(DbContextOptions options)
: base(options)
{
}
public DbSet<Fruit> Fruits { get; set; }
public DbSet<Colour> Colours { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.HasDefaultSchema("public");
builder.Entity<Fruit>()
.HasIndex(f => f.Id)
.IsUnique();
builder.Entity<Colour>()
.HasIndex(c => c.Id)
.IsUnique();
base.OnModelCreating(builder);
}
}
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<FruitDto, Fruit>();
CreateMap<Fruit, FruitDto>();
}
}
}
感谢@lucian-bargaoanu,非常简单的评论。我在文档中错过了。所以我只需要在我的配置文件中使用 ReverseMap() 并删除显式 FruitDto
到 Fruit
映射。
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<FruitDto, Fruit>();
CreateMap<Fruit, FruitDto>();
}
}
变成
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<Fruit, FruitDto>().ReverseMap();
}
}
这可能是一个非常基本的问题,请原谅我的 AutoMapper 无知。我试图从文档和其他 SO 问题中找出答案,但到目前为止都失败了。也许我正在尝试使用 AutoMapper 来做一些我不应该做的事情。我想在扁平化 DTO 的对象 属性 上设置一个值。
鉴于这些;
public class Fruit
{
public int Id { get; set; }
public string Name { get; set; }
public int ColourId { get; set; }
public Colour Colour { get; set; }
}
public class Colour
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FruitDto
{
public string Name { get; set; }
public string ColourName { get; set; }
}
我可以创建一个扁平化的 DTO 没问题,
var db = _serviceScopeFactory.CreateScope()
.ServiceProvider.GetService<FruitDb>();
var fruitDtos = db.Fruits.ProjectTo<FruitDto>(_mapper.ConfigurationProvider);
foreach (var dto in fruitDtos)
{
Console.WriteLine($"db fruit {dto.Name} = {dto.ColourName}");
}
但是当我尝试从 DTO 映射回来时,我并不清楚我需要做什么来设置水果对象颜色 属性 和 Colour.Name 集。
var exampleDto = new FruitDto()
{
Name = "lime",
ColourName = "green"
};
var exampleFruit = _mapper.Map<FruitDto, Fruit>(exampleDto);
Console.WriteLine($"example fruit {exampleFruit.Name} = {exampleFruit.Colour?.Name}");
让 AutoMapper 将 exampleFruit.Colour 设置为名称为 属性 的新 Color 实例的正确方法是什么(这个问题的扩展,一旦设置,我应该如何设置colour.Id 属性 如果颜色已经存在于数据库中)?
这是上面片段的完整示例;
using System;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace EntityFrameworkAutomapConsole
{
public class Fruit
{
public int Id { get; set; }
public string Name { get; set; }
public int ColourId { get; set; }
public Colour Colour { get; set; }
}
public class Colour
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FruitDto
{
public string Name { get; set; }
public string ColourName { get; set; }
}
class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddAutoMapper(typeof(AutoMapperProfile));
services.AddDbContext<FruitDb>(options =>
{
options.UseNpgsql("conn string here");
});
services.AddHostedService<Worker>();
});
}
public class Worker : BackgroundService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IMapper _mapper;
public Worker(
IServiceScopeFactory serviceScopeFactory,
IMapper mapper)
{
_serviceScopeFactory = serviceScopeFactory;
_mapper = mapper;
var fruitDb = _serviceScopeFactory.CreateScope()
.ServiceProvider.GetService<FruitDb>();
fruitDb.Database.EnsureCreated();
}
protected override async Task ExecuteAsync(CancellationToken cancel)
{
var db = _serviceScopeFactory.CreateScope()
.ServiceProvider.GetService<FruitDb>();
var fruitDtos = db.Fruits.ProjectTo<FruitDto>(_mapper.ConfigurationProvider);
foreach (var dto in fruitDtos)
{
Console.WriteLine($"db fruit {dto.Name} = {dto.ColourName}");
}
var exampleDto = new FruitDto()
{
Name = "lime",
ColourName = "green"
};
var exampleFruit = _mapper.Map<FruitDto, Fruit>(exampleDto);
Console.WriteLine($"example fruit {exampleFruit.Name} = {exampleFruit.Colour?.Name}");
}
}
public class FruitDb : DbContext
{
public FruitDb(DbContextOptions options)
: base(options)
{
}
public DbSet<Fruit> Fruits { get; set; }
public DbSet<Colour> Colours { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.HasDefaultSchema("public");
builder.Entity<Fruit>()
.HasIndex(f => f.Id)
.IsUnique();
builder.Entity<Colour>()
.HasIndex(c => c.Id)
.IsUnique();
base.OnModelCreating(builder);
}
}
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<FruitDto, Fruit>();
CreateMap<Fruit, FruitDto>();
}
}
}
感谢@lucian-bargaoanu,非常简单的评论。我在文档中错过了。所以我只需要在我的配置文件中使用 ReverseMap() 并删除显式 FruitDto
到 Fruit
映射。
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<FruitDto, Fruit>();
CreateMap<Fruit, FruitDto>();
}
}
变成
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<Fruit, FruitDto>().ReverseMap();
}
}