I’m not sure how to express precisely what my problem is, so I’ll just dive into what I have done and describe the problem as it occurs. Actual question is at the end of the post.
I’m using EF 4.3 with code-first, and have this general Category entity for organizing various types of content:
public enum ContentType { Articles, Videos };
public class Category
{
public long ID { get; set; }
public long? ParentCategoryID { get; set; }
internal int ContentTypeValue { get; set; }
public string Title { get; set; }
public virtual Category ParentCategory { get; set; }
public virtual ICollection<Category> ChildCategories { get; set; }
public ContentType ContentType
{
get { return (ContentType) ContentTypeValue; }
set { ContentTypeValue = (int) value; }
}
}
This is mapped to the database using the following definitions (I’m using a helper class, but Map simply refers to the concrete model builder for the entity):
Map.Property( e => e.ContentTypeValue ).IsRequired().HasColumnName( "ContentType" );
Map.Property( e => e.Title ).IsRequired().HasMaxLength( 200 );
Map.HasOptional( e => e.ParentCategory ).WithMany( r => r.ChildCategories ).HasForeignKey( e => e.ParentCategoryID ).WillCascadeOnDelete( false );
Note that Category does not provide references to other entity types (except itself).
Then I added an Article entity and the mapping for it:
public class Article
{
public long ID { get; set; }
public long CategoryID { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public virtual Category Category { get; set; }
}
Map.Property( e => e.Title ).IsRequired().HasMaxLength( 50 );
Map.Property( e => e.Body ).IsRequired().HasMaxLength( 4000 );
Map.HasRequired( e => e.Category ).WithMany().HasForeignKey( e => e.CategoryID ).WillCascadeOnDelete( false );
This works fine and creates an Article table with PK(ID) and FK(CategoryID) to the Category table.
Next step was to add a similar entity and mapping definition for Video, which also worked as expected.
public class Video
{
public long ID { get; set; }
public long CategoryID { get; set; }
public string Title { get; set; }
public string FileName { get; set; }
public virtual Category Category { get; set; }
}
Map.Property( e => e.Title ).IsRequired().HasMaxLength( 50 );
Map.Property( e => e.FileName ).IsRequired().HasMaxLength( 200 );
Map.HasRequired( e => e.Category ).WithMany().HasForeignKey( e => e.CategoryID ).WillCascadeOnDelete( false );
However, now I would like for Article to have a direct reference to a particular Video (regardless of which category any of them is in), so in essence a 1:1 (required:optional) reference between the two.
public class Article // broken
{
public long ID { get; set; }
public long CategoryID { get; set; }
public long? VideoID { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public virtual Category Category { get; set; }
public virtual Video Video { get; set; }
}
And to map the class I’d use the following:
Map.Property( e => e.Title ).IsRequired().HasMaxLength( 50 );
Map.Property( e => e.Body ).IsRequired().HasMaxLength( 4000 );
Map.HasRequired( e => e.Category ).WithMany().HasForeignKey( e => e.CategoryID ).WillCascadeOnDelete( false );
Map.HasOptional( e => e.Video ).WithMany().HasForeignKey( e => e.VideoID ).WillCascadeOnDelete( false );
As soon as I add such a reference, EF fails creating the database schema with an DbUpdateException, whose error message is along the lines of “Unable to determine the principal end of (constraint name). Multiple added entities may have the same primary key.”
I can solve the problem by not having Video reference Category (or by not having Article reference Video, as in the first code shown), but that would defeat the generic purpose of the Category class and force me to maintain ArticleCategories, VideoCategories, etc.
To be perfectly clear what I need, here is the schema I’d like to end up with (note: the CategoryID in Video should not be nullable, contrary to the image):

How do I define such a relationship using code-first fluent notation?
I’m unable to reproduce the issue, your configs are just fine (I’m using automatic migrations here).
Can you add the exact error it gives to you?
Anyway, that’s my exact code: https://gist.github.com/1961958
And that’s the generated SQL from Update-Database: https://gist.github.com/1961961
EDIT: ops, I didn’t see the exact same answer from @BalazsTihanyi, sorry.