HelloWorld
HelloWorld

Reputation: 3739

.NET 6 nullable properties warnings for EF Core models

I'm using EF Core, and I have this model:

public class Article
{
    public int Id { get; set; }
    public User Author { get; set; } // <- CS8618
    public int AuthorId { get; set; }
}

As pointed out in the above code comment, I get an annoying nullable warning. I'm using the Fluent API to annotate my model, and obviously Author is not nullable as AuthorId is not nullable.

I feel that using User? Author instead to make the warning go away is incorrect, as the property is obviously not nullable, and it would be a lie, and also a hint to people using my model that it is nullable.

What is the proper way to deal with this situation? Suppress the warning?

Upvotes: 8

Views: 6700

Answers (5)

joakimriedel
joakimriedel

Reputation: 1951

You'd find a lot of different answers on this question

But in this particular case, I would ask myself the question: who generates instances of this class?

1a

If you are 100% relying on EF Core to generate instances of this class for you by querying the database, and you are 100% sure that you ALWAYS use the proper Include(), I would safely set the Author field to null!, which means it assigns the default value null on construction and automatically suppresses the nullability error.

public class Article
{
    public int Id { get; set; }
    public User Author { get; set; } = null!;
    public int AuthorId { get; set; }
}

1b

You could also use the above solution with a private constructor to protect that no-one else but EF Core will generate instances of this class.

public class Article
{
    private Article()
    {
        Author = null!;
    }

    public int Id { get; set; }
    public User Author { get; set; }
    public int AuthorId { get; set; }
}

2

If you generate instances of this class in any other parts of your code, you would need a constructor to ensure that Author is never null after construction.

public class Article
{
    public Article()
    {
        Author = new User();
    }

    public int Id { get; set; }
    public User Author { get; set; }
    public int AuthorId { get; set; }
}

3

If you do not allow a default User object, it would make sense to expect a null value for Author but mark it Required to ensure that it will never be null when written to database.

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

    [Required]
    public User? Author { get; set; }
    public int AuthorId { get; set; }
}

4

Use the new required keyword to enforce setting the property on construction. It does not solve the issue with the foreign key being out of sync with the object however. Setting both to required makes construction complicated, but might be necessary if you sometimes create and save entities to the database linking to other entities using just the foreign key without the full object loaded. EF Core does not like both to be set though, in those cases either property needs to be set to null! or default on construction depending on use case.

public class Article
{
    public int Id { get; set; }
    public required User Author { get; set; }
    public int AuthorId { get; set; }
}

Upvotes: 9

Free_ze
Free_ze

Reputation: 97

Common solution for domain entities is: use private default constructor for EF and public parameterized (keyless) one for explicit object creation. And there are two ways:

  1. Mark props with reference type by "promises" (= null!;)
  2. Disable warning on EF-constructor:
public class MyEntity {
    public int Id { get; [UsedImplicitly] private set; }
    public string Name { get; private set; }

    public MyEntity(string name) {
        Name = string.IsNullOrWhiteSpace(name)
            ? name
            : throw new ArgumentException(nameof(name));
    }

#pragma warning disable CS8618
    [UsedImplicitly]
    private MyEntity(){} // For EF only, allows to fill an object via setters
#pragma warning restore CS8618
}

Second approach is much better because checking still works with parameterized constructor. Private constructor makes minimal impact for type safety and doesn't require manual support.

Upvotes: 0

majed tello
majed tello

Reputation: 43

If it is possible Author to be null make the User property nullable:

public User? Author { get; set; }

If not do this :

 public User Author { get; set; } = default!;

Upvotes: -1

Yoro
Yoro

Reputation: 1730

Since C#11 (.NET 7.0) you can add a required modifier.

public class Article
{
    public int Id { get; set; }
    public required User Author { get; set; }
    public int AuthorId { get; set; }
}

And with the required modifier, you won't be able to use var article= new Article(); to create an object instance. So it's great protection for the not nullable property User.

Now to create an object instance you must do something like:

var article= new Article()
{
   User = new();
};

Originally answer was posted on: What is best way to create .NET6 class with many non-nullable properties?

More detailed info: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required

Upvotes: 10

kddinev18
kddinev18

Reputation: 74

Just put "#nullable disable" above the namespace.

Upvotes: -2

Related Questions