0

所以我有“实体”和“dtos”。

部门有 N 个雇员 雇员有 1 个(父)部门。

现在我对属性名称没有偏差。

我的 EFCore“查询”正在获取包含(子)员工的所有部门。

我更喜欢将我的“映射”代码隔离到接口和具体。我的具体将注入 Mapster 依赖项。

// 实体

using System;
[Serializable]
public partial class DepartmentEntity
{
    public int DepartmentKey { get; set; } /* PK */

    public string DepartmentName { get; set; }


}

    public partial class DepartmentEntity
{
    public DepartmentEntity()
    {
        this.Employees = new List<EmployeeEntity>();
    }

    public ICollection<EmployeeEntity> Employees { get; set; }
}


using System;
[Serializable]
public partial class EmployeeEntity
{
    public int EmployeeKey { get; set; } /* PK */


    public string LastName { get; set; }

    public string FirstName { get; set; }



}


public partial class EmployeeEntity
{

    public DepartmentEntity ParentDepartment { get; set; }

}

Dtos:

// Different CsProject


// Dtos

using System;
[Serializable]
public partial class DepartmentDto
{
    public int DepartmentKey { get; set; } /* PK */

    public string DepartmentName { get; set; }


}

    public partial class DepartmentDto
{
    public DepartmentDto()
    {
        this.Employees = new List<EmployeeDto>();
    }

    public ICollection<EmployeeDto> Employees { get; set; }
}


using System;
[Serializable]
public partial class EmployeeDto
{
    public int EmployeeKey { get; set; } /* PK */


    public string LastName { get; set; }

    public string FirstName { get; set; }



}


public partial class EmployeeDto
{

    public DepartmentDto ParentDepartment { get; set; }

}    

和 CustomerMapper 接口和具体

using System.Collections.Generic;


public interface IDepartmentConverter
{

    DepartmentDto ConvertToDto(DepartmentEntity entity);

    ICollection<DepartmentDto> ConvertToDtos(ICollection<DepartmentEntity> entities);

    DepartmentEntity ConvertToEntity(DepartmentDto dto);

    ICollection<DepartmentEntity> ConvertToEntities(ICollection<DepartmentDto> dtos);

}




using System;
using System.Collections.Generic;
using Mapster;
using MapsterMapper;


public class DepartmentConverter : IDepartmentConverter
{
    public const string ErrorMessageIMapperNull = "IMapper is null";

    private readonly IMapper mapper;

    public DepartmentConverter(IMapper mapper)
    {
        this.mapper = mapper ?? throw new ArgumentNullException(ErrorMessageIMapperNull, (Exception)null);
    }

    public DepartmentDto ConvertToDto(DepartmentEntity entity)
    {
        return this.mapper.Map<Department>(entity);
    }

    public ICollection<DepartmentDto> ConvertToDtos(ICollection<DepartmentEntity> entities)
    {
        return this.mapper.Map<ICollection<Department>>(entities);
    }

    public ICollection<DepartmentEntity> ConvertToEntities(ICollection<DepartmentDto> dtos)
    {
        return this.mapper.Map<ICollection<DepartmentEntity>>(dtos);
    }

    public DepartmentEntity ConvertToEntity(DepartmentDto dto)
    {
        return this.mapper.Map<DepartmentEntity>(dto);
    }
}

所以在我的 EF 获取所有部门,包括员工电话后,我有一个充分的水分

ICollection<DepartmentEntity> departmentsWithEmps 

在我的处置。

但是当它通过转换/映射代码时......我得到一个“堆栈溢出”异常。

我很确定我知道为什么。它是“ParentDepartment”的 Employee 属性......也就是孩子的“互惠”属性。

对于 Newtonsoft,“修复”之一通常是这个

var json = JsonConvert.SerializeObject(harry, 
    new JsonSerializerSettings() 
    { 
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore 
    });

Mapster 是否有处理这种情况的配置?

以下是我的 IoC 注册尝试.......我已经尝试过,但速度很快。

namespace MyStuff
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using Mapster;
    using MapsterMapper;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;


    public class Startup
    {

        private string tempDebuggingConnectionString = string.Empty;

        public Startup(IConfiguration configuration, IWebHostEnvironment iwhe)
        {
            this.Configuration = configuration;
            this.WebHostEnvironment = iwhe;
        }



        public IConfiguration Configuration { get; }


        public IWebHostEnvironment WebHostEnvironment { get; }



        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {


            Type iregisterType = typeof(IRegister);
            IEnumerable<Assembly> iregisterTypeAssemblies = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                                 from assemblyType in assembly.GetTypes()
                                 where assemblyType.GetInterfaces().Contains(iregisterType)
                                 select assembly;

            //TypeAdapterConfig.GlobalSettings.Scan(iregisterTypeAssemblies.Distinct().ToArray());




            // TypeAdapterConfig config = new TypeAdapterConfig();
            // Or
            //TypeAdapterConfig.GlobalSettings.Default.ShallowCopyForSameType(true);
            TypeAdapterConfig config = TypeAdapterConfig.GlobalSettings;


            //     config.NewConfig<DepartmentDto, DepartmentEntity>()
            //.ShallowCopyForSameType(true);


            //     config.NewConfig<DepartmentEntity, DepartmentDto>()
            //     .ShallowCopyForSameType(true);


           // config.NewConfig<DepartmentEntity, DepartmentDto>()
             //   .Map(dest => dest.Employees, src => src.Employees);



            //        TypeAdapterSetter<DepartmentEntity, Department> orgSetter = TypeAdapterConfig<DepartmentEntity, Department>
            //.NewConfig()

            //.ShallowCopyForSameType(true);

            //  orgSetter.Config = config;



            services.AddSingleton(config);
            //services.AddSingleton(orgSetter);
            services.AddScoped<IMapper, ServiceMapper>();
    


        }

        public void Configure(ILogger<Startup> logger, IApplicationBuilder app, IWebHostEnvironment env)

        {
                /* not shown */


        }
    }
}

虽然您可以猜到,但我的 EFCore 代码如下所示:

public async Task<IEnumerable<DepartmentDto>> GetAllAsync(CancellationToken token)
{
    List<DepartmentEntity> entities = await this.entityDbContext.Departments.Include(ent => ent.ApplicationDetails).AsNoTracking().ToListAsync(token);
    try
    {
        /* below is injected, but new'ing it up here for SOF question */
        IDepartmentConverter localNonInjectedConverter = new DepartmentConverter(/* again, not my real code....my IoC has the Mapster object */);
        ICollection<DepartmentDto> returnItems = localNonInjectedConverter.ConvertToDtos(entities);
        return returnItems;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}
4

1 回答 1

0

啊啊啊。

我是如此接近。

我在追逐错误的配置方法。

我(在我原来的帖子中)正在追逐“ShallowCopyForSameType”。

下面显示了“PreserveReference”,它停止了 stackover 异常。

        config.NewConfig<OrganizationEntity, Organization>()
   .PreserveReference(true);

        config.NewConfig<ApplicationDetailEntity, ApplicationDetail>()
   .PreserveReference(true);

大声喊出这个答案:

使用 Mapster 调整导航属性

请注意,这让我的 Dto 水分充足。

我必须添加这个(如下)才能让 asp.net 核心将 object-json 推送到网络上。

检测到.Net Core 3.0 可能的对象循环,但不支持

旁注,我用我在研究时发现的另一个想法对 IoC 进行了一些清理。

        /* the below keeps the Mapster registrations out of the top layer, but without having to keep up with any new IRegister classes */
        Type mapsterRegisterType = typeof(IRegister);
        IEnumerable<Assembly> iregisterTypeAssemblies = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                             from assemblyType in assembly.GetTypes()
                             where assemblyType.GetInterfaces().Contains(mapsterRegisterType)
                             select assembly;

        TypeAdapterConfig.GlobalSettings.Scan(iregisterTypeAssemblies.Distinct().ToArray());




        // TypeAdapterConfig config = new TypeAdapterConfig();
        // Or
        TypeAdapterConfig config = TypeAdapterConfig.GlobalSettings;


        services.AddSingleton(config);
        services.AddScoped<IMapper, ServiceMapper>();

public class MapsterConfiguration : IRegister
{
    public MapsterConfiguration()
    {
        /* MUST have empty constructor */
    }

    public void Register(TypeAdapterConfig config)
    {

        config.NewConfig<DepartmentEntity, DepartmentDto>()
   .PreserveReference(true);

        config.NewConfig<EmployeeEntity, EmployeeDto>()
   .PreserveReference(true);

    }
}
于 2021-03-10T19:57:43.137 回答