Присоединение к группе объектов без вызова всех столбцов в таблицах - PullRequest
0 голосов
/ 11 апреля 2019

У меня проблема с вытягиванием только тех столбцов, которые указаны в запросе при представлении GroupJoin. Для простоты я сузил код до самой проблемы, но есть много других соединений. Из-за сложности полного оператора я бы очень предпочел не использовать Union, где! = Null to == null, поскольку приходится писать в основном идентичный код снова и снова ...

При стандартном соединении:

var ret = await _ICMDbContext.CaseHeader
                .Join(_ICMDbContext.Employee, ch => ch.EmployeeIdRecFkey, emp => emp.IdRec, (ch, emp) => new { ch, emp })
                .Where(x=> x.ch.IsDeleted.Equals(false))
                .Select(x => new CaseHeaderGridModel()
                {
                    IdRec = x.ch.IdRec,
                    CaseCategoryId = x.ch.CaseCategoryId,
                    CreateDttm = x.ch.CreateDttm,
                    CreateUser = x.ch.CreateUser,
                    EmployeeIdRecFkey = x.ch.EmployeeIdRecFkey,
                    EmployeeName = x.ch.EmployeeName,
                    EmployeeClientOrgIdRecFkey = x.ch.EmployeeClientOrgIdRecFkey,
                    CaseEmployerName = x.ch.EmployerName,
                    OccurrenceTreatmentState = x.ch.EventState,
                    CallItemAssignedUserObjectId = x.ch.CallItemAssignedUserObjectId,
                    CallItemOriginatorUserObjectId = x.ch.CallItemOriginatorUserObjectId.Value,
                    CaseItemLocator = x.ch.CaseItemLocator,
                    CaseStatusId = x.ch.CaseStatusId,
                    RequiredLanguageId = x.ch.RequiredLanguageId,
                    NameFirst = x.emp.NameFirst,
                    NameMiddle = x.emp.NameMiddle,
                    NameLast = x.emp.NameLast
                })                                    
                .ToListAsync();

Генерируется ожидаемый SQL только с запрошенными столбцами:

SELECT [ch].[IdRec], [ch].[CaseCategoryId], [ch].[CreateDttm], [ch].[CreateUser], [ch].[EmployeeIdRecFkey], [ch].[EmployeeName]
, [ch].[EmployeeClientOrgIdRecFkey], [ch].[EmployerName] AS [CaseEmployerName], [ch].[EventState] AS [OccurrenceTreatmentState]
, [ch].[CallItemAssignedUserObjectId], [ch].[CallItemOriginatorUserObjectId], [ch].[CaseItemLocator], [ch].[CaseStatusId]
, [ch].[RequiredLanguageId], [emp].[NameFirst], [emp].[NameMiddle], [emp].[NameLast]
FROM [CaseHeader] AS [ch]
INNER JOIN [Employee] AS [emp] ON [ch].[EmployeeIdRecFkey] = [emp].[IdRec]
WHERE [ch].[IsDeleted] = 0

Однако, когда я превращаю это в GroupJoin (Возможно, нет связанного сотрудника, нужен левый):

var ret = await _ICMDbContext.CaseHeader
.GroupJoin(_ICMDbContext.Employee, ch => ch.EmployeeIdRecFkey, emp => emp.IdRec, (ch, emp) => new { ch, emp = emp.FirstOrDefault() })
.Where(x=> x.ch.IsDeleted.Equals(false))
.Select(x => new CaseHeaderGridModel()
{
    IdRec = x.ch.IdRec,
    CaseCategoryId = x.ch.CaseCategoryId,
    CreateDttm = x.ch.CreateDttm,
    CreateUser = x.ch.CreateUser,
    EmployeeIdRecFkey = x.ch.EmployeeIdRecFkey,
    EmployeeName = x.ch.EmployeeName,
    EmployeeClientOrgIdRecFkey = x.ch.EmployeeClientOrgIdRecFkey,
    CaseEmployerName = x.ch.EmployerName,
    OccurrenceTreatmentState = x.ch.EventState,
    CallItemAssignedUserObjectId = x.ch.CallItemAssignedUserObjectId,
    CallItemOriginatorUserObjectId = x.ch.CallItemOriginatorUserObjectId.Value,
    CaseItemLocator = x.ch.CaseItemLocator,
    CaseStatusId = x.ch.CaseStatusId,
    RequiredLanguageId = x.ch.RequiredLanguageId,
    NameFirst = x.emp.NameFirst,
    NameMiddle = x.emp.NameMiddle,
    NameLast = x.emp.NameLast
})                                    
.ToListAsync();

