У меня проблемы с довольно сложным запросом Linq, и мне нужен совет. Это включает в себя синтаксис VB, поэтому мне нужны конкретные ответы для этой платформы, так как у меня много проблем с переводом синтаксиса C # в VB.
Мне нужно объединить две основные таблицы и отфильтровать результаты по элементам в веб-форме ASP.NET. Эти фильтры создаются на лету, поэтому мне нужно использовать множество расширений для фильтрации запросов. Я хочу выполнить запрос с максимально оптимизированным SQL.
Сначала я делаю простое соединение между TW_Sites и TW_Investigators. Тогда есть две вложенные таблицы, которые участвуют. TW_InvestigatorToArea и TW_InvestigatorToDisease. Хотя большинство предложений where работают нормально, я обнаружил проблему с производительностью, которая сейчас не будет проблемой, но будет проблемой по мере увеличения таблицы.
Массивы DiseaseCategories и DiseaseAreas будут результатом результата CheckBoxList.
Protected Sub LoadResults()
' Get Dictionary of Filters
Dim FilterDictionary As OrderedDictionary = Session.Item("InvestigatorFilterDictionary")
' Initialize LinqToSql
Dim LinqDbHandler As TrialWatchDC = New TrialWatchDC(WebConfigurationManager.ConnectionStrings("DataSourceName").ConnectionString)
' Create List of Categories to Filter By
Dim DiseaseCategories() As Integer = {1, 2, 3, 4, 5, 6, 11, 22, 361, 77, 82, 99, 400}
Dim CategorySubQuery = From ic In LinqDbHandler.TW_InvestigatorsToDiseases Where DiseaseCategories.Contains(ic.DiseaseCategoryID) Select ic.InvestigatorID Distinct
' Dim CategorySubArray = CategorySubQuery.ToArray()
' Create List of Areas to Filter By
Dim AreaCategories() As Integer = {17, 1, 3, 5}
Dim AreaSubQuery = From ic In LinqDbHandler.TW_InvestigatorsToAreas Where AreaCategories.Contains(ic.AreaID) Select ic.InvestigatorID Distinct
Dim AreaSubArray = AreaSubQuery.ToArray()
Dim dc As DbCommand
Dim ThisQuery = From Site In LinqDbHandler.TW_Sites _
Join Investigator In LinqDbHandler.TW_Investigators On Site.TrialSiteID Equals Investigator.TrialSiteID _
Join SiteType In LinqDbHandler.TW_SiteTypes On Site.SiteTypeID Equals SiteType.SiteTypeID _
Order By Site.ResearchCenterName, Investigator.InvestigatorName
Select New With {.TrialSiteID = Site.TrialSiteID, _
.InvestigatorID = Investigator.InvestigatorID, _
.ResearchCenterName = Site.ResearchCenterName, _
.SiteTypeID = SiteType.SiteTypeID, _
.TypeLabel = SiteType.TypeLabel, _
.CenterState = Site.CenterState, _
.CenterCountry = Site.CenterCountry, _
.ContactName = Site.ContactName, _
.ContactEMail = Site.ContactEMail, _
.ContactPhone = Site.ContactPhone, _
.IsRcppSubscriber = Site.IsRcppSubscriber, _
.InvestigatorName = Investigator.InvestigatorName, _
.IsPublicationSubscriber = Investigator.IsPublicationSubscriber, _
.HasPhase01 = Investigator.HasPhase01, _
.HasPhase02 = Investigator.HasPhase02, _
.HasPhase03 = Investigator.HasPhase03, _
.HasPhase04 = Investigator.HasPhase04, _
.AreaList = String.Join(",", (From ia In LinqDbHandler.TW_InvestigatorsToAreas Join a In LinqDbHandler.Disease_Areas On ia.AreaID Equals a.Area_Number Where ia.InvestigatorID = Investigator.InvestigatorID Order By a.Area_Name Select a.Area_Name Distinct).ToArray()), _
.CategoryList = String.Join(",", (From id In LinqDbHandler.TW_InvestigatorsToDiseases Join d In LinqDbHandler.Disease_Categories On id.DiseaseCategoryID Equals d.Category_Number Where id.InvestigatorID = Investigator.InvestigatorID Order By d.Category_Name Select d.Category_Name Distinct).ToArray())}
If Not String.IsNullOrEmpty(FilterDictionary.Item("CountryFilter")) Then
ThisQuery = ThisQuery.Where(Function(s) s.CenterCountry = FilterDictionary.Item("CountryFilter").ToString())
End If
If Not String.IsNullOrEmpty(FilterDictionary.Item("SiteType")) Then
ThisQuery = ThisQuery.Where(Function(s) s.SiteTypeID = Convert.ToInt32(FilterDictionary.Item("SiteType")))
End If
dc = LinqDbHandler.GetCommand(ThisQuery)
If Not String.IsNullOrEmpty(FilterDictionary.Item("StateFilter")) Then
ThisQuery = ThisQuery.Where(Function(s) s.CenterState = FilterDictionary.Item("StateFilter").ToString())
End If
dc = LinqDbHandler.GetCommand(ThisQuery)
ThisQuery = ThisQuery.Where(Function(i) CategorySubArray.Contains(i.InvestigatorID))
ThisQuery = ThisQuery.Where(Function(i) AreaSubArray.Contains(i.InvestigatorID))
dc = LinqDbHandler.GetCommand(ThisQuery)
Trace.Warn("Command", dc.CommandText)
For Each dcp As SqlParameter In dc.Parameters
Trace.Warn(dcp.ParameterName.ToString(), dcp.Value.ToString())
Next
Dim ThisLinqResult = ThisQuery
InvestigatorResultGrid.DataSource = ThisLinqResult
InvestigatorResultGrid.DataBind()
End Sub
Большая проблема, когда вы смотрите на код, в основном я сначала преобразовываю отфильтрованные подзапросы в массив, а затем передаю его в код SQL. В результате получается SQL-запрос с большим количеством параметров, как показано ниже.
SELECT [t0].[TrialSiteID], [t1].[InvestigatorID], [t0].[ResearchCenterName], [t2].[SiteTypeID], [t2].[TypeLabel], [t0].[CenterState], [t0].[CenterCountry], [t0].[ContactName],
[t0].[ContactEMail], [t0].[ContactPhone], [t0].[IsRcppSubscriber], [t1].[InvestigatorName], [t1].[IsPublicationSubscriber], [t1].[HasPhase01], [t1].[HasPhase02], [t1].[HasPhase03],
[t1].[HasPhase04]
FROM [dbo].[TW_Sites] AS [t0]
INNER JOIN [dbo].[TW_Investigators] AS [t1] ON [t0].[TrialSiteID] = [t1].[TrialSiteID]
INNER JOIN [dbo].[TW_SiteTypes] AS [t2] ON [t0].[SiteTypeID] = ([t2].[SiteTypeID])
WHERE ([t1].[InvestigatorID] IN (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18, @p19, @p20, @p21, @p22, @p23, @p24, @p25, @p26, @p27,
@p28, @p29, @p30, @p31, @p32, @p33, @p34, @p35, @p36, @p37, @p38, @p39, @p40, @p41, @p42, @p43, @p44, @p45, @p46, @p47, @p48, @p49, @p50, @p51, @p52, @p53, @p54, @p55, @p56, @p57, @p58,
@p59, @p60, @p61, @p62, @p63, @p64, @p65, @p66, @p67, @p68, @p69, @p70, @p71, @p72, @p73, @p74, @p75, @p76, @p77, @p78, @p79, @p80, @p81, @p82, @p83, @p84, @p85, @p86, @p87, @p88, @p89,
@p90, @p91, @p92, @p93, @p94, @p95, @p96, @p97, @p98, @p99, @p100, @p101, @p102, @p103, @p104, @p105, @p106, @p107, @p108, @p109, @p110, @p111, @p112, @p113, @p114, @p115)) AND
([t1].[InvestigatorID] IN (@p116, @p117, @p118, @p119, @p120, @p121, @p122, @p123, @p124, @p125, @p126, @p127, @p128, @p129, @p130, @p131, @p132, @p133, @p134, @p135, @p136, @p137, @p138,
@p139, @p140, @p141, @p142, @p143, @p144, @p145, @p146, @p147, @p148, @p149, @p150, @p151, @p152, @p153, @p154, @p155, @p156, @p157, @p158, @p159, @p160, @p161, @p162, @p163, @p164, @p165,
@p166, @p167, @p168, @p169, @p170, @p171, @p172, @p173, @p174, @p175, @p176, @p177, @p178, @p179, @p180, @p181, @p182, @p183, @p184, @p185, @p186, @p187, @p188, @p189, @p190, @p191, @p192,
@p193, @p194, @p195, @p196, @p197, @p198, @p199, @p200, @p201, @p202, @p203, @p204, @p205))
ORDER BY [t0].[ResearchCenterName], [t1].[InvestigatorName]
Это много параметров и будет только хуже. По сути, вместо небольшого предложения IN с условиями у меня есть гораздо большее предложение IN с идентификаторами следователя.
Итак, я пытаюсь понять, как вместо того, чтобы преобразовывать запросы Area и Category в массив и затем добавлять их к третьему запросу, чтобы запросы включали вложенные таблицы и выполняли прямой поиск для соответствующих идентификаторов областей и категорий. Мне нужно иметь возможность использовать синтаксис предиката, так как области и категории представляют собой две вложенные таблицы, и иногда обе или ни одна не будут включены. Я знаю, что это связано с предикатами .Any (), .Join () или .Where (), я просто не знаю, как заставить его работать.
По сути, я пытаюсь изменить SQL, чтобы он выглядел примерно так.
WHERE ([t1].[InvestigatorID] IN (SELECT InvestigatorID FROM TW_InvestigatorsToAreas
WHERE DiseaseCategoryID IN (@p101, @p102, @p103)))
Буду признателен за любую помощь или руководство.