2015-12-21 222 views
0

我的任務是將篩選機制添加到結果集中。我理解使用Linq中的Where子句進行過濾的基本概念,但是這有一個更好的方法來做到這一點,對吧?使用Linq查詢進行VB.NET篩選

場景: 我在結果集上有5個可過濾的列。我必須在任何時候考慮這5個濾波器的所有變化。這意味着我必須手動輸入一個具有120種不同變體的If/ElseIf語句!

下面是事情進展的一般方法,我只是簡單地問:有沒有更好,更快的方法來做到這一點?

的過濾器

ByVal SearchMxMID As Integer, 
ByVal SearchProfile As Integer, 
ByVal SearchCZ As String, 
ByVal SearchTerm As Integer, 
ByVal SearchFwMth As Integer 

的If語句的過程

If SearchMxMID = 0 
And SearchProfile = 0 
And SearchCZ = "All" 
And SearchTerm = 0 
And SearchFwMth = 0 Then 

Dim queryMM = (From a In DBPricingContext.tbl_Matrix_Margins 
       Where a.CompanyID = CInt(sCompanyID) 
       Order By a.Profile 
       Select a) 
Return New StoreResult(queryMM) 

ElseIf SearchMxMID > 0 
And SearchProfile = 0 
And SearchCZ = "All" 
And SearchTerm = 0 
And SearchFwMth = 0 Then 
Dim queryMM = (From a In DBPricingContext.tbl_Matrix_Margins 
       Where a.CompanyID = CInt(sCompanyID) And a.MarGroupID = SearchMxMID 
       Order By a.Profile 
       Select a) 
Return New StoreResult(queryMM) 

ETC ETC ETC

120總次數爲這5個過濾器的每個組合(無論它們是否是空白或有價值)。有沒有更快的方法,我可以做到這一點,可能在一個單一的Linq查詢?

If SearchMxMID > 0 Then a.MarGroupID = SearchMxMID Else DO NOT APPLY WHERE CLAUSE 

???

+0

**場景:我的結果集上有5個可篩選的列。我必須在任何時候考慮這5個濾波器的所有變化。這意味着我必須用120種不同的變體手動輸入一個If/ElseIf語句!**不,你不知道。只使用相關的東西 - 是的,你的where塊有五個IF語句,但你只需要插入值。我一直在SQL中這樣做,所以它應該也可以在Linq中使用。我在SQL中使用IN,在Linq中有類似的功能。 – Tim

回答

0

Linq查詢是可鏈接的。你可以根據你的情況簡單地擁有一個,如果它是真的,那麼在另一個地方添加另一個。即(在C#中,但應該很容易遵循任何.NET編碼器 - 或者你可以使用Telerik的代碼轉換器和修改代碼位):

string country = "Germany"; 
string city = "Berlin"; 
int? productId = 3; 

var data = db.Customers; 

var result = data.AsQueryable(); 
if (!string.IsNullOrEmpty(country)) 
{ 
    result = result.Where(r => r.Country == country); 
} 
if (!string.IsNullOrEmpty(city)) 
{ 
    result = result.Where(r => r.City == city); 
} 
if (productId.HasValue) 
{ 
    result = result 
    .Where(r => 
    r.Orders.Any(o => 
     o.OrderDetails 
     .Any(od => od.ProductID == productId.Value))); 

} 

另一種方法是就是使用一個NULL或。 ..方法。即:

Private Sub Main() 
    Dim country As String = "" '"Brazil" 
    Dim city As String = "" '"Sao Paulo" 
    Dim orderDate As System.Nullable(Of DateTime) = Nothing 'new DateTime(1996,8,28); 

    Dim data = Orders.Where(Function(c) _ 
    String.IsNullOrEmpty(country) OrElse c.ShipCountry.StartsWith(country)) _ 
    .Where(Function(c) String.IsNullOrEmpty(city) OrElse c.ShipCity.StartsWith(city)) _ 
    .Where(Function(c) orderDate Is Nothing OrElse c.OrderDate = orderDate) _ 
    .Select(Function(c) New Order() With { _ 
     .OrderId = c.OrderID, _ 
     .CustomerId = c.CustomerID, _ 
     .OrderDate = c.OrderDate, _ 
     .ShipCountry = c.ShipCountry, _ 
     .ShipCity = c.ShipCity _ 
    }) 

    Dim f As New Form() With { .Text = "Query Results" } 
    Dim dgv As New DataGridView() With { .Dock = DockStyle.Fill } 
    f.Controls.Add(dgv) 

    dgv.DataSource = data.ToList() 
    f.ShowDialog() 
End Sub 

Public Class Order 
    Public Property OrderId() As Integer 
     Get 
      Return m_OrderId 
     End Get 
     Set 
      m_OrderId = Value 
     End Set 
    End Property 
    Private m_OrderId As Integer 
    Public Property OrderDate() As System.Nullable(Of DateTime) 
     Get 
      Return m_OrderDate 
     End Get 
     Set 
      m_OrderDate = Value 
     End Set 
    End Property 
    Private m_OrderDate As System.Nullable(Of DateTime) 
    Public Property CustomerId() As String 
     Get 
      Return m_CustomerId 
     End Get 
     Set 
      m_CustomerId = Value 
     End Set 
    End Property 
    Private m_CustomerId As String 
    Public Property ShipCountry() As String 
     Get 
      Return m_ShipCountry 
     End Get 
     Set 
      m_ShipCountry = Value 
     End Set 
    End Property 
    Private m_ShipCountry As String 
    Public Property ShipCity() As String 
     Get 
      Return m_ShipCity 
     End Get 
     Set 
      m_ShipCity = Value 
     End Set 
    End Property 
    Private m_ShipCity As String 
End Class 

注意:代碼是Linq To SQL代碼。使用EF這將不被支持,你需要使用前一種方法。

0

您可以鏈Where條款並動態構建您的查詢是這樣的:

Dim query = DBPricingContext.tbl_Matrix_Margins.AsQueryable() 

If compID > 0 Then 
    query = query.Where(Function(a) a.CompanyID = compID) 
End If 
If SearchMxMID > 0 Then 
    query = query.Where(Function(a) a.MarGroupID = SearchMxMID) 
End If 
... 

query = query.OrderBy(Function(a) a.Profile) 

請注意,我使用的擴展方法的語法和lambda表達式,而不是專門的LINQ查詢語法。如果您只是選擇參數a本身,則不需要致電Select

如果您使用的是LINQ到對象而不是LINQ到some_database,請將AsQueryable()替換爲AsEnumerable()

0

您還可以使用LINQ語法按順序編寫查詢。

Dim TempQuery = (From a In DbPricingContext.tbl_Matrix_Margins 
       Where a.CompanyID = CInt(sCompanyID) 
       Select a) 

If SearchMxMID > 0 Then 
    TempQuery = (From a In TempQuery 
       Where a.MarGroupID = SearchMxMID 
       Select a) 
End If 

'... Add your other conditions in here... 

Return New StoreResult(From a In TempQuery Order By a.Profile Select a) 
0

使用邏輯一樣以同樣的方式SearchValue = DefaultValue OrElse SearchValue = PropertyValue

Dim result = DBPricingContext.tbl_Matrix_Margins. 
       Where(Function(a) a.CompanyID = CInt(sCompanyID)). 
       Where(Function(a) SearchMxMID = 0 OrElse a.MarGroupID = SearchMxMID) 

並添加其他搜索條件。
它將如果SearchMxMID = 0返回所有行和返回,如果SearchMxMID <> 0

爲了精確結果,我將用Nullable

Where(Function(a) SearchMxMID.HasValue = False OrElse a.MarGroupID = SearchMxMID.Value) 
0

您可以實現的規範模式只匹配的行。像這樣的:

Sub Main() 
     Dim someList As New List(Of SomeClass) 

     Dim now As DateTime = DateTime.Now 

     someList.Add(New SomeClass() With {.Id = 1, .Title = "001", .EntryDate = now}) 
     someList.Add(New SomeClass() With {.Id = 2, .Title = "002", .EntryDate = now.AddSeconds(10)}) 
     someList.Add(New SomeClass() With {.Id = 3, .Title = "003", .EntryDate = now.AddSeconds(20)}) 

     Dim idParam As Integer = 1 
     Dim titleParam As String = "" '"001" 
     Dim dateParam As DateTime = now 



     ' first approach, one selector 
     Dim selector As Func(Of SomeClass, Boolean) = Function(item) 
                  With item 
                   Return ((idParam <= 0) OrElse (.Id = idParam)) AndAlso 
                    ((String.IsNullOrEmpty(titleParam)) OrElse (.Title = titleParam)) AndAlso 
                    ((dateParam.CompareTo(DateTime.MinValue) = 0) OrElse (.EntryDate = dateParam)) 
                  End With 
                 End Function 



     Dim list = From o In someList Where selector(o) Select o 

     For Each o In list 
      Console.WriteLine(o) 
     Next 



     ' second approach, one selector per parameter 
     Dim selectorId As Func(Of SomeClass, Boolean) = Function(item) 
                  Return ((idParam <= 0) OrElse (item.Id = idParam)) 
                 End Function 


     Dim selectorTitle As Func(Of SomeClass, Boolean) = Function(item) 
                   Return ((String.IsNullOrEmpty(titleParam)) OrElse (item.Title = titleParam)) 
                  End Function 


     Dim selectorEntryDate As Func(Of SomeClass, Boolean) = Function(item) 
                    Return ((dateParam.CompareTo(DateTime.MinValue) = 0) OrElse (item.EntryDate = dateParam)) 
                   End Function 

     Dim list2 = From o In someList 
        Where 
        selectorId(o) AndAlso 
        selectorTitle(o) AndAlso 
        selectorEntryDate(o) 
        Select o 

     For Each o In list2 
      Console.WriteLine(o) 
     Next 

     Console.ReadLine() 
    End Sub 

    Public Class SomeClass 
     Public Property Id As Integer 
     Public Property Title As String 
     Public Property EntryDate As DateTime 

     Public Overrides Function ToString() As String 
      Return String.Format("Id:{0} Title:{1} EntryDate:{2}", Id, Title, EntryDate) 
     End Function 
    End Class 

希望這個例子能幫助你一點。