Я получаю каждый столбец из обеих таблиц (в действительности все таблицы)

SELECT [ch].[IdRec] AS [IdRec0], [ch].[AdditionalData], [ch].[BillToClientOrgIdRecFkey], [ch].[CallGroupLocator], [ch].[CallItemAssignedUserObjectId]
, [ch].[CallItemLocator], [ch].[CallItemOriginatorUserObjectId], [ch].[CallItemTypeId], [ch].[CallerName], [ch].[CallerOrganization], [ch].[CaseCategoryId]
, [ch].[CaseItemContacts], [ch].[CaseItemLocator], [ch].[CaseOutcomeWithIntervention_OutcomeId], [ch].[CaseOutcomeWithoutIntervention_OutcomeId]
, [ch].[CaseStatusId], [ch].[CaseWorkflowPhaseId], [ch].[ChangeData], [ch].[CreateDttm] AS [CreateDttm0], [ch].[CreateUser] AS [CreateUser0]
, [ch].[CurrentMedicalStatusCalc], [ch].[DateOfBirth], [ch].[EmployeeClientOrgIdRecFkey], [ch].[EmployeeIdRecFkey], [ch].[EmployeeName]
, [ch].[EmployeePhoneNumber], [ch].[EmployerName] AS [CaseEmployerName], [ch].[EventCity], [ch].[EventDateTime], [ch].[EventDateTimeQualifierId]
, [ch].[EventDescription], [ch].[EventElevatedAdvice], [ch].[EventGeographicDescription], [ch].[EventState] AS [OccurrenceTreatmentState], [ch].[GenderId]
, [ch].[GeneratedFromVoicemail], [ch].[HandednessId], [ch].[IsDeleted], [ch].[JobDutiesDescription], [ch].[JobPhysicalityClassificationId]
, [ch].[LocalClientOrgId], [ch].[LocaleId], [ch].[MedicalHistory], [ch].[NoteData], [ch].[PhoneCallerIdExt], [ch].[PhoneCallerIdNumber]
, [ch].[PhoneStatedCallBackExt], [ch].[PhoneStatedCallBackNumber], [ch].[RequiredLanguageId], [ch].[ServiceCategoryId], [ch].[ServiceOrgNotifiedDispositionId]
, [ch].[SysRowVersion], [ch].[SysTag], [ch].[ThirdPartyEmployer], [ch].[ThirdPartyEmployerIdRecFkey], [ch].[TimezoneId], [ch].[TreatmentCity]
, [ch].[TreatmentState], [ch].[UpdateDttm], [ch].[UpdateUser], [ch].[WorkDaysCalcLostTime], [ch].[WorkDaysCalcRestricted], [ch].[WorkScheduleDescription]
, [ch].[WorkdayDateEstimatedReturn], [ch].[WorkdayDateFirstMissed], [ch].[WorkdayDateFullReturn], [ch].[WorkdayDateRestrictedReturn], [ch].[WorkloadMetricValue]
, [emp].[IdRec], [emp].[AdditionalData], [emp].[ClientEmployeeIdentity], [emp].[CostCenter], [emp].[CreateDttm], [emp].[CreateUser], [emp].[DateOfBirth]
, [emp].[DispositionId], [emp].[EmploymentEndDate], [emp].[EmploymentStartDate], [emp].[ExternalReferenceEmployeeId], [emp].[ExternalReferenceEmployeeId_Source]
, [emp].[GenderId], [emp].[HandednessId], [emp].[IdRecParent], [emp].[IsDeleted], [emp].[JobPhysicalityClassificationId], [emp].[JobTitleId], [emp].[LanguageId]
, [emp].[LocalClientOrgId], [emp].[NameFirst], [emp].[NameFirstPreferred], [emp].[NameGenerationalTitleId], [emp].[NameLast], [emp].[NameMiddle]
, [emp].[NameProfessionalTitle], [emp].[NameTitleId], [emp].[NationalOrStateIdNumber], [emp].[PersonnelLocatorCode], [emp].[SysRowVersion], [emp].[SysTag]
, [emp].[ThirdPartyEmployerName], [emp].[ThirdPartyEmployerNameIdRecFkey], [emp].[UpdateDttm], [emp].[UpdateUser], [emp].[WorkerClassificationId]
FROM [CaseHeader] AS [ch]
LEFT JOIN [Employee] AS [emp] ON [ch].[EmployeeIdRecFkey] = [emp].[IdRec]
WHERE [ch].[IsDeleted] = 0
ORDER BY [ch].[EmployeeIdRecFkey]

