2011-10-15 98 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