Reputation: 1277
I've been trying to find my way with EF during the last couple of days/weeks. Currently I'm a bit stuck on handling Foreign Keys, in this case I have a table that has two FK's to itself (please no questions about my DB design, as this is just the situation I'm facing, there is no chance to change the database structure).
I've reduced my code to this example below in which I make use of a single table described by class Foo
:
class Foo
{
public int ID { get; set; }
public string Data { get; set; }
public int firstFkID { get; set; }
public int secondFkID { get; set; }
[ForeignKey("firstFkID")]
public virtual Foo firstFk { get; set; }
[ForeignKey("secondFkID")]
public virtual Foo secondFk { get; set; }
}
My DbContext
derived class:
class EFFKContext : DbContext
{
public EFFKContext(string connectionString) : base(connectionString) { }
public virtual DbSet<Foo> Foo { get; set; }
}
And of course the code where I use all this:
static void Main(string[] args)
{
SqlConnectionStringBuilder cnStrBuilder = new SqlConnectionStringBuilder()
{
DataSource = "(local)",
InitialCatalog = "EF_FK",
IntegratedSecurity = true
};
EFFKContext context = new EFFKContext(cnStrBuilder.ConnectionString);
Foo foo = context.Foo.Find(3);
Foo fFoo = foo.firstFk;
Foo sFoo = foo.secondFk;
}
When I compile this, there is no problem at all, but during runtime I get the following error:
An unhandled exception of type 'System.InvalidOperationException' occurred in >EntityFramework.dll
Additional information: Unable to determine the principal end of an association >between the types 'RF_EF_FK.Foo' and 'RF_EF_FK.Foo'. The principal end of this >association must be explicitly configured using either the relationship fluent >API or data annotations.`
Can anyone explain why I'm getting this error, what it exactly means and point the direction in which I will have to modify my code to get it to behave the way I want it to?
Which is being able to obtain the objects the two FK's are pointing to.
I've tried the following:
Adding additional navigation properties returning a collection, though this does not provide the desired solution. Also the relationship is not a one-to-many relationship so this does not even feel correct.
I've also tried adding some Fluent API code, but again this did not provide me the solution I need.
Though I've tried the above things, it might very well be possible that I've missed anything there. Any help is more than welcome!
Edit:
Whilst continuing my search to tackle this problem I've found that adding the following to my context class would solve the FK problem.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>().HasOptional(f => f.secondFk).WithMany().HasForeignKey(f => f.secondFkID);
modelBuilder.Entity<Foo>().HasOptional(f => f.firstFk).WithMany().HasForeignKey(f => f.firstFkID);
}
Now, when loading the entity from the database I need to use the Include
functions to include the related objects right away, or use the following to load it later:
context.Entry(sFoo).Reference("firstFk").Load();
Still not sure whether this is the way to go though.
Upvotes: 4
Views: 377
Reputation: 1277
Due to the fact that no other answers than the one of Jenish Radadiya have been submitted, I'll post my own findings as answer now.
Whilst continuing my search to tackle this problem I've found that adding the following to my context class would solve the FK problem.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Foo>().HasOptional(f => f.secondFk).WithMany().HasForeignKey(f => f.secondFkID);
modelBuilder.Entity<Foo>().HasOptional(f => f.firstFk).WithMany().HasForeignKey(f => f.firstFkID);
}
Now, when loading the entity from the database I need to use the Include functions to include the related objects right away, or use the following to load it later:
context.Entry(sFoo).Reference("firstFk").Load();
Still not sure whether this is the way to go though.
Upvotes: 2
Reputation: 6766
You might need to make one field as nullable. I am not much sure on that.
You can use Fluent api instead to prepare model relationship.
class Foo
{
public int ID { get; set; }
public string Data { get; set; }
public int firstFkID { get; set; }
public int secondFkID { get; set; }
//[ForeignKey("firstFkID")] <- remove this while using fluent api
public virtual Foo firstFk { get; set; }
//[ForeignKey("secondFkID")] <- remove this while using fluent api
public virtual Foo secondFk { get; set; }
}
Try this.
public class FooConfiguration : EntityTypeConfiguration<Foo>
{
public FooConfiguration()
{
this.HasKey(x => x.ID);
this.HasOptional(f => f.firstFk)
.WithOptionalDependent(f => f.secondFk);
}
}
I also found one related stackoverflow thread => here
Upvotes: 1