Я пытаюсь выполнить автоматический вызов ProjectTo <> из IQueryable с использованием EFC3. У моих объектов есть некоторые навигационные свойства, которые мне нужно получить как таковые, но другие, которые мне нужно отфильтровать с помощью предложения Where.
Я могу добиться этого, выполнив 3 вызова базы данных
var dto = _context.Bonds.Where(x => x.Id == request.Id).
ProjectTo<BondDto>(_mapper.ConfigurationProvider) // Mapping is done here
.FirstOrDefaultAsync(cancellationToken);
var price = _context.MarketDatas.OfType<RatingMarketData>()
.Where(x => x.Date == request.Date && x.AssetId == request.Id)
.ProjectTo<RatingMarketDataDto>(_mapper.ConfigurationProvider)
.FirstOrDefaultAsync(cancellationToken);
var rating = ... same than for price
1 вызов базы данных со множеством включений и отображений, которые мне не нравятся
var vm = _context.Bonds
.Include(x => x.CallSchedule)
.Include(x => x.PutSchedule)
.Include(x => x.FixedCouponSchedule)
.Include(x => x.FloatingCouponSchedule)
.Include(x => x.RedemptionSchedule) // If I don't Include I don't get nested objects like ProjectTo<>
.Where(x => x.Id == request.Id)
.Select(b => new BondVm
{
BondDto = _mapper.Map<BondDto>(b),
RatingDto = _mapper.Map<RatingMarketDataDto>(b.MarketDatas.OfType<RatingMarketData>()
.OrderByDescending(x => x.Date)
.FirstOrDefault(x => x.AssetId == request.Id && x.Date <= request.Date)),
PriceDto = _mapper.Map<PriceMarketDataDto>(
b.MarketDatas.OfType<PriceMarketData>()
.FirstOrDefault(x => x.Date == request.Date && x.AssetId == request.Id))
})
.FirstOrDefaultAsync(cancellationToken);
1 вызов базы данных без использования Automapper. Много ручного картирования и некрасивого кода. Это именно то, чего я пытаюсь достичь, но я хотел бы использовать возможности Automapper projectTo << >>.
var vm = await _context.Bonds
.Where(b => b.Id == request.Id)
.Select(bond => new
{
Bond = new BondDto
{
Id = bond.Id.ToString(),
Currency = bond.Currency,
BorrowerClass = bond.BondSector.BorrowerClass,
CouponFrequency = bond.CouponFrequency,
AccruedDayCount = bond.AccruedDayCount,
CallScheduleStyle = bond.CallScheduleStyle,
CorrelatedResidual = bond.CorrelatedResidual,
IsPerpetual = bond.IsPerpetual,
Issuer = bond.Issuer,
IssuerSeniority = bond.IssuerSeniority,
Maturity = bond.Maturity,
CallSchedule = bond.CallSchedule.Select(s => _mapper.Map<CallScheduleItemDto>(s)).ToList(),
FixedCouponSchedule = bond.FixedCouponSchedule.Select(s => _mapper.Map<FixedCouponScheduleItemDto>(s)).ToList(),
RedemptionSchedule = bond.RedemptionSchedule.Select(s => _mapper.Map<RedemptionScheduleItemDto>(s)).ToList(),
PutSchedule = bond.PutSchedule.Select(s => _mapper.Map<PutScheduleItemDto>(s)).ToList(),
FloatingSpreadSchedule = bond.FloatingSpreadSchedule.Select(s => _mapper.Map<FloatingSpreadScheduleItemDto>(s)).ToList(),
},
Price = _mapper.Map<PriceMarketDataDto>(bond.MarketDatas.OfType<PriceMarketData>()
.FirstOrDefault(p => p.Date == request.Date && p.AssetId == request.Id)),
Rating = _mapper.Map<RatingMarketDataDto>(bond.MarketDatas.OfType<RatingMarketData>()
.OrderByDescending(x => x.Date)
.FirstOrDefault(x => x.AssetId == request.Id && x.Date <= request.Date))})
.FirstOrDefaultAsync(cancellationToken);
То, чего я хотел бы достичь, - это 1 база данных позвоните с помощью ProjectTo << 'BondVm' >>
var vm = _context.Bonds
.Where(x => x.Id == request.Id)
.ProjectTo<BondVm>(_mapper.ConfigurationProvider);
Вот BondVM на всякий случай:
public class BondVm
{
public BondDto BondDto { get; set; }
public RatingMarketDataDto RatingDto { get; set; }
public PriceMarketDataDto PriceDto { get; set; }
}
И каким-то образом можно будет отфильтровать 2 моих навигационных свойства (рейтинг и цена) с условиями выше. Я не могу понять, как отфильтровать свой профиль сопоставления с помощью
Дайте мне знать, если вам нужна дополнительная информация. Большое спасибо за вашу помощь!
Edit:
Что касается того, что Lucian Bargaoanu предлагает, это мой профиль картирования:
public BondVmMapper()
{
Map.ForMember(d => d.BondDto, o => o.MapFrom(x => x));
Map.ForMember(d => d.PriceDto, o => o.MapFrom(s => s.MarketDatas.OfType<PriceMarketData>()));
Map.ForMember(d => d.RatingDto, o => o.MapFrom(s => s.MarketDatas.OfType<RatingMarketData>()));
}
Что странного в том, что мы наносим на карту a Перечислимо на одном объекте, как это должно работать?