Сначала код EF 4.1: как обращаться к дочерним записям от родителя в отношении один ко многим - PullRequest
1 голос
/ 01 ноября 2011

У меня есть простое отношение 1: много совокупностей, скажем:

public class Parent
{
    public string Name {get; set;}
    public Child SelectedChild {get; set;}
    public Child PublishedChild {get; set;}
    public virtual ICollection<Child> AllChildren {get; set;}
}

public class Child
{
    public string Name {get; set;}
    [Required]
    public Parent Father {get; set;}
}

При создании схемы из этой модели я получаю ошибку:

Введение ограничения FOREIGN KEY 'Parent_SelectedChild' в таблицу 'Parent' может привести к возникновению циклов или нескольких каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION или измените другие ограничения FOREIGN KEY

Поэтому я добавляю следующее в OnModelCreating:

        modelBuilder.Entity<Child>()
            .HasRequired(v => v.Parent)
            .WithOptional(c => c.SelectedChild)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Child>()
            .HasRequired(v => v.Parent)
            .WithOptional(c => c.PublishedChild)
            .WillCascadeOnDelete(false);

Это обходит исходную ошибку, но теперь я получаю:

Невозможно определить основной конец отношения 'xxx.Parent_SelectedChild'. Несколько добавленных объектов могут иметь один и тот же первичный ключ.

Кто-нибудь может помочь? Все, что я, по сути, хочу сделать, - это сослаться на конкретные дочерние записи в отношении совокупности 1: многие от родителя. Я предполагаю, что EF создаст столбцы идентификатора дочернего идентификатора INT для родителя, например, с именем SelectedChild_Id & ОпубликованныйChild_Id (или аналогичный).

Заранее спасибо -macon

Редактировать: В ответ на @Slauma: Я могу получить схему, созданную с помощью:

            modelBuilder.Entity<Parent>()
            .HasOptional(p => p.SelectedChild)
            .WithOptionalPrincipal()
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Parent>()
            .HasOptional(p => p.PublishedChild)
            .WithOptionalPrincipal()
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Parent>()
            .HasMany(p => p.AllChildren)
            .WithRequired(c => c.Father)
            .WillCascadeOnDelete(false);

Но это генерирует несколько FK в записи Child, например Parent_Id, Parent_Id1. Я просто хочу ссылку от родителя на одну из дочерних строк, например, Parent_SelectedChildId. Нужно ли делать это вручную с помощью столбца int на родительском элементе?

1 Ответ

2 голосов
/ 01 ноября 2011

Я думаю, что у вас есть три отношения один ко многим:

modelBuilder.Entity<Parent>()
    .HasOptional(p => p.SelectedChild)
    .WithMany()
    .WillCascadeOnDelete(false);

modelBuilder.Entity<Parent>()
    .HasOptional(p => p.PublishedChild)
    .WithMany()
    .WillCascadeOnDelete(false);

modelBuilder.Entity<Parent>()
    .HasMany(p => p.AllChildren)
    .WithRequired(c => c.Father)
    .WillCascadeOnDelete(false);

Редактировать

Я проверил свое отображение выше с точно классами Parent и Child, которые вы указали в своем вопросе - с единственным исключением, что я добавил свойство первичного ключа в оба класса: public int Id { get; set; }. В противном случае EF будет жаловаться на отсутствующее ключевое свойство. Это отображение не вызывает исключение и создает следующие таблицы в базе данных:

Родители Таблица:

- Id                    int             not nullable (PK)
- Name                  nvarchar(MAX)   nullable
- SelectedChild_Id      int             nullable (FK)
- PublishedChild_Id     int             nullable (FK)

Дети Стол:

- Id                    int             not nullable (PK)
- Name                  nvarchar(MAX)   nullable
- Father_Id             int             not nullable (FK)

Итак, есть три столбца внешнего ключа, как и ожидалось.

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

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

...