Reputation: 3739
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
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?
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; }
}
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; }
}
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; }
}
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; }
}
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
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:
= null!;
)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
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
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