EFCore - How to have multiple navigation properties to the same type?

.net asp.net c# entity-framework entity-framework-core

Question

My model contains the classes Post and PostHistory, where Post has a one-to-many relationship with PostHistory.

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

    public PostVersion CurrentVersion { get; set; }
    public PostVersion OriginalVersion { get; set; }
    public IList<PostVersion> History { get; set; }
}

class PostVersion
{
    public int Id { get; set; }
    public Post Post { get; set; }

    public string Title { get; set; }
    public string Body { get; set; }
}

The History property contains a list of all PostVersions related to that Post. The CurrentVersion and PreviousVersion properties both reference a perticlar version in that post history (most likley the most recent version and the first version).

My problem is that EF Core struggles to understand the relationship due to the CurrentVersion and OriginalVersion navigation properties. When I try to create a migration, I get this error message:

Unable to determine the relationship represented by navigation property 'Post.CurrentVersion' of type 'PostVersion'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

After that I tried to use the Fluent API to create the relationships manually.

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<Post>()
        .HasMany(x => x.History)
        .WithOne(x => x.Post);
    builder.Entity<Post>()
        .HasOne(x => x.CurrentVersion)
        .WithOne(x => x.Post);
    builder.Entity<Post>()
        .HasOne(x => x.OriginalVersion)
        .WithOne(x => x.Post);
}

But created a different error:

Cannot create a relationship between 'PostVersion.Post' and 'Post.CurrentVersion', because there already is a relationship between 'Post.History' and 'PostVersion.Post'. Navigation properties can only participate in a single relationship.

Is it possible to create this kind of relationship in EF Core code-first?

1
4
12/15/2018 3:23:42 PM

Accepted Answer

Edit I did some changes, you cannot reference same property in multiple relationships. Therefore i had to use foreign keys for mappings. PostVersion has only one Post reference as you required.

public class Post
{
    public Guid Id { get; set; }

    public Guid CurrentVersionId { get; set; }
    public PostVersion CurrentVersion { get; set; }
    public Guid OriginalVersionId { get; set; }
    public PostVersion OriginalVersion { get; set; }
    public IList<PostVersion> History { get; set; }
}

public class PostVersion
{
    public Guid Id { get; set; }
    public Guid PostId { get; set; }

    public Post Post { get; set; }

    public string Title { get; set; }
    public string Body { get; set; }
}

modelBuilder.Entity<Post>()
    .HasOne(x => x.CurrentVersion)
    .WithOne()
    .HasForeignKey<Post>(p => p.CurrentVersionId);
modelBuilder.Entity<Post>()
    .HasOne(x => x.OriginalVersion)
    .WithOne()
    .HasForeignKey<Post>(p => p.OriginalVersionId);

modelBuilder.Entity<Post>()
    .HasMany(x => x.History)
    .WithOne(p => p.Post)
    .HasForeignKey(pv => pv.PostId);

Original You need to specify additional property for that second relationship

public class Post
{
    public Guid Id { get; set; }

    public PostVersion CurrentVersion { get; set; }
    public PostVersion OriginalVersion { get; set; }
    public IList<PostVersion> History { get; set; }
}

public class PostVersion
{
    public Guid Id { get; set; }
    public Post Post { get; set; }
    public Post SecondPost { get; set; }
    public Post ThirdPost { get; set; }

    public string Title { get; set; }
    public string Body { get; set; }
}


 modelBuilder.Entity<Post>()
            .HasOne(x => x.CurrentVersion)
            .WithOne(x => x.Post);
 modelBuilder.Entity<Post>()
            .HasOne(x => x.OriginalVersion)
            .WithOne(x => x.SecondPost);
 modelBuilder.Entity<Post>()
            .HasMany(x => x.History)
            .WithOne(x => x.ThirdPost);
2
12/17/2018 4:04:40 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow