2014-06-07 65 views
2

我有一個Address模型(簡體)完全執行......提高LINQ查詢,以便它在數據庫

public class Address 
{ 
    public int AddressId { get; set; } 
    public string City { get; set; } 
} 

...這包含一組Addresses一個DbContext派生類:

public DbSet<Address> Addresses { get; set; } 

然後,我有這個疑問這是爲了獲取一個或沒有address_context是我的數據庫上下文類的一個實例):

public Address GetAddress(string city, int addressId) 
{ 
    Address address = null; 

    // this is a database query 
    var addresses = _context.Addresses.Where(a => a.City == city).ToList(); 

    // the rest queries in memory 
    if (addresses.Count <= 1) 
     address = addresses.FirstOrDefault(); 
    else 
    { 
     address = addresses.FirstOrDefault(a => a.AddressId == addressId); 
     if (address == null) 
      address = addresses.FirstOrDefault(); 
    } 

    return address; 
} 

該查詢有點奇怪。的邏輯是簡單地:

  • 如果只有一個(或沒有)在與被請求的city藉此地址作爲結果的數據庫的表地址。
  • 如果有多個地址,請求的city更喜歡具有給定addressId的地址。如果沒有結果地址有這個addressId只是第一個。

令人不安的是,在.ToList()通話可能加載了大量的地址到內存中,我不感興趣。最後,我只過濾加載地址中的一個在內存作爲最終結果。

有沒有辦法重寫這個查詢(與LINQ到實體),以便它完全在數據庫中運行並返回一個或沒有地址(只有一個數據庫往返)?

回答

5

你的邏輯可以被解釋爲喜歡給定ID的地址,如果沒有匹配的話,根本就不會選擇任何東西。您的查詢不會強制執行該案件的任何訂單。

var addressesInCity = _context.Addresses.Where(a => a.City == city); 
var addrByID = addressesInCity.Where(a => a.AddressId == addressId); 
var anyAddr = addressesInCity.Take(1); 

你可以用兩個查詢寫:

addrByID.FirstOrDefault() ?? anyAddr.FirstOrDefault(); 

您可以將那些到一個查詢:

addrByID.Select(a => new { Priority = 1, a }) 
.Concat(anyAddr.Select(a => new { Priority = 2, a })) 
.OrderBy(x => x.Priority) 
.Take(1) 
.Select(x => x.a) 
.FirstOrDefault(); 

這樣可以節省往返和SQL Server通過理解排序不變。它將高效運行。不是必然比第一種形式更有效,但沒有明顯更差。

請注意,由UNION (ALL)返回的結果順序未定義。我們需要通過引入Priority字段來強制執行訂單。

+0

只需注意。有一些版本的EF在這一點上有一個錯誤。 – Aron

+0

EF從未停下來讓人失望。 L2S可以做到這一點,而現在EF正在積極開發中,現在已經廢棄了5年。 – usr

+0

不要讓我開始使用L2S。它甚至不能處理'char'或'varchar'。至少他們有EF的補丁的新版本。當他們上次更新L2S時告訴我。 – Aron