3

I'm using Entity Framework and here it's my entity Model:

Public class Document
{
    Public int Id { get; set; }
    Public Document Parent { get; set; }
}

and as you see that it has a self-reference property.

Now I'm trying to add another self-reference property like this:

Public class Document
{
    Public int Id { get; set; }
    Public Document Parent { get; set; }
    Public Document SrcDocument { get; set; }
}

But unfortunately I've faced with below error:

Unable to determine the principal end of an association between the types 'Document' and 'Document'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

Majid Parvin
  • 4,499
  • 5
  • 29
  • 47
Reza
  • 65
  • 6

2 Answers2

3

Entity Framework Code-First conventions are assuming that Document and Document belong to the same relationship and are the inverse navigation properties of each other. Because both navigation properties are references (not collections) EF infers a one-to-one relationship.

Since you actually want two one-to-many relationships you must override the conventions. Just override OnModelCreating method of the context and put there what's your idea about new cycle-relation like this:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Document>().HasRequired(p => p.SrcDocument).WithMany();
    base.OnModelCreating(modelBuilder);
}

Update

modelBuilder.Entity<Document>().HasRequired(p => p.SrcDocument).WithMany(); say to Entity Framework the SrcDocument has a one-to-many relation with itself.

and also you can use below code:

modelBuilder.Entity<Document>().HasOptional(p => p.SrcDocument).WithMany();

to make a zero-to-many relation.

and with this:

modelBuilder.Entity<Document>().HasOptional(p => p.SrcDocument).WithOptionalDependent();

you can define a one-to-zero relation.

It'll be worked.

Majid Parvin
  • 4,499
  • 5
  • 29
  • 47
  • "Since you actually want two one-to-many" this is not what I'm reading in the question. Also, your code piece does define one of the properties as the navigation property in a one-to-zero or one relationship. You should streamline those assertions, since then the answer will likely be correct. – DevilSuichiro Jun 21 '17 at 15:49
2

Try to use InverseProperty attribute:

public class Document
{
    public int Id { get; set; }

    public virtual Document Parent { get; set; }
    public int ParentId { get; set; }

    public virtual Document SrcDocument { get; set; }
    public int SrcDocumentId { get; set; }

    [InverseProperty("Parent")]
    public virtual ICollection<Document> Children {get;set;}
    [InverseProperty("SrcDocument")]
    public virtual ICollection<Document> Derived {get;set;}
}

Migration:

CreateTable(
    "dbo.Documents",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            ParentId = c.Int(nullable: false),
            SrcDocumentId = c.Int(nullable: false),
        })
    .PrimaryKey(t => t.Id)
    .ForeignKey("dbo.Documents", t => t.ParentId)
    .ForeignKey("dbo.Documents", t => t.SrcDocumentId)
    .Index(t => t.ParentId)
    .Index(t => t.SrcDocumentId);
Slava Utesinov
  • 13,410
  • 2
  • 19
  • 26