简体   繁体   中英

How to configure foreign key in Entity Framework without an inverse navigation property?

I am new to Entity Framework and I am trying to get a couple models to work. I'll use the entities from this microsoft doc as an example, since it is the one I am following to guide myself up.

My entities (without the non-relevant properties) look something like this:

public class Blog
{
    public Guid Id { get; set; }
    public List<Post> Posts { get; set; } = new List<Post>();
}

public class Post
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
}

But my database looks like this:

Blogs table

Column Type
Id uniqueidentifier

Posts table

Column Type
Id uniqueidentifier
Title nvarchar
Content nvarchar
BlogId uniqueidentifier

Notice the foreign key BlogId in the Posts table. Also notice that it the property is not explicitly defined in the Post entity in code.

When I try to do an insert using EF I get the following error:

fail: Microsoft.EntityFrameworkCore.Update[10000]
An exception occurred in the database while saving changes for context type 'MyNamespace.DatabaseContext'.
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while saving the entity changes. See the inner exception for details.
Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'BlogId', table 'Posts'; column does not allow nulls. INSERT fails.

It is trying to insert a NULL value to the BlogId column in the Posts table, but I want it to grab the id from the Blog object in which that Post object is defined. (Posts cannot exist outside a blog, so they should always be defined inside a List<Posts> )

What I have done is the following:

public class DatabaseContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    public DatabaseContext()
    {
    }

    public DatabaseContext(DbContextOptions<DatabaseContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasMany<Post>(b => b.Posts);

        modelBuilder.Entity<Post>()
            .HasOne<Blog>()
            .WithMany(b => b.Posts)
            .HasForeignKey(b => b.Id);
    }
}

Here is my question: how can make EF grab the id from the blog containing the post without adding a BlogId property to the Post model? Is it even possible or am I forced to adjust my model's properties?

Also, I am using EF with a database-first approach.

Edit : some more information on the code.

The API receives the id of the Blog and the post's properties to create a new post in that blog. After that a commands runs that

...
var blog = await context.Set<Blog>().FindAsync(
    keyValues: new object?[] { id }, cancellationToken);
blog.Posts.Add(new Post
{
    Title = title,
    Content = content
});
await context.SaveChangesAsync(cancellationToken);

Since you are using database first you can create the tables with foreign key and type this command

Scaffold-DbContext "Server=localhost;Database=[DatabaseName];Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -force

and EF will generate models for you in Models folder

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM