В чем может быть причина того, что моя базовая сущность не загружена в методе расширения? - PullRequest
0 голосов
/ 12 сентября 2018

У меня проблемы с использованием Kendo Grid и Linq. Я использую kendo только в бэкэнде, чтобы упростить фильтрацию и сортировку. Все работало нормально, пока я не коснулся объекта, который имеет связанные объекты. Мои объекты базовые объекты не загружены в мое расширениеметод, но если я использую инициализацию объекта в методе выбора linq, он работает нормально.Может быть, моего знания linq недостаточно, но я хочу узнать, что за фокус здесь происходит?Любая помощь будет принята с благодарностью.

Мой метод расширения, который дает мне ViewModel:

public static MeetingRoomCultureListViewModel ToMeetingRoomCultureListViewModel(this MeetingRoomCulture meetingRoomCulture) {

        var viewModel = new MeetingRoomCultureListViewModel();

        viewModel.Id = meetingRoomCulture.BaseEntityId;

        viewModel.CancellationDuration = meetingRoomCulture.BaseEntity.CancellationDuration;

        viewModel.MinimumMeetingDuration = meetingRoomCulture.BaseEntity.MinimumMeetingDuration;
        viewModel.OnlyAdminsCanReserve = meetingRoomCulture.BaseEntity.OnlyAdminsCanReserve;
        viewModel.Price = meetingRoomCulture.BaseEntity.Price;
        viewModel.SaltoLockId = meetingRoomCulture.BaseEntity.SaltoLockId;
        viewModel.Status = meetingRoomCulture.Status;
        viewModel.Capacity = meetingRoomCulture.BaseEntity.Capacity;
        viewModel.CleaningDuration = meetingRoomCulture.BaseEntity.CleaningDuration;
        viewModel.Color = meetingRoomCulture.BaseEntity.Color;
        viewModel.Currency = meetingRoomCulture.BaseEntity.Currency;
        viewModel.IsHidden = meetingRoomCulture.BaseEntity.IsHidden;
        viewModel.LocationId = meetingRoomCulture.BaseEntity.LocationId;
        viewModel.LocationName = meetingRoomCulture.BaseEntity.Location.Name;
        viewModel.MaximumDaysForReservationInFuture = meetingRoomCulture.BaseEntity.MaximumDaysForReservationInFuture;
        viewModel.PictureUrl = meetingRoomCulture.BaseEntity.PictureUrl;
        viewModel.Name = meetingRoomCulture.BaseEntity.Name;
        viewModel.TaxRatio = meetingRoomCulture.BaseEntity.TaxRatio;
        viewModel.MaximumMeetingDuration = meetingRoomCulture.BaseEntity.MaximumMeetingDuration;
        viewModel.CreatedDate = meetingRoomCulture.CreatedDate;
        viewModel.LastModifiedDate = meetingRoomCulture.LastModifiedDate;
        return viewModel; 
} 

Вот этот BaseEntity не загружается, и я получаю исключение нулевой ссылки.

И мой метод API:

 public IActionResult Get([FromQuery] [DataSourceRequest] DataSourceRequest request) {
        var ds = _dbContext.MeetingRoomCultures.AsNoTracking().Include(x => x.BaseEntity).ThenInclude(x => x.Location).CultureFilter(CurrentCulture)
            .Select(x => x.ToMeetingRoomCultureListViewModel()).ToDataSourceResult(request);
        return Ok(ds);
    }

