Ok you can see my simplified model below. If I leave out the mappings I get all sorts of duplicate keys generated in the database in my base BusinessCardActions table everytime I add a new collection that relates back such as Requests or Invites in the example code below.
// DbContext
public DbSet<BusinessCardAction> BusinessCardActions { get; set; }
// Classes
public abstract class BusinessCardAction
{
public Int32 Id { get; set; }
public User User { get; set; }
public Int32 UserId { get; set; }
public Int32 OtherUserId { get; set; }
public User OtherUser { get; set; }
public Guid UniqueId { get; set; }
public String Email { get; set; }
public String OtherEmail { get; set; }
public Int32 UserAction { get; protected set; }
public DateTime ActionDate { get; set; }
}
public abstract class StatusAction : BusinessCardAction
{
public Int32 Status { get; set; }
public String Password { get; set; }
}
public class Request : StatusAction
{
public Int32 InviteId { get; set; }
}
public class Acceptance : BusinessCardAction
{
}
public class Nudge : BusinessCardAction
{
}
public class User
{
public Int32 Id { get; set; }
public ICollection<Associate> AssociatedUsers { get; set; }
public ICollection<Request> Requests { get; set; }
public ICollection<Invite> Invites{ get; set; }
public ICollection<BusinessCardAction> RecentActions { get; set; }
}
Now, I don't have a huge problem with these duplicate columns if there is just no way to share the foreign key columns, in my base class, among the derived classes. But this is not what happens. The data as shown at the link after the following inserts shows that they all share the desired UserId column.
I have created some test code and added a link to the results after data is added.
var accept = new Acceptance()
{
Email = "tsie@mail.com",
OtherUserId = 2,
UserId = 1,
OtherEmail = "jaim@l8.ca",
Associate = "James",
ActionDate = DateTime.Now
};
var invite = new Invite()
{
Email = "tsie@ail.com",
OtherUserId = 2,
UserId = 1,
OtherEmail = "jai@llev8.ca",
Status = 1,
Password = "Password",
ActionDate = DateTime.Now
};
var request = new Request()
{
Email = "tst@mail.com",
OtherUserId = 2,
UserId = 1,
OtherEmail = "jai@llev8.ca",
Password = "********",
Status = 2,
ActionDate = DateTime.Now
};
var nudge = new Nudge()
{
Email = "tsi@ail.com",
OtherUserId = 2,
UserId = 1,
OtherEmail = "jai@lev8.ca",
ActionDate = DateTime.Now
};
_businessCardActionService.Data.BusinessCardActions.Add(accept);
_businessCardActionService.Data.BusinessCardActions.Add(invite);
_businessCardActionService.Data.BusinessCardActions.Add(request);
_businessCardActionService.Data.BusinessCardActions.Add(nudge);
_businessCardActionService.Save();
Follow this link to view the BusinessCardActionsData after the preceding inserts http://screencast.com/t/JKBcpaCT742
So as you can see, the for different types are stored in the base class table. Unfortunately there are some rogue unused columns at the end of the table that appear to be useless. I have been trying to map them so that these columns disappear in the generated code.
And here is the mapping section for the classes.
...
modelBuilder.Entity<Nudge>()
.HasRequired(i => i.User)
.WithMany()
.HasForeignKey(i => i.UserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Acceptance>()
.HasRequired(a => a.User)
.WithMany()
.HasForeignKey(a => a.UserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Nudge>()
.HasRequired(i => i.OtherUser)
.WithMany()
.HasForeignKey(i => i.OtherUserId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Acceptance>()
.HasRequired(a => a.OtherUser)
.WithMany()
.HasForeignKey(a => a.OtherUser)
.WillCascadeOnDelete(false);
Instead of a nicely generated database table I just get the following error, which makes sense to some degree, but at the same time somehow annoys me deeply. Maybe there is a way to do this but I haven't found it yet.
The navigation property 'User' declared on type 'Ellevate.BusinessCards.Models.BusinessCardAction' has been configured with conflicting multiplicities.