У меня проблема с вытягиванием только тех столбцов, которые указаны в запросе при представлении 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]