Как указывалось выше, это на самом деле гораздо более сложный запрос, и в нем есть несколько GroupJoins - фактическое количество возвращаемых столбцов при использовании GroupJoins исчисляется сотнями, и наш набор данных довольно большой, поэтому это вызывает наш запрос может занять до 15-20 секунд, в то время как если я ограничу столбцы только тем, что запрашиваю, он вернется менее чем за секунду.

Есть ли способ обойти это с помощью GroupJoin (или другой способ получить левое соединение) или мне нужно объединиться и создать кучу ветвей?

Выбор CaseHeaderModel из контекста и последующее выполнение GroupJoin над моделью вместо контекста не изменяет сгенерированный SQL. Кажется, что GroupJoin действительно хочет захватить все столбцы.

Редактировать
Я попробовал приведенный ниже код, и, к сожалению, он по-прежнему тянет во всех столбцах:

var ret = _ICMDbContext.CaseHeader
                .GroupJoin(_ICMDbContext.Employee, ch => ch.EmployeeIdRecFkey, emp => emp.IdRec, (ch, emp) => new
                {
                    ch = new
                    {
                        ch.IdRec,
                        ch.CaseCategoryId,
                        ch.CaseStatusId,
                        ch.IsDeleted,
                        ch.CreateDttm,
                        ch.CreateUser,
                        ch.CallItemTypeId,
                        ch.EmployeeIdRecFkey,
                        ch.EmployeeName,
                        ch.EmployeeClientOrgIdRecFkey,
                        ch.EmployerName,
                        ch.EventState,
                        ch.CallItemAssignedUserObjectId,
                        ch.CallItemOriginatorUserObjectId,
                        ch.CaseItemLocator,
                        ch.RequiredLanguageId
                    }
                ,
                    emp = emp.Select(x => new
                    {
                        x.NameFirst,
                        x.NameMiddle,
                        x.NameLast
                    }).FirstOrDefault()
                })                    
                .Where(x=> x.ch.EmployeeIdRecFkey != null && x.ch.IsDeleted.Equals(false))
                .Select(x => new CaseHeaderGridModel()
                {
                    IdRec = x.ch.IdRec,
                    CaseCategoryId = x.ch.CaseCategoryId,
                    CreateDttm = TimeZoneConverter.GetConvertFromDateToDate(x.ch.CreateDttm, utcAdditionalData, loggedInUserTimeZoneAddlData).Value,
                    CreateDttmValue = TimeZoneConverter.GetConvertFromDateToDateFormattedTimeString(x.ch.CreateDttm, utcAdditionalData, loggedInUserTimeZoneAddlData),
                    CreateTimezoneShortName = TimeZoneConverter.GetTimeZoneShortName(x.ch.CreateDttm, loggedInUserTimeZoneAddlData),
                    CreateUser = x.ch.CreateUser,
                    CallItemTypeId = x.ch.CallItemTypeId.Value,
                    EmployeeIdRecFkey = x.ch.EmployeeIdRecFkey,
                    EmployeeName = x.ch.EmployeeName,
                    EmployeeClientOrgIdRecFkey = x.ch.EmployeeClientOrgIdRecFkey,
                    CaseEmployerName = x.ch.EmployerName,
                    OccurrenceTreatmentState = x.ch.EventState,
                    CallItemAssignedUserObjectId = x.ch.CallItemAssignedUserObjectId,
                    CallItemOriginatorUserObjectId = x.ch.CallItemOriginatorUserObjectId.Value,
                    CaseItemLocator = x.ch.CaseItemLocator,                       
                    RequiredLanguageId = x.ch.RequiredLanguageId,
                    NameFirst = x.emp.NameFirst,
                    NameMiddle = x.emp.NameMiddle,
                    NameLast = x.emp.NameLast,
                    CaseStatusId = x.ch.CaseStatusId,
                }).ToList();

Я получаю то же самое:

