EntityFramework Core 3 и Automapper. Включить с фильтром - PullRequest
0 голосов
/ 28 февраля 2020

Я пытаюсь выполнить автоматический вызов 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 Перечислимо на одном объекте, как это должно работать?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...