Выбор и обновление «многие ко многим» в Entity Framework 4 - PullRequest
4 голосов
/ 15 октября 2011

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 ]

6 голосов
/ 16 октября 2011

Во-первых, когда я получаю актив (или активы) из модели, я хочу получить соответствующие страны, с которыми он связан.Затем я хотел бы иметь возможность привязать список стран к 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();
}

Второй вариант в порядке (не уверен, что он лучше, чем первый с точки зрения SQL), поскольку AssetId является первичным ключом, поэтомуможет быть только один актив.Для запросов по другим критериям, например Asset.Name == "XYZ", где можно ожидать более одного актива, я бы предпочел первый вариант.Для второго вам пришлось заменить Select на SelectMany и SingleOrDefault на ToList и использовать Distinct, чтобы отфильтровать возможные дублированные страны.SQL, вероятно, будет более сложным.

Наконец, я хочу иметь возможность обновить список стран для данного Актива.

Это сложнее, потому что вам нужночтобы разобраться со случаями: 1) страна была добавлена ​​к активу, 2) страна была удалена из актива, 3) страна уже связана с активом.

Скажем, у вас есть список идентификаторов страны (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 голосов
/ 15 октября 2011

Какой конкретный вопрос здесь?Разве вы не можете этого сделать?

хотите ли вы выбрать страны в активе или страны, которые имеют определенный актив?

, чтобы обновить его простой, просто измените материал, а затемcontext.SaveChanges() передаст в базу данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...