Обновление ассоциаций внешних ключей в Entity Framework 4.1 Code-First - PullRequest
3 голосов
/ 19 апреля 2011

Я пришел к выводу, что я должен определить как Независимую ассоциацию, так и Ассоциацию внешних ключей в проекте My Code-First.Например:

public class Book
{
  public int ID {get; set;}
  public int AuthorID {get; set;}
  [ForeignKey("AuthorID")]
  public Author Author {get; set;} 
}  
  1. При указанном выше определении нужно ли обновлять AuthorID, когда я хочу сменить автора книги, или достаточно просто использовать приведенную ниже строку?
    myBook.Author = автор;

  2. Собираюсь ли я получить пустое исключение в приведенной выше строке, если я впервые определяю автора книги?(EF инициализирует автора книги автоматически, когда я присваиваю ей какое-то значение?) Должен ли я инициализировать ее в определении:

Код:

public class Book
{
  public int ID {get; set;}
  public int AuthorID {get; set;}

  private Author m_Author;
  [ForeignKey("AuthorID")]
  public Author Author {get
  {
    get
    {
      if (m_Author == null)
        m_Author = new Author();
      return m_Author;
    }
    set
    {
      this.m_Author = value;
    }
  } 
}

Ответы [ 2 ]

4 голосов
/ 19 апреля 2011

Прежде всего, вы не можете использовать как независимый, так и внешний ключ связи - вы используете либо первое, либо второе.Разница в том, используете ли вы свойство FK или нет.Если вы используете ассоциацию с внешним ключом, вы должны использовать внешний ключ для построения отношения.По этой причине ассоциация FK была введена в EFv4.

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

Простой пример, почему вы должны использовать FK вместо свойства навигации при использовании пользовательских POCO (обычно в EFv4.1) и FKотношения:

Это работает без проблем:

var child = new ChildEntity() {Id = 1};
child.ParentEntityId = 1;  // Assigning FK
context.Childs.Attach(child);
context.Entry(child).State = EntityState.Modified;
context.SaveChanges();

Это исключение:

var parent = new ParentEntity() { Id = 1 };
context.Parents.Attach(parent);
var child = new ChildEntity() {Id = 1};
child.Parent = parent;  // <-- Assigning only navigation property
// Next line will cause InvalidOperationException:
// A referential integrity constraint violation occurred: 
// The property values that define the referential constraints 
// are not consistent between principal and dependent objects in 
// the relationship.
context.Childs.Attach(child);
context.Entry(child).State = EntityState.Modified;
context.SaveChanges();

Это снова работает без проблем:

var parent = new ParentEntity() { Id = 1 };
context.Parents.Attach(parent);
var child = new ChildEntity() {Id = 1};
child.Parent = parent;
child.ParentEntityId = 1; // <-- AGAIN assigning FK
context.Childs.Attach(child);
context.Entry(child).State = EntityState.Modified;
context.SaveChanges();
2 голосов
/ 22 апреля 2011

Пример ниже имеет ту же проблему:

public class PingPongPlayer
{
    [Key]
    public string Name { get; set; }
    public string EMail { get; set; }
    public int Ranking { get; set; }
}

public class Match
{
    [Key]
    public int Id { get; set; }

    public string FrkPlayer1 { get; set; }
    public string FrkPlayer2 { get; set; }

    [ForeignKey("FrkPlayer1")]
    public PingPongPlayer Player1 { get; set; }

    [ForeignKey("FrkPlayer2")]
    public PingPongPlayer Player2 { get; set; }

    public DateTime MatchDate { get; set; }

    public bool AlreadyPlayed { get; set; }

    public string Player1Name
    {
        get { return Player1.Name; }
    }

    public string Player2Name
    {
        get { return Player2.Name; }
    }
}

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

Name    EMail   Ranking <br>
a   a@q.com 10 <br>
b   b@q.com 15 <br>
c   c@q.com 12 <br>
d   d@q.com 20 <br>

Id  FrkPlayer1  FrkPlayer2  MatchDate   AlreadyPlayed
1   a           b           2011-04-21 00:00:00.000 0
2   a           c           2011-04-21 00:00:00.000 0
3   b           c           2011-04-21 00:00:00.000 0
4   a           d           2011-04-21 00:00:00.000 0
5   a           c           2011-04-21 00:00:00.000 0
6   d           c           2011-04-21 00:00:00.000 0

Чтобы устранить проблему, просто замените:

[ForeignKey("FrkPlayer1")]
public PingPongPlayer Player1 { get; set; }

[ForeignKey("FrkPlayer2")]
public PingPongPlayer Player2 { get; set; }

на

[ForeignKey("FrkPlayer1")]
public virtual PingPongPlayer Player1 { get; set; }

[ForeignKey("FrkPlayer2")]
public virtual PingPongPlayer Player2 { get; set; }
...