具有Parent和ChildCollection的Mapster "reciprocal"导航属性.



我有" entities"one_answers"dtos".

Department有N Employees员工有1个(父)部门

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

My 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; }
}

dto:

// 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"...."的雇员属性又名"互惠";属性。

使用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;
}
}

我就差那么一点。

我使用了错误的配置方法。

我(在我的原始帖子中)正在追踪"shallowcopyforsametype"。

下面显示了"preserverreference",它阻止了stackover异常。

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

大声喊出答案:

使用Mapster调整导航属性

注意,这使我的Dto的水分。

我必须添加这个(下面)来让asp.net core通过网络推送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);
}
}

最新更新