Efcore: Scaffold mapping on non-nullable bool

Created on 31 Jan 2018  路  10Comments  路  Source: dotnet/efcore

Our DB columns are defined as such in a table:

[IsActive] BIT CONSTRAINT [DF_IsActive] DEFAULT ((1)) NOT NULL
[IsDeleted] BIT CONSTRAINT [DF_IsDeleted] DEFAULT ((0)) NOT NULL

The scaffold used to produce:
public bool? IsActive { get; set; }
public bool? IsDeleted { get; set; }
It would also emit a warning like the following for both the IsActive and IsDeleted columns:

The column 'scUtil.BatchEvent.IsActive' would normally be mapped to a non-nullable bool property, but it has a default constraint. Such a column is mapped to a nullable bool property to allow a difference between setting the property to false and invoking the default constraint. See https://go.microsoft.com/fwlink/?linkid=851278 for details.

However after updating to the latest NuGet packages is seems to be producing this:
public bool? IsActive { get; set; }
public bool IsDeleted { get; set; }

Note that IsDeleted is no longer nullable and we only see warnings emitted for the IsActive column.

I guess I do not understand the decision in the first place to make them nullable and then why again it seems things may have changed? The columns are not null and have a default in the DB. Can't the scaffold be smart enough to allow me to set it like I want it. For example:

    public bool IsActive { get; set; } = true;
    public bool IsDeleted { get; set; } = false;

It would be up to us to make sure that a value was passed into the Entity to set those values accordingly when we did an update would it not? I understand the warning message but cant we have a switch to set the behavior to what we want and keep it that way so we can have consistency across versions?

Further technical details

EF Core version: v2.0.1 - Design, SqlServer and Tools
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Win 10 latest patches
IDE: Visual Studio 2017 15.5.6

closed-question

Most helpful comment

Yeah I am not onboard with this reasoning. In my case I have created a default constraint so that if I happen to find myself inserting rows directly into the db i do not need to provide values for some columns. I have not created it to facilitate/assist with my application logic at all.

Db scaffold's attempt at using defaults to facilitate some kind of highly assumptive "smart" behaviour is a boondoggle. Did anyone actually ask for this feature?

All 10 comments

There are three possible values to INSERT into a BIT column:

  • 0
  • 1
  • NULL (Use the DEFAULT constraint)

If a BIT column has a DEFAULT constraint, we make the property nullable regardless of whether it has a NOT NULL constraint. This allow you to use the default value in EF.

We recently made an optimization where if the DEFAULT value is 0 and the column has NOT NULL, there is no need to make the property nullable since inserting NULL and 0 are equivalent.

For additional reasoning as to why we make it nullable at all, imagine the following column:

[NeedsReview] BIT DEFAULT (RAND() % 2) NOT NULL

No column will contain NULL, but when saving you entity, you have three choices:

  • Save false
  • Save true
  • Save null letting the database pick

I guess I see the logic but our downstream code is expecting the IsDeleted field in the Model to be nullable and now it is not. The optimization has broken our code base as the expected result of the scaffold has changed. So my question is there a switch that can be used to set it up the way we had it. Or do we have to accept the breaking change to move forward?

Added a note to #9627 about adding a flag to change the way default values are handled in the database. Also, this should be less of an issue once update-from-database is implemented (see issue #831) since the database won't need to be fully reverse engineered each time it is changed.

Thanks all! Greatly appreciate the consideration! :-)

@bricelam Thanks for the explanation. I can fully accept your reasoning behind this.
But given that, are we supposed to see this warning every time we scaffold (for every column with these properties)? We have a no warning policy in most our projects. Is there any way to disable it, or mark it as "ok got it, don't show me anymore"?

@memark what exact warning are you seeing?

@bricelam I'm referring to this

The column 'dbo.Equipment.IsActive' would normally be mapped to a non-nullable bool property, but it has a default constraint. Such a column is mapped to a nullable bool property to allow a difference between setting the property to false and invoking the default constraint. See https://go.microsoft.com/fwlink/?linkid=851278 for details.

There is currently no way to suppress design-time warnings. However, they only occur once when running the tool and not, for example, every time you build or run your app.

Yeah I am not onboard with this reasoning. In my case I have created a default constraint so that if I happen to find myself inserting rows directly into the db i do not need to provide values for some columns. I have not created it to facilitate/assist with my application logic at all.

Db scaffold's attempt at using defaults to facilitate some kind of highly assumptive "smart" behaviour is a boondoggle. Did anyone actually ask for this feature?

Was this page helpful?
0 / 5 - 0 ratings