Как добавить внешний ключ в ссылочную модель, не добавляя свойство навигации в основную модель - PullRequest
0 голосов
/ 18 мая 2018

У меня есть отношения «один ко многим» между моделями «Родитель» и «Ребенок».Следуя соглашению проекта, мне нужно создать отдельный класс для сопоставления каждой сущности, выходящей из класса EntityTypeConfiguration.

public class Parent
{
    public int Id { get; set; }
    [Required]
    public string ParentName { get; set; }
    //public IEnumerable<Child> Children { get; set; }
}

public class Child
{
    [Key]
    public int ChildId { get;  set; }

    [Required]
    public string ChildName { get; set; }

    [ForeignKey]
    public int CustomParentId { get; set; }

    public Parent Parent { get; set; }
}

public class ChildMap : EntityTypeConfiguration<Child>
{

}

Как добавить внешний ключ в ChildMap без добавления свойства навигации Child в родительскую модель?

1 Ответ

0 голосов
/ 22 мая 2018

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

public class ParentMap : EntityTypeConfiguration<Parent>
{
  ToTable("Parents");
  HasKey(x => x.Id)
    .Property(x => x.Id)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}

//With Parent ID in Child:
public class ChildMap : EntityTypeConfiguration<Child>
{
  ToTable("Children");
  HasKey(x => x.ChildId)
    .Property(x => x.ChildId)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

  HasRequired(x => x.Parent)
    .WithMany()
    .HasForeignKey(x => CustomParentId);
}

// Without Parent ID in child. (Column in table called "CustomParentId")
public class ChildMap : EntityTypeConfiguration<Child>
{
  ToTable("Children");
  HasKey(x => x.ChildId)
    .Property(x => x.ChildId)
    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

  HasRequired(x => x.Parent)
    .WithMany()
    .Map(x => x.MapKey("CustomParentId"));
}

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

public class Child
{
  // .. Without virtual
  public Parent Parent { get; set; }
}

//vs.
public class Child
{
  // .. With virtual
  public virtual Parent Parent { get; set; }
}

Если для загрузки дочернего элемента вы используете следующий код ...

var child = myContext.Children
  .SingleOrDefault(x => x.ChildId == 1);

, перейдите к родительскому элементу с помощью ...

string parentName = child.Parent?.Name;

В случае, если у вас нет виртуального родителя, ссылка Parent не была загружена, поэтому Parent будет #null.Если родительский объект является виртуальным, то для извлечения родительского объекта будет сделан отложенный вызов загрузки, и вы получите связанный объект.Ленивая загрузка в целом полезна, но не очень эффективна, поскольку приводит к вероятному второму обращению к базе данных.В обоих случаях, если вы сделали:

var child = myContext.Children
  .Include(x => x.Parent)
  .SingleOrdefault(x => x.ChildId == 1);

Тогда родительская ссылка будет загружена и доступна, виртуальная или нет.

В качестве альтернативы, лучший способ получения данных - использовать отдельное представлениемодель и выберите нужные поля из данных и связанных данных.Например, используя модель представления, которая возвращает дочерние данные с идентификатором и именем родителя:

var child = myContext.Children
  .Select(x => new ChildSummaryViewModel 
  {
    ChildId = x.ChildId,
    Name = x.Name,
    ParentId = x.Parent.Id,
    ParentName = x.Parent.Name
  })
  .SingleOrdefault(x => x.ChildId == 1);

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

При обновлении сущностей вы должны использовать связанные .Include () для корректировки или изменения отношений.

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