Я впервые использую Automapper в базовом проекте. net, который использует внедрение зависимостей для передачи данных из старой унаследованной базы данных в новую архитектуру микросервисов, при этом каждый микросервис подключается к собственной базе данных (используя DDD принципы). К сожалению, невозможно перенести данные из sql в sql, и я предпочел бы создать приложение, которое извлекает данные из источника, а затем передает данные в новое приложение через совокупность root и модели.
У меня есть 3 проекта в моем решении:
- Основная точка входа, которая создает коллекцию сервисов с помощью DbContexts (исходный и целевой), добавляет целевой API, добавляет автоматический обработчик и создает / создает экземпляр передачи класс обслуживания
- Проект содержит исходный / унаследованный контекст БД, модели, а также профиль Automapper для создания карты.
- Сервисный проект, в котором существуют контексты sourceDB и targetDB и где выполняется Map.
Мне нужно добавить (я думаю) «Преобразование значений» для полей внешнего ключа и правильно перестроить структуры данных в новых базах данных. Моя проблема в том, добавить ли преобразование значения в профиль в пункте 2), но это не может получить доступ к целевому контексту в 3) Только когда служба запущена, существуют и исходный, и целевой контексты, и у меня есть доступ к обоим. Я посмотрел в документе «Прочитать документы для Automapper», но не могу найти способ добавить обработчик в проекте 2), который вызывается только в 3), когда сопоставление столбца имеет место.
ОБНОВЛЕНИЕ
- Код в Program.cs ->. net core 3.1 консольное приложение
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
ServiceProvider serviceProvider;
serviceCollection
.AddDbContext<Source.Models.SourceDbContext>(options => options.UseSqlServer(config.GetConnectionString("Source")))
.AddDbContext<Target.Models.ModelDbContext>(options => options.UseSqlServer(config.GetConnectionString("Target")))
.AddScoped<ILoggerFactory, LoggerFactory>()
.AddScoped<Source.Models.Services.IReadSourceService, Source.Models.Services.ReadSourceService>()
.AddAutoMapper(typeof(Source.Models.Currency).Assembly);
serviceProvider = serviceCollection.BuildServiceProvider();
}
В исходном проекте модели базы данных
public class MappingProfile : Profile
{
public DataTakaMappingProfile(IReadSourceService service)
{
this.CreateMap<Source.Models.Instrument, Target.Models.Instruments.Instrument>()
.ForMember(c => c.InstrumentId, opt => opt.Ignore())
.ForMember(c => c.TrackingState, opt => opt.Ignore())
.ForMember(c => c.CurrencyId, opt => opt.ConvertUsing(new CurrencyIdConverter(), c => c.CurrencyID));
}
В сервисном проекте
public class ReadSourceService : IReadSourceService
{
private readonly SourceDbContext context;
private readonly Target.Models.ModelDbContext targetContext;
private readonly ILogger<ReadSourceService> logger;
private readonly IMapper mapper;
/// <summary>
/// Initializes a new instance of the <see cref="ReadSourceService"/> class.
/// </summary>
/// <param name="sourceContext">Source DB context </param>
/// <param name="targetContext">Target DB context</param>
/// <param name="logger">logger</param>
/// <param name="mapper">mapper</param>
public ReadSourceService(
SourceDbContext context,
Target.Models.ModelDbContext targetContext,
ILogger<ReadSourceService> logger,
IMapper mapper)
{
this.context = context;
this.targetContext = targetContext;
this.logger = logger;
this.mapper = mapper;
}
/// <summary>
/// Perform tha data comparison
/// </summary>
public void TransferInstrument()
{
// perform the mapping here
}
}
Здесь мне нужно преобразовать для источника CurrencyId в Source.Instruments в новый CurrencyId в Target.Instruments
ОБНОВЛЕНИЕ 2
Инструмент "AB C", имеющий ссылку на внешний ключ в валюте "USD", будет перенесен из источника в цель. Валюты на данном этапе уже переведены. CurrencyCode: "USD", скорее всего, будет иметь разные значения первичного ключа, например:
- SourceDB -> CurrencyID = 23, CurrencyCode = "USD"
- TargetDB -> CurrencyID = 45 , CurrencyCode = "USD"
Когда отображается запись инструмента для InstrumentCode: "AB C", мне нужно перехватить сопоставление в свойстве "CurrencyID" и изменить значение с 23 на 45.
Моя структура проекта выглядит следующим образом
- ProjectA - console app.
└─ Program.cs
- ProjectB - source model classes
├─ Source - folder for data models in your source DB
└─ MappingProfile.cs
- ProjectC - source model classes
└─ DataTransferService.cs
- ProjectD - target model classes. This is just a nuget package that contains the new app/updated models in target DB
ОБНОВЛЕНИЕ 3 Я попытался создать преобразователь значений, а затем добавить его в профиль ForMember. Я также попытался использовать интерфейс IReadSourceService в конструкторе для распознавателя, надеясь, что DI будет использовать это, но в любом случае я получу исключение AutoMapper.AutoMapperMappingExa для элемента назначения: CurrencyId:
Не удается создать экземпляр Тип ForeignKeyResolver
this.CreateMap<Source.Models.Instrument, Target.Models.Instruments.Instrument>()
.ForMember(dest => dest.CurrencyId, opt => opt.MapFrom<ST.DataTaka.Models.Services.ForeignKeyResolver>());
public class ForeignKeyResolver : IValueResolver<object, object, int>
{
private readonly List<Tuple<int, int>> mappings;
public ForeignKeyResolver(List<Tuple<int, int>> mappings)
{
this.mappings = mappings;
}
public int Resolve(object source, object dest, int destMember, ResolutionContext context)
{
return mappings.Where(c => c.Item1 == (int)source).FirstOrDefault().Item2;
}
}