2

Let's start with a textbook example for Blogs and Posts using code-first EntityFramework Core:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

The EF Core configurures the one-to-many relationship automatically by convension, or it can be done manually using fluent API:

internal class MyContext : DbContext
{
    // ...

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts);
            .HasForeignKey(p => p.BlogId);
    }
}

Fine. Now I would like to add an optional FeaturedPost to a Blog.

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public ICollection<Post> Posts { get; set; }
    
    public Post FeaturedPost { get; set; }
}

What would be the recommended way of configuring such additional relationship (preserving the original one-to-many relationship) in EF Core? Automatic confuguration results in exception and I fail to figure out how to achieve this manually.

1
  • 3
    Hey @seilgeir, it would be helpful if you posted what the exception you get is. Commented Mar 30, 2021 at 6:15

1 Answer 1

3

You could take a look to this other answer of mine.

But, in short, if you have multiple relationships between two types you will need to configure them using the Fluent API.

In your case, try something like this:

internal class MyContext : DbContext
{
    // ...

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .HasForeignKey(p => p.BlogId);

        modelBuilder.Entity<Blog>()
            .HasOne(b => b.FeaturedPost)
            .WithOne()
            .HasForeignKey<Blog>(b => b.FeaturedPostId); 

        // You should add a int? FeaturedPostId property in your Blog class.
        // Having a nullable FK will make it optional.

    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

I would recommend a nullable FeaturedPostId. If posts require a blog and blogs require a post, maintaining referencial integrity will always be a nightmare.
@grek40 not only that, but also the OP asked for an optional FeaturedPostId explicitly 😅, completely forgot about that. Have updated my answer, thank :)
Indeed @grek40 making FeaturedPostId nullable was what I've been missing, that fixed the model :-)
@seilgeir yes, if you don't make it nullable it won't be optional, and then you have a chicken-and-egg problem when saving (Post requires BlogId, and Blog requires FeaturedPostId, but none are created yet). Making one optional solves the issue because Post can be created without having the FK yet. Btw there is a good answer related to that stackoverflow.com/a/42734093/10648865
@dglozano I was confused because I have (among other things) tried to configure the relation with .IsRequired(false) but that did not make any change (the field in the database was still created as NOT NULL). Shouldn't this .IsRequired(false) throw if the corresponding foreign key property is not nullable?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.