AutoMapper +可为空的外键+实体框架核心

时间:2018-12-01 19:37:31

标签: c# entity-framework-core automapper

状态更新(12/19/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; }
}

我发现这是通过从 Product ProductCmd 中删除Color导航属性并执行AssertConfigurationIsValid

Startup.cs

public class Startup
{
    public void Configure(IApplicationBuilder app, 
                          IHostingEnvironment env, 
                          IMapper autoMapper)
    {
        autoMapper.ConfigurationProvider.AssertConfigurationIsValid();
    }
}

现在,我得到了:

  

AutoMapper.AutoMapperConfigurationException
  HResult = 0x80131500
  来源= AutoMapper
  StackTrace:无法评估异常堆栈跟踪

     

‘AutoMapperConfigurationException:未映射的成员是   找到”。

当我删除ColorSystemName成员时,不会发生此问题:

ProductCmd.cs

public class ProductCmd
{
    public virtual int? ColorId { get; set; }
    public virtual ColorCmd Color { get; set; }
}

问题:
尝试在包含空ColorSystemName导航属性的原始配置中展平Color时,AutoMapper是否实例化了新的 Color 类型?


原始帖子

我希望AutoMapper将空(EF核心导航)属性ColorProductCmd映射到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
  •   

AutoMapper Documentation或各种在线资源中找不到解决此问题的方法。

以下是显示映射结果和错误的示例代码:

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."            
        //
    }

}

0 个答案:

没有答案