0

Я смущен тем, как моделировать свои отношения в Entity Framework.Как получить комбинированное необязательное отношение и отношение «Один к многим»?

Я хочу, чтобы ClassA, необязательно, указывал на ClassB. Это похоже на необязательные отношения «один-к-одному».

Я также хочу, чтобы ClassB всегда указывал на класс А, который указывает на него. Я также хочу разрешить нескольким ClassB, чтобы обратиться к тем же ClassA. Это звучит как отношения «один ко многим».

Является ли это наилучшим образом смоделированным как одно отношение, или это действительно две совершенно разные отношения?

Если это два отношения, они могут совместно использовать одно свойство ClassAKey, которое появляется в ClassB, которое будет использоваться для ссылки на ClassA?

В моей проблеме это ясно в моей голове, что я хочу, чтобы мой О.М. быть:

ClassA 
{ 
    [Key] 
    int Key { get; set; } 
    ClassB Maybe { get; set; } 
    int MaybeKey { get; set; } 
} 

ClassB 
{ 
    [Key] 
    int Key { get; set; } 
    ClassA Always { get; set; } 
    int AlwaysKey { get; set; } 
} 

Это также ясно в моей голове, что это должно выглядеть в БД: там должно быть только ClassAKey колонка для ClassB и столбец ClassBKey для ClassA, так что каждый из них может ссылаться друг на друга и отношения внешних ключей на этих столбцах.

Но ... Я не понимаю, как можно моделировать это в EF. На самом деле кажется, что я должен что-то делать неправильно! Если я только начинаю с кода выше, я получаю сообщение об ошибке.

Unable to determine the principal end of an association between the types 'ClassA' and 'ClassB'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

Если я пытаюсь настроить его так,

modelBuilder.Entity<ClassA>() 
      .HasOptional(a => a.Maybe) 
      .WithRequired(b => b.Always); 

я по какой-то причине получить то, что выглядит неправильно дизайнер код, сгенерированный где ClassB имеет неправильное внешнего ключ свойство

.ForeignKey("dbo.ClassAs", t => t.Key) 

Это должно быть t.AlwaysKey, правильно? Что происходит !?

+0

Не уверен, что я понял, но что вы получите, если попытаетесь создать .edmx из существующего db? –

ответ

0

в конце концов, это то, что я считаю, должно было сработать, но я не получил его работы (это может быть ошибка в Entity Framework 5):

modelBuilder.Entity<ClassB>() 
    .HasRequired(a => a.Always) 
    .WithMany() 
    .HasForeignKey(a => a.AlwaysKey); 

modelBuilder.Entity<ClassB>() 
    .HasOptional(b => b.Maybe); 

И это то, что на самом деле работал [закомментировав последние две строки]:

modelBuilder.Entity<ClassB>() 
    .HasRequired(a => a.Always) 
    .WithMany() 
    .HasForeignKey(a => a.AlwaysKey); 

//modelBuilder.Entity<ClassB>() 
// .HasOptional(b => b.Maybe); 

Также я изменил MaybeKey на значение, равное нулю.

int? MaybeKey { get; set; } 

Вторая необязательная связь работает по соглашению, вместо явной конфигурации.

1

Если я правильно понял, вы пытаетесь создать One: Многие дополнительные отношения между ClassA и ClassB. Это также звучит так, будто вы всегда хотите, чтобы ClassB имел связанный с ним ClassA, что сделало бы ваш ClassA вашим главным и ClassB вашим зависимым.

Во-первых, вам необходимо будет изменить навигационное свойство для ClassB (в вашем ClassA). Поскольку вы хотите найти много отношений, вам понадобится какая-то коллекция для хранения ваших ClassB объектов.

Это означает, что вы будете удалить ваш MaybeKey в ClassA, так как нет ни одного объекта, который вы имеете в виду, а теперь у вас есть коллекция (например ICollection<ClassB>). Вам также не понадобится столбец в соответствующей таблице ClassA, чтобы ссылаться на ClassB (поскольку это отношение «один-много», один столбец не будет работать).В таблице ClassB должна быть только колонка с внешним ключом, относящаяся к ClassA, к которой относится ClassB.

Ваш код может выглядеть следующим образом:

public class ClassA 
{ 
    [Key] 
    public int Key { get; set; } // ClassA Key 

    public virtual ICollection<ClassB> MyClassBs { get; set; } // Your optional dependants. 
} 

public class ClassB 
{ 
    [Key] 
    public int Key { get; set; } // ClassB key 

    public int AKey { get; set; } // Your foreign key. 
    public virtual ClassA myClassA { get; set; } // Your principal. 
} 

свойства навигации отмечены virtual так Entity Framework может переопределить их, и предоставить вам функциональность отложенной загрузки (если требуется его).

Чтобы создать ваше сопоставление, вы бы сделали что-то в этом направлении (возможно, потребуется изменить, если я неправильно понял вашу цель).

modelBuilder.Entity<ClassA>() 
      .HasMany(b => b.MyClassBs)  // Many ClassBs 
      .WithRequired(a => a.myClassA) // Each ClassB requires a ClassA 
      .HasForeignKey(b => b.AKey); // Use Akey as a foreign key 

Есть несколько способов, чтобы выразить это (например, вы могли бы сделать это с ClassB стороны).

Может быть, стоит придерживаться чуть более обычного наименовании например ID для первичных ключей и имен, как ClassAID для ваших внешних ключей, так как рамки Entity имеет ряд default conventions вы можете использовать. Это также облегчает чтение другим кодом вашего кода (поскольку вы склонны сталкиваться с аналогичными соглашениями).

Редактировать: Обновлено, чтобы включить «особые» отношения.

В вашей ClassA вы можете включить следующие поля (которые вы уже имели в своем исходном примере, с разными названиями):

public int SpecialBID { get; set; } 
public virtual ClassB SpecialB { get; set; } 

и добавить следующее отображение:

modelBuilder.Entity<ClassA>() 
      .HasOptional(x => x.SpecialB) 
      .WithMany() 
      .HasForeignKey(x => x.SpecialBID); 

Хотя теперь нет гарантии, что ваш SpecialB включен в вашу коллекцию MyClassBs.

Вы также должны быть в состоянии удалить коллекцию MyClassBs полностью из ClassA, используя отображение отношения, которое не требует свойства навигации на другой стороне отношений (в объекте ClassB):

modelBuilder.Entity<ClassB>() 
     .HasRequired(x => x.myClassA) 
     .WithMany() 
     .HasForeignKey(x => x.AKey); 
+0

Hm. Интересный ответ. Мое мнение состояло в том, что мне действительно не нужна коллекция MyClassB. Я не уверен, что это очень больно иметь эту коллекцию, если я ее лениво загрузил и никогда не использовал. –

+0

В вашем ответе также отсутствует одна важная для меня вещь, которая заключается в том, что ClassA необязательно имеет один связанный ClassB, который является «специальным» членом его коллекции. –

+0

Посмотрите, действительно ли мое редактирование полезно. – Chris

 Смежные вопросы

  • Нет связанных вопросов^_^