The Problem with null
in Entity Framework
To fix your problem, try this:
//[Required] <<< remove this
...
public string CFName { get; set; } = null;// set default value to null
Here is the Confusion
For starters, a string property in C# is a reference type. That means by default its a nullable type
and can be assigned null
or any other value
. They do NOT need to be decorated with nullable operators (like string?) to be nullable or accept null values. But by Microsoft's definition now, they are called "uninitialized non-nullable properties". Crazy huh?
Second of all, most forget, but null
is an actual value. So it is better than NOT assigning anything to a variable or property. An uninitialized variable, field, or property cannot be used till a value is assigned. That is especially true in Entity Framework.
The confusion is the fact that Entity Framework classes when instantiating your entity classes to receive or assign data to the database must auto-assign values to all your properties. In the case of Value Types like int
its pretty easy as those have three possible states: An assigned value
, null
if set as nullable, or a default value which is 0
if not nullable.
When using strings
in Entity Framework it is a whole different ball game...
For starters, Reference Types like string
or object
(your Types) in Entity Framework now trigger a null check error during compilation. Why? They should default to null
, right?
The reason is they now fall into a state of either non-null
or maybe-null
(Microsoft definitions) now. All reference types are nullable
types plus can accept nulls
. But if not explicitly assigned a value, like a nullable type or empty string, remain vulnerable to unexpected null assignments. So EF and the compiler does not like them! They actually become maybe-nulls
. This means that Entity Framework does not know what the default should be, null or not null, nor if the table column should accept NULL. By default in EF, using code first, plain string types therefore create non-null columns, which adds more confusion (and likely what the poster experienced).
The best way to settle all this is to just be as explicit as possible and avoid [Required] which does not help with defining the intent, since you can still assign a default of null which goes against the use of required properties.
A better way I have found is to set the property in your entity classes to either explicitly support non-nulls or nulls using defaults, and add the nullable
operator (?) to your strings if they will possibly be nullable in the database, as shown below. Realize that reference types remain as nullable and null-accepting types by default, even if not explicitly decorated with nullable operators. But to the new compilers, they trigger warnings now because they fall into that gray area of maybe-nulls
until you explicitly define them and give them a default value:
// These support a null in the database and defaults
// to null if no value provided. But are not clear in intent.
public string CFName { get; set; } = null;
public string CFName { get; set; } = default;// same as null
// BETTER : These explicitly support the string
// as a nullable type and set a null default for nullable columns
public string? CFName { get; set; } = null;
public string? CFName { get; set; } = default;// same as null
// For support of non-null database columns and strings
// add an empty string default!
public string CFName { get; set; } = string.Empty;
//public string CFName { get; set; } = default;// NO! this is null!
In the last case, notice string still defaults to null
! To me, that means several things. All strings
and objects
will always support null. No decoration can stop them from using or being null
, though your tell the compiler your expectations. nullable(?
) and null-forgiving(!
) operators do not really help as these types still have the same behavior away from these code points.
Using the keyword "default" which then turns into "null" on a a type without a nullable operator proves that fact!
Explicitly setting a non-null value on on implicit null like a reference type does not change their basic behavior in .NET and should not. And that is part of the confusion. This whole system they added is mostly for the compilers and the new null alert system they added, not your logic and how types can and should be used, which is using null assignments.
We all hate null exceptions and they are the bane of C# programming, for sure. But to me in C# it is better to check for nulls as a "best practices" habit than let compiler warnings do it for you.
So that is my advice.