选择&在实体框架4中更新多对多

时间:2011-10-15 19:29:09

标签: entity-framework entity-framework-4

enter image description here

我是EF的新手,并且上面有以下实体模型,其中包含资产和国家/地区。资产可以属于许多国家/地区,因此与国家/地区具有多对多关系(数据库中有一个连接表,两个字段都作为主键)。

我希望能够做到以下几点:

首先,当我从模型中检索资产(或资产)时,我希望获得与其关联的各个国家/地区。然后,我希望能够将国家/地区列表绑定到IEnumerable。以这种方式检索国家为我提供了一个国家对象的EntityCollection,它具有ToList()的扩展方法。因此不确定如果我正沿着正确的大道走下去。这是我的GetAll方法:

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

其次,我希望能够选择AssetId ==某个值的国家/地区列表。

最后,我希望能够更新给定资产的国家/地区列表。

非常感谢。

2 个答案:

答案 0 :(得分: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" - 您可以期待多个资产我更喜欢第一个选项。对于第二个,您必须按Select替换SelectManySingleOrDefault替换ToList,并使用Distinct过滤掉可能重复的国家/地区。 SQL可能会更复杂。

  

最后,我希望能够更新给定的国家/地区列表   资产。

这更棘手,因为您需要处理案例:1)国家已添加到资产,2)国家已从资产中删除,3)已与资产相关的国家。

假设您有国家/地区ID(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%肯定。

答案 1 :(得分:0)

具体问题是什么?你不能那样做吗?

是否要选择资产中的国家/地区或拥有特定资产的国家/地区?

更新其简单,只需更改内容,然后context.SaveChanges()将提交到数据库。