Однако, если я использую инициализацию объекта, все работает нормально, и Базовая сущность загружается, исключений не происходит. Как ниже:

 public IActionResult Get([FromQuery] [DataSourceRequest] DataSourceRequest request) {
        var ds = _dbContext.MeetingRoomCultures.AsNoTracking().Include(x => x.BaseEntity).ThenInclude(x => x.Location).CultureFilter(CurrentCulture)
            .Select(x => new MeetingRoomCultureListViewModel()
            {
                Id = x.BaseEntityId,

                CancellationDuration = x.BaseEntity.CancellationDuration,

                MinimumMeetingDuration = x.BaseEntity.MinimumMeetingDuration,
                OnlyAdminsCanReserve = x.BaseEntity.OnlyAdminsCanReserve,
                Price = x.BaseEntity.Price,
                SaltoLockId = x.BaseEntity.SaltoLockId,
                Status = x.Status,
                Capacity = x.BaseEntity.Capacity,
                CleaningDuration = x.BaseEntity.CleaningDuration,
                Color = x.BaseEntity.Color,
                Currency = x.BaseEntity.Currency,
                IsHidden = x.BaseEntity.IsHidden,
                LocationId = x.BaseEntity.LocationId,
                LocationName = x.BaseEntity.Location.Name,
                MaximumDaysForReservationInFuture = x.BaseEntity.MaximumDaysForReservationInFuture,
                PictureUrl = x.BaseEntity.PictureUrl,
                Name = x.BaseEntity.Name,
                TaxRatio = x.BaseEntity.TaxRatio,
                MaximumMeetingDuration = x.BaseEntity.MaximumMeetingDuration,
                CreatedDate = x.CreatedDate,
                LastModifiedDate = x.LastModifiedDate
            }).ToDataSourceResult(request);
        return Ok(ds);
    }

1 Ответ

0 голосов
/ 12 сентября 2018

Существует несколько причин.

Во-первых, в обоих запросах используется проекция (Select) на не тип сущности, следовательно, они попадают в В число игнорируемых включается категория:

Если изменить запрос так, чтобы он больше не возвращал экземпляры типа сущности, с которого начался запрос, то операторы включения игнорируются.

Разница составляет , где оценивается Select.Пользовательские (расширенные) методы не могут быть переведены в SQL, поэтому выполняются на клиенте.Поскольку включения игнорируются, вы получаете null свойства навигации по ссылкам и null или свойства навигации по пустой коллекции.В то время как во втором сценарии запрос транслируется в SQL и выполняется на стороне сервера (базы данных).Внутри SQL-запроса не задействованы реальные «объекты» или «коллекции», только таблицы и объединения.

Для получения дополнительной информации см. Оценка клиента и сервера abd Как выполнять запросыРаботайте по (и в целом по всем запросам данных связанным) темам документации.

В заключение, для повышения производительности (и многих других причин), всегда пытайтесь создавать запросы на стороне сервера.Что означает не использовать пользовательские методы вообще.Если вам нужно повторно использовать логику, поместите ее в Expression<TSource, TResult>, скомпилируйте делегат и используйте его из других источников.

Например:

public static class Selectors
{
    public static readonly Expression<Func<MeetingRoomCulture, MeetingRoomCultureListViewModel>>
    MeetingRoomCultureToListViewModel = source => new MeetingRoomCultureListViewModel
    {
        Id = source.BaseEntityId,

        CancellationDuration = source.BaseEntity.CancellationDuration,

        // the rest ...
    };


    private static readonly Func<MeetingRoomCulture, MeetingRoomCultureListViewModel>
    MeetingRoomCultureToListViewModelFunc = MeetingRoomCultureToListViewModel.Compile();

    public static MeetingRoomCultureListViewModel ToMeetingRoomCultureListViewModel(
        this MeetingRoomCulture source) => MeetingRoomCultureToListViewModelFunc(source);

}

И, конечно, используйте выражение внутри LINQ.к запросам сущностей:

var ds = _dbContext.MeetingRoomCultures // no tracking, no includes
    .CultureFilter(CurrentCulture)
    .Select(Selectors.MeetingRoomCultureToListViewModel) // <--
    .ToDataSourceResult(request);

Как уже упоминалось в комментариях, сторонние библиотеки, такие как AutoMapper , могут значительно упростить преобразования из / в модели сущностей.

...