SELECT [ch].[IdRec] AS [IdRec0], [ch].[AdditionalData], [ch].[BillToClientOrgIdRecFkey], [ch].[CallGroupLocator], [ch].[CallItemAssignedUserObjectId]
, [ch].[CallItemLocator], [ch].[CallItemOriginatorUserObjectId], [ch].[CallItemTypeId], [ch].[CallerName], [ch].[CallerOrganization], [ch].[CaseCategoryId]
, [ch].[CaseItemContacts], [ch].[CaseItemLocator], [ch].[CaseOutcomeWithIntervention_OutcomeId], [ch].[CaseOutcomeWithoutIntervention_OutcomeId]
, [ch].[CaseStatusId], [ch].[CaseWorkflowPhaseId], [ch].[ChangeData], [ch].[CreateDttm], [ch].[CreateUser] AS [CreateUser0]
, [ch].[CurrentMedicalStatusCalc], [ch].[DateOfBirth], [ch].[EmployeeClientOrgIdRecFkey], [ch].[EmployeeIdRecFkey], [ch].[EmployeeName]
, [ch].[EmployeePhoneNumber], [ch].[EmployerName] AS [CaseEmployerName], [ch].[EventCity], [ch].[EventDateTime], [ch].[EventDateTimeQualifierId]
, [ch].[EventDescription], [ch].[EventElevatedAdvice], [ch].[EventGeographicDescription], [ch].[EventState] AS [OccurrenceTreatmentState], [ch].[GenderId]
, [ch].[GeneratedFromVoicemail], [ch].[HandednessId], [ch].[IsDeleted], [ch].[JobDutiesDescription], [ch].[JobPhysicalityClassificationId]
, [ch].[LocalClientOrgId], [ch].[LocaleId], [ch].[MedicalHistory], [ch].[NoteData], [ch].[PhoneCallerIdExt], [ch].[PhoneCallerIdNumber]
, [ch].[PhoneStatedCallBackExt], [ch].[PhoneStatedCallBackNumber], [ch].[RequiredLanguageId], [ch].[ServiceCategoryId]
, [ch].[ServiceOrgNotifiedDispositionId], [ch].[SysRowVersion], [ch].[SysTag], [ch].[ThirdPartyEmployer], [ch].[ThirdPartyEmployerIdRecFkey]
, [ch].[TimezoneId], [ch].[TreatmentCity], [ch].[TreatmentState], [ch].[UpdateDttm], [ch].[UpdateUser], [ch].[WorkDaysCalcLostTime]
, [ch].[WorkDaysCalcRestricted], [ch].[WorkScheduleDescription], [ch].[WorkdayDateEstimatedReturn], [ch].[WorkdayDateFirstMissed]
, [ch].[WorkdayDateFullReturn], [ch].[WorkdayDateRestrictedReturn], [ch].[WorkloadMetricValue], [emp].[IdRec], [emp].[AdditionalData]
, [emp].[ClientEmployeeIdentity], [emp].[CostCenter], [emp].[CreateDttm], [emp].[CreateUser], [emp].[DateOfBirth], [emp].[DispositionId]
, [emp].[EmploymentEndDate], [emp].[EmploymentStartDate], [emp].[ExternalReferenceEmployeeId], [emp].[ExternalReferenceEmployeeId_Source]
, [emp].[GenderId], [emp].[HandednessId], [emp].[IdRecParent], [emp].[IsDeleted], [emp].[JobPhysicalityClassificationId], [emp].[JobTitleId]
, [emp].[LanguageId], [emp].[LocalClientOrgId], [emp].[NameFirst], [emp].[NameFirstPreferred], [emp].[NameGenerationalTitleId], [emp].[NameLast]
, [emp].[NameMiddle], [emp].[NameProfessionalTitle], [emp].[NameTitleId], [emp].[NationalOrStateIdNumber], [emp].[PersonnelLocatorCode]
, [emp].[SysRowVersion], [emp].[SysTag], [emp].[ThirdPartyEmployerName], [emp].[ThirdPartyEmployerNameIdRecFkey], [emp].[UpdateDttm], [emp].[UpdateUser]
, [emp].[WorkerClassificationId]
FROM [CaseHeader] AS [ch]
LEFT JOIN [Employee] AS [emp] ON [ch].[EmployeeIdRecFkey] = [emp].[IdRec]
WHERE [ch].[EmployeeIdRecFkey] IS NOT NULL AND ([ch].[IsDeleted] = 0)
ORDER BY [ch].[EmployeeIdRecFkey]

1 Ответ

0 голосов
/ 11 апреля 2019

Проблема с неиспользованием SelectMany.Я не осознавал, что это необходимо, когда у меня всегда будет 1 матч, и использовал только левое соединение, чтобы скрыть нули.Я думал, что размещение FirstOrDefault () в GroupJoin сделает в основном то же самое.При добавлении SelectMany столбцы выбираются правильно.

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