2011-10-15 99 views
4

enter image description here選擇與更新許多到許多實體框架4

我是相對較新的EF和具有上面它由一個資產和國家以下實體模型。一個資產可以屬於許多國家,因此與國家有多對多的關係(在數據庫中有一個連接表,兩個字段都是主鍵)。

我希望能夠做到以下幾點:

首先,當我檢索模型中的資產(或資產),我想各個國家,它的關聯。然後我希望能夠將國家列表綁定到IEnumerable。以這種方式檢索國家爲我提供了具有ToList()的擴展方法的國家對象的EntityCollection。因此,不知道如果我正在與這一個正確的道路走下去。這裏是我的GETALL方法:

public IEnumerable<Asset> GetAll() 
{ 
    using (var context = CreateAssetContext()) 
    { 
     var assetEntities = context.Assets.Include("Countries").ToList(); 
     return AssetMapper.FromEntityObjects(assetEntities); 
    } 
} 

其次我希望能夠選擇在由assetid ==某個值的國家名單。

最後,我希望能夠更新給定資產的國家列表。

非常感謝。

回答

6

首先,當我從模型中檢索資產(或資產)時,我想要 獲取與其關聯的相應國家/地區。然後我會 喜歡能夠將國家列表綁定到IEnumerable。

不知道如果我的理解是正確的,但EntityCollection<T>實現IEnumerable<T>,所以你沒有做什麼特別的,你只可以使用Asset.Countries已裝入資產,包括國家之後。

其次,我希望能夠選擇一個國家的列表,其中AssetId = ==某些值。

using (var context = CreateAssetContext()) 
{ 
    var countries = context.Countries 
     .Where(c => c.Assets.Any(a => a.AssetId == givenAssetId)) 
     .ToList(); 
} 

或者:

using (var context = CreateAssetContext()) 
{ 
    var countries = context.Assets 
     .Where(a => a.AssetId == givenAssetId) 
     .Select(a => a.Countries) 
     .SingleOrDefault(); 
} 

第二個選項是OK(不知道這是不是從SQL觀點一批好),因爲AssetId是主鍵,因此只能有一個資產。對於其他條件的查詢 - 例如Asset.Name == "XYZ" - 您可以預期多個資產,我寧願選擇第一個選項。第二,你必須用SelectManySingleOrDefaultSelect替換成ToList,並使用Distinct來過濾掉可能出現的重複國家。 SQL可能會更復雜。

最後,我希望能夠更新給定 資產的國家/地區列表。

這樣比較棘手,因爲您需要處理以下情況:1)國家已被添加到資產中,2)國家已從資產中刪除,3)國家已與資產相關。

假設你有一個國家的IDS(IEnumerable<int> countryIds)列表,並要涉及這些國家給定的資產:

using (var context = CreateAssetContext()) 
{ 
    var asset = context.Assets.Include("Countries") 
     .Where(a => a.AssetId == givenAssetId) 
     .SingleOrDefault(); 

    if (asset != null) 
    { 
     foreach (var country in asset.Countries.ToList()) 
     { 
      // Check if existing country is one of the countries in id list: 
      if (!countryIds.Contains(country.Id)) 
      { 
       // Relationship to Country has been deleted 
       // Remove from asset's country collection 
       asset.Countries.Remove(country); 
      } 
     } 
     foreach (var id in countryIds) 
     { 
      // Check if country with id is already assigned to asset: 
      if (!asset.Countries.Any(c => c.CountryId == id)) 
      { 
       // No: 
       // Then create "stub" object with id and attach to context 
       var country = new Country { CountryId = id }; 
       context.Countries.Attach(country); 
       // Then add to the asset's country collection 
       asset.Countries.Add(country); 
      } 
      // Yes: Do nothing 
     } 
     context.SaveChanges(); 
    } 
} 

編輯

對於第二往返的價格向數據庫,你可以使用這個更簡單的代碼:

using (var context = CreateAssetContext()) 
{ 
    var asset = context.Assets.Include("Countries") 
     .Where(a => a.AssetId == givenAssetId) 
     .SingleOrDefault(); 

    if (asset != null) 
    { 
     // second DB roundtrip 
     var countries = context.Countries 
      .Where(c => countryIds.Contains(c.CountryId)) 
      .ToList(); 

     asset.Countries = countries; 

     context.SaveChanges(); 
    } 
} 

EF的變化檢測應該能夠識別哪個國家已經從資產的國家列表中添加或刪除。如果後面的代碼能正常工作,我不是100%確定的。

+0

非常好的Slauma謝謝你的詳細解答,我會試一試,讓你知道我是怎麼做到的。 – Cragly

+0

@Cragly:我已經爲第二個問題添加了第二個查詢選項。是的,讓我特別知道,如果編輯部分中的代碼工作(如果你應該測試它):) – Slauma

+0

對不起,延遲但被卡在別的東西!剛剛嘗試過兩種版本,並且差不多在那裏。他們兩個人唯一的問題是,當我嘗試創建一個新的Country對象來添加到資源時,它的類型不正確。國家實體是一個純粹的EF對象,但與資產相關的是Assets.Country類型,不會讓我添加它。已經有了一些映射,但仍然不能讓它玩球。對於導航屬性是不同類型的多對多關係,情況如何? – Cragly

0

這裏的具體問題是什麼?你不能這樣做嗎?

是否要選擇資產中的國家或具有特定資產的國家/地區?

更新它的簡單,只是改變的東西,然後context.SaveChanges()將提交到數據庫。

+0

'[Include]'屬性?那是什麼? – Slauma

+0

@Slauma對不起,這僅適用於使用RIA服務的域服務。 – GriffinHeart

+0

啊,我知道,不知道域服務提供這個屬性。 – Slauma