Связывание нескольких свойств с одной и той же таблицей в Entity Framework - PullRequest
0 голосов
/ 03 июля 2018

Позвольте мне предвидеть это, сказав, что это мой первый реальный опыт работы с Entity Framework и реляционными базами данных в целом. Если я делаю это совершенно неправильно, пожалуйста, скажите мне.

Я хочу, чтобы мои данные были структурированы примерно так (Сократите код "extra"):

Indicators {
    int SomeText1TranslationRef
    List<Translation> SomeText1Translations
    int SomeText2TranslationRef
    List<Translation> SomeText2Translations
}

Measures {
    int SomeText3TranslationRef
    List<Translation> SomeText3Translations
    int SomeText3TranslationRef
    List<Translation> SomeText4Translations
}

Translation {
    Int TranslationID
    String LanguageCode
    String Text
}

Таким образом, в сущности, таблица индикаторов будет содержать список переводов SomeText1, а также SomeText2, все из которых будут объединены с использованием TranslationID через свойства «Ref».

У меня есть свойства перевода, помеченные [ForeignKey("....Ref")].

Я ожидал, что это будет работать магически, как кажется остальной части фреймворка, но вместо этого таблица перевода получает столбцы с именами «SomeText1TranslationRef» и «SomeText2TranslationRef».

Я делаю это неправильно?

Я смотрю на другие функции Entity Framework и вижу аннотацию для «InverseProperty». Это может помочь?

Ответы [ 3 ]

0 голосов
/ 04 июля 2018

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

В вашем случае вы получите 4 навигационных свойства, требуемых для вашего перевода. (int IndicatorRef1, int IndicatorRef2, int MeasureRef3, int MeasureRef4). Большинство не назвало бы это сценарием мечты.

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

Итак, вот ответ на то, что вы пытаетесь достичь, и, возможно, даже решение 2 ваших вопросов:

Не полагайтесь на ручку EF в любом сценарии. На самом деле, в значительной степени не полагайтесь на EF для обработки отношений, кроме 1-1, 1- * или * - *. И некоторые формы наследования.

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

Хорошие новости? Вы не должны полагаться на EF для этого. Основным преимуществом EF является его производительность. В некоторых случаях все еще стоит использовать EF, но предлагать свои собственные методы повышения производительности. Если вы хотите получить набор индикаторов с 2-мя коллекциями переводов на основе ссылки, просто создайте метод, который его предоставляет.

Что-то вроде

        public IQueryable<Indicators> SetOfIndicatorsWithTranslations()
        {
            // Untested query that might need some fixing in an actual implementation 
            return ctx.Set<Indicators>().Select(ind => new Indicators() {
                                    Text1Ref= ind.Text1Ref, // whatever the property is 
                                    Text1RefList = ctx.Set<Translation>().Where(t => t.TranslationId == ind.Text1Ref),  
                                    Text2Ref= ind.Text2Ref,  
                                    Text2RefList = ctx.Set<Translation>().Where(t => t.TranslationId == ind.Text2Ref),  
                                });
        }

Теперь этот запрос EF выполнит для вас изящно.

Есть, конечно, гораздо более элегантные решения для чего-то подобного Важно то, что иногда стоит сделать это самостоятельно, а не ограничивать себя возможностями своего инструмента выбора. (Ну, по крайней мере, это важная часть, которую я в конечном итоге выучил :))

0 голосов
/ 04 июля 2018

Короче говоря, предостережение - это "ядро" части .Net Core. EF Core не поддерживает соглашение "сверхконфигурация" для множества "многие ко многим" , но (см. здесь ).

Единственный способ добиться этого - вручную создать соединительные таблицы, как предложил Стив. Вот вся необходимая информация: https://www.learnentityframeworkcore.com/configuration/many-to-many-relationship-configuration

В предыдущих версиях Entity Framework этого определения модели было достаточно для EF, чтобы подразумевать правильный тип отношений и генерировать для него таблицу соединений. В EF Core 1.1.0 необходимо включить объект в модель для представления таблицы соединения, а затем добавить свойства навигации по обе стороны от отношений «многие ко многим», которые вместо этого указывают на объект соединения:

Приведенная выше ссылка, скорее всего, будет обновляться со временем, поэтому для целей контекста приведен код, который сопровождает ее:

public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }
    public Author Author { get; set; }
    public ICollection<BookCategory> BookCategories { get; set; }
} 

public class Category
{
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
    public ICollection<BookCategory> BookCategories { get; set; }
}

public class BookCategory
{
    public int BookId { get; set; }
    public Book Book { get; set; }
    public int CategoryId { get; set; }
    public Category Category { get; set; }
}

В качестве альтернативы, используя Fluent:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<BookCategory>()
        .HasKey(bc => new { bc.BookId, bc.CategoryId });

    modelBuilder.Entity<BookCategory>()
        .HasOne(bc => bc.Book)
        .WithMany(b => b.BookCategories)
        .HasForeignKey(bc => bc.BookId);

    modelBuilder.Entity<BookCategory>()
        .HasOne(bc => bc.Category)
        .WithMany(c => c.BookCategories)
        .HasForeignKey(bc => bc.CategoryId);
}
0 голосов
/ 03 июля 2018

Я не на 100% ясен относительно вашей цели, но если у индикатора может быть много переводов Text1 и много переводов Text2, то это 2 отношения «многие ко многим». То же самое для мер. Для этого EF потребуется таблица соединения / моста / соединения (IndicatorTranslation и MeasureTranslation). Вы можете явно создать эту таблицу или позволить EF сделать это за кулисами:

Indicator {
    // other indicator fields
    public virtual List<Translation> SomeText1Translations
    public virtual List<Translation> SomeText2Translations
}

Measure {
    // other measure fields
    public virtual List<Translation> SomeText3Translations
    public virtual List<Translation> SomeText4Translations
}

Translation {
    Int TranslationID
    String LanguageCode
    String Text

    // Use inverse attributes or fluent code to tell EF how to connect relationships
    [InverseProperty("SomeText1Translations")]
    public virtual ICollection<Indicator> TranslationForIndicatorText1 { get; set; }
    [InverseProperty("SomeText2Translations")]
    public virtual ICollection<Indicator> TranslationForIndicatorText2 { get; set; }
    [InverseProperty("SomeText3Translations")]
    public virtual ICollection<Measure> TranslationForMeasureText3 { get; set; }
    [InverseProperty("SomeText4Translations")]
    public virtual ICollection<Measure> TranslationForMeasureText4 { get; set; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...