Отслеживание изменений ядра Entity Framework

Помогите, пожалуйста, понять странное поведение Entity Framework Core v2.2.2. У меня есть класс Country, который содержит набор регионов, каждый регион ссылается на своего владельца - страну, а также регион может содержать набор субрегионов, каждый субрегион ссылается на свой SuperiorRegion .

См. UML-диаграмму ниже. Модель домена

А вот код:

класс Страна

public class Country
{
    public Country(string name)
    {
        Name = name;
        Regions = new List<Region>();
    }

    // for EF
    protected Country()
    {
    }

    public int Id { get; set; }

    public string Name { get; set; }

    public IList<Region> Regions { get; set; }

    public Region CreateRegion(string name)
    {
        var region = new Region(name, this);

        Regions.Add(region);

        return region;
    }
}

класс Регион

public class Region
{
    public Region(string name, Country country)
    {
        Name = name;
        Country = country;
        SubRegions = new List<Region>();
    }

    // for EF
    protected Region()
    {
    }

    public int Id { get; set; }

    public string Name { get; set; }

    public Country Country { get; set; }

    public IList<Region> SubRegions { get; set; }

    public Region SuperiorRegion { get; set; }

    public Region CreateSubRegion(string name)
    {
        var region = new Region(name, Country);

        SubRegions.Add(region);
        region.SuperiorRegion = this;

        return region;
    }
}

Затем я создаю дерево (пока все идет хорошо):

var country = new Country("Best Country of the World");
var beachesRegion = country.CreateRegion("Region with beaches");
var hotelsRegion = beachesRegion.CreateSubRegion("Region with hotels");
var workRegion = country.CreateRegion("Region with hard work");

Вот структура, которую я получаю: Диаграмма объекта

Проверка:

Console.WriteLine(country.Regions.Count); // 2

А теперь более интересное. Я создаю DbContext…

public class CountryContext : DbContext
{
    public CountryContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<Country> Countries { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
    }
}

… и подключим к нему Country:

var options = new DbContextOptionsBuilder<CountryContext>()
            .UseInMemoryDatabase(databaseName: "Countries")
            .Options;

using (var db = new CountryContext(options))
{
    db.Countries.Add(country);
}

И на этот раз

Console.WriteLine(country.Regions.Count); //3!!!!!!!

Вот что я получаю на диаграмме: Диаграмма объекта

Собственно, вопрос: как сделать, чтобы SubRegion не добавлялся в коллекцию Region of Country?


person Andrey    schedule 05.03.2019    source источник


Ответы (1)


Ваша проблема заключается в том, что два отношения регионов и субрегионов со страной сбивают с толку EF. Когда вы просите EF получить регионы для вас, он ищет все регионы, у которых есть страна, из которой вы перемещаетесь, что означает, что субрегионы также соответствуют этому критерию.

Чтобы решить эту проблему, вам нужно либо удалить свойство Country из Region. Или вы создаете два класса Region и SubRegion, где Region имеет свойство Country (может быть и без свойства SuperiorRegion, если иерархия не может углубляться более чем на два уровня). И SubRegion не имеет свойства Country.

person Mohammad    schedule 05.03.2019
comment
Полностью согласен, но также предполагаю, что есть способ настроить EF mapping, но пока не нашел как. - person Andrey; 06.03.2019
comment
EF нужен способ отличать регионы верхнего уровня от подрегионов при их загрузке из БД, и оба они находятся в одной таблице. Вы также связываете страну с субрегионами, чтобы EF считал, что они также принадлежат непосредственно стране. Вы можете попробовать оставить значение Country нулевым для подрегионов, но этот дизайн не кажется чистым и может быть легко нарушен другим кодом, который забывает соблюдать это правило. Лучше проектировать с нуля, чтобы вашу модель нельзя было легко перевести в недопустимое состояние. - person Mohammad; 06.03.2019