I have come to a conclusion that I should define both Independent Association and Foreign Key Association in My Code-First design. e.g:
public class Book
{
public int ID {get; set;}
public int AuthorID {get; set;}
[ForeignKey("AuthorID")]
public Author Author {get; set;}
}
With the above definition, do I have to update AuthorID when I want to change the book's author, Or just using the below line is enough?
myBook.Author = author;Am I going to get a null exception on the above line if that is the first time I'm defining an author for the book? (Does EF initialize book's author automatically when I assign some value to it?) Should I initialize it in the definition:
The code:
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;
}
}
}
First of all you can't use both independent and foreign key association - you use either first or second. The difference is if you use FK property or not. If you use foreign key association you should use foreign key to build a relation. That is the reason why FK association was introduced in EFv4.
Edit:
Simple example why you should use FK instead of navigation property when using custom POCOs (common in EFv4.1) and FK relations:
This works without any problem:
var child = new ChildEntity() {Id = 1};
child.ParentEntityId = 1; // Assigning FK
context.Childs.Attach(child);
context.Entry(child).State = EntityState.Modified;
context.SaveChanges();
This throws exception:
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();
This again works without any problem:
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();
The example below has the same issue:
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; }
}
}
If I bind a property of a Control to the Player1Name property I get a NullPointerException. In the database I can see the table and it seems to have the correct key values.
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
To fix the problem just replace:
[ForeignKey("FrkPlayer1")]
public PingPongPlayer Player1 { get; set; }
[ForeignKey("FrkPlayer2")]
public PingPongPlayer Player2 { get; set; }
by
[ForeignKey("FrkPlayer1")]
public virtual PingPongPlayer Player1 { get; set; }
[ForeignKey("FrkPlayer2")]
public virtual PingPongPlayer Player2 { get; set; }
来源:https://stackoverflow.com/questions/5716733/updating-foreign-key-associations-in-entity-framework-4-1-code-first