Search code examples
c#asp.net-core.net-coreentity-framework-core

How come EF Core is able to assign NULL to a non-nullable property?


NRT is enabled.

I have the following models:

public class Blog
{
    public int Id { get; set; }
    public string Url { get; set; }
    public Header Header { get; set; }
}

public class Header
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

According to docs, EF Core respects NRT and will use it to set columns to be nullable or not if NRT is enabled, which it is.

Now, I know that having Header be non-nullable in a principal entity doesn't make sense, but EF Core is completely ignoring it. I can even create a Blog without any Header linked! A Header will be set to NULL if I create a blog without a header.

It's also frustrating, even though it makes sense, that the compiler thinks it can't be NULL yet it is!

The migration code is:

migrationBuilder.CreateTable(
                name: "Blogs",
                columns: table => new
                {
                    Id = table.Column<int>(type: "INTEGER", nullable: false)
                        .Annotation("Sqlite:Autoincrement", true),
                    Url = table.Column<string>(type: "TEXT", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Blogs", x => x.Id);
                });

migrationBuilder.CreateTable(
                name: "Headers",
                columns: table => new
                {
                    Id = table.Column<int>(type: "INTEGER", nullable: false)
                        .Annotation("Sqlite:Autoincrement", true),
                    Title = table.Column<string>(type: "TEXT", nullable: false),
                    BlogId = table.Column<int>(type: "INTEGER", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Headers", x => x.Id);
                    table.ForeignKey(
                        name: "FK_Headers_Blogs_BlogId",
                        column: x => x.BlogId,
                        principalTable: "Blogs",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                });

How come EF Core is able to assign NULL to a non-nullable property?


Solution

  • As you say, Blog is the principal entity. Hence table Blog doesn't have a HeaderId, so the database allows Blogs without Headers. It even has no way to enforce Blogs to have Headers.

    EF core has always followed the line of making validation a developer-responsibility and I think that's why they allow the entity model to do what the database allows. They're not going to validate it for you.

    As for reading: you can configure Blog.Header as auto-include.

    Even then, you can still get a null value in Blog.Header, note that NRT is nothing but a compiler feature that issues warnings at compile-time where code may throw a NRE. It doesn't change anything on actual nullability of reference types. I.e. Blog.Header can always be null. It's not a problem for C# with NRT enabled and EF chooses to not make it their problem.