C# AutoMapper 映射多对多问题,外键错误

标签 c# automapper

我遇到了将模型映射到具有多对多关系的实体的奇怪问题

我有以下实体和模型:

using System;
using System.Diagnostics;
using System.Collections.Generic;

namespace AutoMapper.ReproducedExample
{
    public class StoreEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<StoreProductEntity> Products { get; set; } = new List<StoreProductEntity>();
    }

    public class ProductEntity
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<StoreProductEntity> Stores { get; set; } = new List<StoreProductEntity>();
    }

    public class StoreProductEntity
    {
        public int StoreId { get; set; }
        public StoreEntity Store { get; set; }
        public int ProductId { get; set; }
        public ProductEntity Product { get; set; }
    }

    public class StoreModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<ProductModel> Products { get; set; } = new List<ProductModel>();
    }

    public class ProductModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public List<StoreModel> Stores { get; set; } = new List<StoreModel>();
    }

    public class CustomProfile : Profile
    {
        public CustomProfile()
        {
            CreateMap<StoreModel, StoreEntity>()
                .ForMember(d => d.Products,
                    opt => opt.MapFrom(s => s.Products))
                .AfterMap((model, entity) =>
                {
                    foreach (var entityProduct in entity.Products)
                    {
                        entityProduct.StoreId = entity.Id;
                        entityProduct.Store = entity;
                    }
                });
            CreateMap<StoreModel, StoreProductEntity>()
                .ForMember(entity => entity.StoreId, opt => opt.MapFrom(model => model.Id))
                .ForMember(entity => entity.Store, opt => opt.MapFrom(model => model))
                .ForMember(entity => entity.ProductId, opt => opt.Ignore())
                .ForMember(entity => entity.Product, opt => opt.Ignore());

            CreateMap<ProductModel, ProductEntity>()
                .ForMember(d => d.Stores,
                    opt => opt.MapFrom(s => s.Stores))
                .AfterMap((model, entity) =>
                {
                    foreach (var entityStore in entity.Stores)
                    {
                        entityStore.ProductId = entity.Id;
                        entityStore.Product = entity;
                    }
                });
            CreateMap<ProductModel, StoreProductEntity>()
                .ForMember(entity => entity.StoreId, opt => opt.Ignore())
                .ForMember(entity => entity.Store, opt => opt.Ignore())
                .ForMember(entity => entity.ProductId, opt => opt.MapFrom(model => model.Id))
                .ForMember(entity => entity.Product, opt => opt.MapFrom(model => model));

        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var configuration = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile<CustomProfile>();
            });
#if DEBUG
            configuration.AssertConfigurationIsValid();
#endif
            var mapper = configuration.CreateMapper();
            var store0 = new StoreModel()
            {
                Id = 1,
                Name = "Store0",
            };
            var store1 = new StoreModel()
            {
                Id = 2,
                Name = "Store1",
            };
            var product = new ProductModel()
            {
                Id = 1,
                Name = "Product",
            };
            store1.Products.Add(product);
            product.Stores.Add(store1);
            store0.Products.Add(product);
            product.Stores.Add(store0);
            
            var store0Entity = mapper.Map<StoreEntity>(store0);
            Debug.Assert(store0Entity.Products[0].Product.Stores[0].Store.Id ==
                         store0Entity.Products[0].Product.Stores[0].Store.Products[0].StoreId);
        }
    }
}

映射成功,但由于某种原因,某些深层 key 未映射到相关的StoreEntity

以下断言失败...

Debug.Assert(store0Entity.Products[0].Product.Stores[0].Store.Id ==
             store0Entity.Products[0].Product.Stores[0].Store.Products[0].StoreId);

似乎由于某种原因,深入存储类 AutoMapper 使用了错误的映射列表...但我不确定...

最佳答案

我已经弄清楚如何解决这个问题(感谢对问题 Automapper creates 2 instances of one object 的回答)

为了检测循环引用,我可以添加.PreserveReferences()方法进行映射

这是正确的CustomProfile:

    public class CustomProfile : Profile
    {
        public CustomProfile()
        {
            CreateMap<StoreModel, StoreEntity>()
                .ForMember(d => d.Products,
                    opt => opt.MapFrom(s => s.Products))
                .AfterMap((model, entity) =>
                {
                    foreach (var entityProduct in entity.Products)
                    {
                        entityProduct.StoreId = entity.Id;
                        entityProduct.Store = entity;
                    }
                })
                .PreserveReferences();
            CreateMap<StoreModel, StoreProductEntity>()
                .ForMember(entity => entity.StoreId, opt => opt.MapFrom(model => model.Id))
                .ForMember(entity => entity.Store, opt => opt.MapFrom(model => model))
                .ForMember(entity => entity.ProductId, opt => opt.Ignore())
                .ForMember(entity => entity.Product, opt => opt.Ignore());

            CreateMap<ProductModel, ProductEntity>()
                .ForMember(d => d.Stores,
                    opt => opt.MapFrom(s => s.Stores))
                .AfterMap((model, entity) =>
                {
                    foreach (var entityStore in entity.Stores)
                    {
                        entityStore.ProductId = entity.Id;
                        entityStore.Product = entity;
                    }
                })
                .PreserveReferences();
            CreateMap<ProductModel, StoreProductEntity>()
                .ForMember(entity => entity.StoreId, opt => opt.Ignore())
                .ForMember(entity => entity.Store, opt => opt.Ignore())
                .ForMember(entity => entity.ProductId, opt => opt.MapFrom(model => model.Id))
                .ForMember(entity => entity.Product, opt => opt.MapFrom(model => model));
        }
    }

但实际上我不知道这是否是一个问题,因为根据文档 AutoMapper 应该自动检测 AutoMapper 版本 10.0.0 的 Circular References 并且似乎这是一个问题

关于C# AutoMapper 映射多对多问题,外键错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63973722/

相关文章:

c# - Automapper 正在丢失引用

c# - 具有AutoMapper的体系结构?

c# - 在派生类中调用泛型函数的更好方法

c# - 添加基于变量的附加 linq where 子句

c# - 使用 AutoMapper 获取异常

c# - AutoMapper 根据外部值有条件地映射属性

entity-framework - 具有相互导航属性的自动映射器

c# - 尝试将递归 JavaScript 方法移植到 C#,这种方法有意义吗?

javascript - 如何为仅可用的键绑定(bind) Knockout viewModel?

c# - 如何在 WCF 服务响应中正确实现自定义 soap 1.2 header 和 WS-Addressing