Reputation: 811
I'm having trouble defining a foreign key relationship in entity framework. I've boiled the code down to the minimum to demonstrate the problem.
The model is defined as ;
public class AccessControlList
{
[Key] public int Id { get; set; }
public string Name { get; set; }
}
public class ManagedFile
{
[Key] public int Id { get; set; }
public string Name { get; set; }
public virtual AccessControlList AccessControl { get; set; }
}
public class ManagedFolder
{
[Key] public int Id { get; set; }
public string Name { get; set; }
public virtual AccessControlList AccessControl { get; set; }
public virtual ISet<ManagedFile> Files { get; private set; }
public ManagedFolder()
{
Files = new HashSet<ManagedFile>();
}
}
So essentially, I have a single AccessControl entity that can be referenced by either a ManagedFile or ManagedFolder entity.
To make sure the foreign key is added to ManagedFile and ManagedFolder, I've added the following fluent mapping
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<ManagedFile>()
.HasRequired(mf => mf.AccessControl)
.WithRequiredDependent()
.Map(m => m.MapKey("AccessControlListId"));
modelBuilder.Entity<ManagedFolder>()
.HasRequired(mf => mf.AccessControl)
.WithRequiredDependent()
.Map(m => m.MapKey("AccessControlListId"));
base.OnModelCreating(modelBuilder);
}
This builds a database that looks exactly as I expect, with a foreign key AccessControlListId on each of ManagedFile and ManagedFolder.
It all looks good to me, but when I try to insert some data, with this code
using(var ctx = new MyContext())
{
var mf = ctx.Folders.Add(new ManagedFolder {Name = "$/"});
mf.AccessControl = new AccessControlList();
var file = new ManagedFile {Name = "myfile.txt"};
mf.Files.Add(file);
file.AccessControl = new AccessControlList();
ctx.SaveChanges();
}
It throws an error...
I can't figure out what I've done that's incorrect?
As I understand my mapping, EF can save a new AccessControlList entity, then use the Id to write either the ManagedFolder or ManagedFile table.
As always, I appreciate any help offered.
Thanks Andy
Upvotes: 4
Views: 2481
Reputation: 177133
Why does the database look "exactly as you expect"? Apparently you are trying to define two one-to-one relationships (.HasRequired(...).WithRequiredDependent(...)
) but your relationships in the database are one-to-many.
Do you want one-to-one to one-to-many relationships? In the latter case (which is easier) just replace the two WithRequiredDependent()
methods by WithMany()
.
If you want one-to-one you can't define a separate foreign key AccessControlListId
. You must use shared primary keys, i.e. the PK of the dependent is the FK at the same time. The mapping would have to be:
modelBuilder.Entity<ManagedFile>()
.HasRequired(mf => mf.AccessControl)
.WithRequiredDependent();
// the same for ManagedFolder
...without the MapKey
.
Upvotes: 5