Обновление статуса (19.12.18)
Проблема в том, что при выполнении Map<Product>(cmd)
AutoMapper отображает новый тип Color
(с нулевыми значениями) на Продукт .
Вопрос:
Может ли это быть ошибкой, когда AutoMapper пытается "сгладить" элемент ColorSystemName
?
ProductCmd.cs
public class ProductCmd
{
public virtual int? ColorId { get; set; }
public virtual ColorCmd Color { get; set; }
public virtual string ColorSystemName { get; set; }
}
Я нашел это, удалив свойство навигации Color
из Product и ProductCmd и выполнивAssertConfigurationIsValid
:
Startup.cs
public class Startup
{
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
IMapper autoMapper)
{
autoMapper.ConfigurationProvider.AssertConfigurationIsValid();
}
}
Теперь я получаю:
AutoMapper.AutoMapperConfigurationException
HResult =0x80131500
Source = AutoMapper
StackTrace: Невозможно оценить трассировку стека исключений
'AutoMapperConfigurationException: Обнаружены несопоставленные элементы'.
Эта проблема не возникает при удаленииColorSystemName
член:
ProductCmd.cs
public class ProductCmd
{
public virtual int? ColorId { get; set; }
public virtual ColorCmd Color { get; set; }
}
Вопрос:
Создал ли AutoMapper новый тип Color при попытке сгладить ColorSystemName
в исходной конфигурации, содержащей нулевое Color
свойство навигации?
Исходное сообщение
Я хочу, чтобы AutoMapper отображал нулевое свойство (навигация EF Core) Color
из ProductCmd
в Product
.
У меня естьпопытался использовать одно свойство навигации, а также полностью определенное отношение (включая свойство обратной навигации).
Product.cs
public class Product
{
public virtual int? ColorId { get; set; }
public virtual Color Color { get; set; }
}
ProductCmd.cs
public class ProductCmd
{
public virtual int? ColorId { get; set; }
public virtual ColorCmd Color { get; set; }
public virtual string ColorSystemName { get; set; }
}
Color.cs
public class Color
{
public virtual int Id { get; set; }
public virtual string SystemName { get; set; }
}
ColorCmd.cs
public class ColorCmd
{
public virtual int Id { get; set; }
public virtual string SystemName { get; set; }
}
ProductTypeConfiguration.cs
public class ProductTypeConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.ToTable("Product", "dbo");
builder.HasKey(a => a.Id);
builder.HasOne(a => a.Color)
.WithMany()
.HasForeignKey(s => s.ColorId)
.OnDelete(DeleteBehavior.ClientSetNull)
.IsRequired(false);
}
}
ColorTypeConfiguration.cs
public class ColorTypeConfiguration : IEntityTypeConfiguration<Color>
{
public void Configure(EntityTypeBuilder<Color> builder)
{
builder.ToTable("Color", "dbo");
builder.HasKey(a => a.Id);
}
}
InitialInventoryDbMigration.cs
public partial class InitialInventoryDbMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Color",
schema: "dbo",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
SystemName = table.Column<string>(maxLength: 256, nullable: false),
},
constraints: table =>
{
table.PrimaryKey("PK_Color", x => x.Id);
});
migrationBuilder.CreateTable(
name: " Product",
schema: "dbo",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
ColorId = table.Column<int>(nullable: true),
},
constraints: table =>
{
table.PrimaryKey("PK_ Product", x => x.Id);
table.ForeignKey(
name: "FK_Product_Color_ColorId",
column: x => x.ColorId,
principalSchema: "dbo",
principalTable: " Color",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
}
Startup.cs
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
_services.AddAutoMapper(cfg =>
{
cfg.AllowNullDestinationValues = true;
},
new[]
typeof(AutoMapperProfiles_Inventory)
});
}
}
AutoMapperProfiles_Inventory.cs
public class AutoMapperProfiles_Inventory
{
public List<Profile> GetProfiles()
{
var profiles = new List<Profile>()
{
new AutoMapperProfile_Inventory_Cmd()
};
return profiles;
}
}
AutoMapperProfile_Inventory_Cmd.cs
using features = Module.Inventory.ApplicationCore.BLL.Domain.Features;
using pocos = Module.Inventory.ApplicationCore.BLL.Domain.Entities;
using AutoMapper;
namespace Dcs.NetCore.Module.Inventory.ApplicationCore.BLL.Domain.Entities.Mappers.Profiles
{
public class AutoMapperProfile_Inventory_Cmd : Profile
{
public AutoMapperProfile_Inventory_Cmd()
{
CreateMap<pocos.Color, features.Colors.Cmd>().ReverseMap();
CreateMap<pocos.Product, features.Products.Cmd>()
.ReverseMap();
}
}
}
Использованные библиотеки:
- Microsoft.EntityFrameworkCore v.2.1.4
- Microsoft.NETCore.App v.2.1
- AutoMapper.Extensions.Microsoft.DependencyInjection v.6.0.0
- AutoMapper v.8.0.0
Проблема также возникает с:
- AutoMapper.Extensions.Microsoft.DependencyInjection v.5.0.1
- AutoMapper v.7.0.1
Я не смог найти решение этого сценария, яn Документация AutoMapper или различные онлайн-ресурсы.
Вот пример кода, показывающий результаты сопоставления и ошибку:
public class Example
{
private readonly IMapper _mapper;
private readonly IProductRepository _repository;
public Example(IMapper mapper, IProductRepository repository)
{
_mapper = mapper;
_repository = repository;
}
public void Add()
{
var cmd = new Cmd()
{
Color = null,
ColorId = null,
Id = 0,
ProductBrand = null,
ProductBrandId = 2
};
var dao = _mapper.Map<Product>(cmd);
//
//
// at this point:
//
//
// dao.Color == Color(with null values)
// dao.Color.Id == 0
// dao.ColorId == null
// dao.Id == 0
// dao.ProductBrand == ProductBrand(with null values)
// dao.ProductBrand.Id == 0
// dao.ProductBrandId == 1
//
//
_repository.AddAsync(dao);
//
// executes dbSet.Add(dao);
//
//
// at this point:
//
// dao.Color == Color(with null values)
// dao.Color.Id == -2147482643
// dao.ColorId == -2147482643
// dao.Color.Products[0].Color.Id == -2147482643
// dao.Color.Products[0].Id == -2147482647
// dao.Id == -2147482647
// dao.ProductBrand == ProductBrand(with correct values)
// dao.ProductBrand.Id == 1
// dao.ProductBrandId == 1
//
//
_repository.SaveChangesAsync();
//
// executes _dbContext.SaveChangesAsync();
//
//
// at this point:
//
// System.Data.SqlClient.SqlException(0x80131904):
// "Cannot insert the value NULL into column 'AddedBy',
// table 'dbo.Color';
// column does not allow nulls.
// INSERT fails.\r\nThe statement has been terminated."
//
}
}