Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-nullable bool column with default constraint #8777

Closed
wants to merge 2 commits into from

Conversation

lajones
Copy link
Contributor

@lajones lajones commented Jun 8, 2017

Fix for #8400.

If Reverse Engineering would map a non-nullable column to a non-nullable bool property but the column has a default constraint then a) map it to a nullable bool property instead and b) issue a warning message.

This is to allow the user of the generated classes to distinguish between actively setting the property to 'false' and not setting the property and allowing the default constraint to generate the value in the database.

default constraint then a) map it to a nullable bool property and b)
issue a warning message.
/// A column would be mapped to a bool type, is non-nullable and has a default constraint.
/// This event is in the <see cref="DbLoggerCategory.Scaffolding" /> category.
/// </summary>
public static readonly EventId NonNullableBoooleanColumnHasDefaultConstraintWarning = MakeScaffoldingId(Id.NonNullableBoooleanColumnHasDefaultConstraintWarning);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are not logging DiagnosticSource event then where are these ids used?
cc: @ajcvickers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ajcvickers for response to this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still the event ID for the ILogger message.

{
if (forceNullable)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move warning outside of this if block & right after checking conditions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could. Don't feel it makes make much difference.

@@ -310,8 +310,14 @@ protected virtual PropertyBuilder VisitColumn([NotNull] EntityTypeBuilder builde
}

var clrType = typeScaffoldingInfo.ClrType;
if (column.IsNullable)
var forceNullable = typeof(bool) == clrType && column.DefaultValue != null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create variable nullable taking value from Column.IsNullable & update the variable if conditions match (in same block as log message)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a relatively minor point, but I think the way it is now is much clearer. I think it's good for the developer to know that this is happening because nullability is being forced by the scaffolding, rather than it being any intrinsic property of the underlying database model. By saying forceNullable you are explaining that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its minor point but no need to compute same thing multiple times, if we are having extra variable then why not use it in well way. We start with value in database, we update the variable with whatever conditions comes up and we set nullability based on that. Today its 2 conditions, it may expand more in future. Its better to right a condensed code. We don't need variables to explain what is happening. Logging message would make it very clear why we decided to introduce nullability. And if still doesn't look very clear, feel free to write a comment for explanation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need to issue the warning message only if you are forcing nullability - and not just because something is nullable - so you will need the forceNullable variable (or at least an if statement with the same logic). I could create forceNullable and then immediately create nullable as well to do what you want. If the variable name was something like wasNullableInDatabaseOrNullabilityWasForced I'd be OK with it. But that's ridiculously long. Personally I find the other way much clearer so I'm going to stick with it for now.

@@ -361,7 +367,7 @@ protected virtual PropertyBuilder VisitColumn([NotNull] EntityTypeBuilder builde

if (!column.PrimaryKeyOrdinal.HasValue)
{
property.IsRequired(!column.IsNullable);
property.IsRequired(!column.IsNullable && !forceNullable);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be just !nullable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above - I think this is better.

public partial class NonNullBoolWithDefault
{
public int Id { get; set; }
public bool? TestWithDefault { get; set; }
Copy link
Member

@smitpatel smitpatel Jun 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BooleanWithDefaultValueSql and likewise for other property & classname

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Don't think it's important as the test already explains that but OK. Why the Sql addition?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just because it is Bool property with DefaultValueSql set. Becomes more explicit and easy to evaluate the expected output file as in fluent API, you can check if the property has HasDefaultValueSql generated. It's not important but being more explicit in test not gonna hurt and helps person to read the tests more easily.

Copy link
Contributor Author

@lajones lajones Jun 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought bool was obvious a) from the name of the test and b) from the produced type. And actually HasDefaultValueSql() is the choice of the scaffolder - it could (and did in the past) do something different if it wanted. The fact that the underlying database model has ColumnModel.DefaultValue set is what's being tested. But OK - like I say I don't think it really matters.

/// </summary>
public static readonly EventDefinition<string> LogNonNullableBoooleanColumnHasDefaultConstraint
= new EventDefinition<string>(
DesignEventId.NonNullableBoooleanColumnHasDefaultConstraintWarning,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used here.

@@ -584,6 +584,18 @@ public static string ExistingFiles([CanBeNull] object outputDirectoryName, [CanB
DesignEventId.ForeignKeyPrincipalEndContainsNullableColumnsWarning,
_resourceManager.GetString("LogForeignKeyPrincipalEndContainsNullableColumns")));

/// <summary>
/// The column '{columnName}' 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@divega fwlink this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lajones - wait for this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ajcvickers @smitpatel @divega are we doing a fwlink within the warning message? I didn't see a response from @divega

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lajones I will have it in a couple of minutes. Trying to pick a temporary landing page for it until we have the actual topic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @divega. I'll add this to the message and check in.

@lajones
Copy link
Contributor Author

lajones commented Jun 9, 2017

@smitpatel @ajcvickers I think I've addressed everything. So I'm going to go ahead and check in soon. Let me know if I shouldn't.

@smitpatel
Copy link
Member

Also can you rebase on latest dev, both CI services are red.

@lajones
Copy link
Contributor Author

lajones commented Jun 9, 2017

@smitpatel Sure. Np.

@lajones
Copy link
Contributor Author

lajones commented Jun 9, 2017

Checked in with commit 61650f8.

@lajones lajones closed this Jun 9, 2017
@lajones lajones added this to the 2.0.0 milestone Jun 9, 2017
@lajones lajones self-assigned this Jun 9, 2017
@lajones lajones deleted the 170607_8004_BoolDefConstraint_03 branch June 9, 2017 20:30
@lajones lajones added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jun 9, 2017
@ryanelian
Copy link

ryanelian commented Sep 1, 2017

Excuse me, can I do something to disable this behavior?

I'm trying to re-scaffold a database context for an existing project from an existing database (schema manually managed / updated by SQL) after upgrading to ASP.NET Core 2.0 but suddenly EF Core puts ? to many columns within the entity classes, causing over 122 compile errors...

EDIT: oh lmao #9627

😕

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants