【问题标题】:Selecting & Updating Many-To-Many in Entity Framework 4在 Entity Framework 4 中选择和更新多对多
【发布时间】:2011-10-15 19:29:09
【问题描述】:

我对 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 == 某个值的国家/地区列表。

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

非常感谢。

【问题讨论】:

    标签: entity-framework entity-framework-4


    【解决方案1】:

    首先,当我从我想要的模型中检索一个(或多个)资产时 获取与其关联的各个国家/地区。那时我会 希望能够将国家列表绑定到 IEnumerable。

    不确定我是否理解正确,但EntityCollection&lt;T&gt; 实现了IEnumerable&lt;T&gt;,所以你不需要做任何特别的事情,你可以在加载包括国家/地区在内的资产后使用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();
    }
    

    第二个选项没问题(从 SQL 的角度不确定它是否比第一个更好)因为AssetId 是主键,所以只能有一个资产。对于按其他标准进行查询 - 例如Asset.Name == "XYZ" - 您可以期望多个资产,我更喜欢第一个选项。第二次您必须将Select 替换为SelectMany,将SingleOrDefault 替换为ToList,并使用Distinct 过滤掉可能的重复国家/地区。 SQL 可能会更复杂。

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

    这比较棘手,因为您需要处理以下情况:1) 国家/地区已添加到资产中,2) 国家/地区已从资产中删除,3) 国家/地区已与资产相关。

    假设您有一个国家/地区 ID 列表 (IEnumerable&lt;int&gt; 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% 确定后面的代码是否能正常工作。

    【讨论】:

    • 优秀的 Slauma 感谢您的详细回答,我会试一试,让您知道我的进展情况。
    • @Cragly:我在您的第二个问题中添加了第二个查询选项。是的,让我特别知道编辑部分中的代码是否有效(如果你应该测试它):)
    • 抱歉耽搁了,但被困在别的事情上了!!刚刚尝试了两个版本,并且快到了。它们的唯一问题是,当我尝试创建一个新的 Country 对象以添加到 Asset 时,它的类型不正确。 Country 实体是一个纯 EF 对象,但与 Asset 关联的那些是 Assets.Country 类型,不会让我添加它。已经尝试了一些映射,但仍然无法让它打球。导航属性是不同类型的多对多关系是否属于这种情况?
    • @Cragly:我不知道。这是什么Assets.Country 类型?这是您提到的编译时错误还是运行时错误?我真的希望asset.Countries 是普通Country 实体的集合。如果您不知道出了什么问题,也许会提出一个新问题。
    • 只是为了让您知道这不是对象类型的问题,而是集合类型的问题。我将列表项更改为 EntityCollection,如stackoverflow.com/questions/2364676/… 概述的那样,一切都与您编辑的答案配合得很好。再次感谢并将问题标记为已回答。
    【解决方案2】:

    这里的具体问题是什么?你做不到吗?

    您要选择资产中的国家还是拥有特定资产的国家?

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

    【讨论】:

    • [Include] 属性?那是什么?
    • @Slauma 抱歉,这不正确,它仅适用于使用 RIA 服务的域服务。
    • 啊,我明白了,不知道域服务提供这个属性。
    猜你喜欢
    • 1970-01-01
    • 2023-04-07
    • 2012-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多