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

Names for the primary key would be generated the same in all cases #1803

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

TheSquidCombatant
Copy link

Eliminated the difference between classes DefaultConstraintNameConvention and DefaultPrimaryKeyNameConvention in the default generated primary key name. See issue #1800.

@jzabroski jzabroski self-requested a review May 19, 2024 12:20
Copy link
Collaborator

@jzabroski jzabroski left a comment

Choose a reason for hiding this comment

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

In general, I don't think I will accept this PR but I left what I hope are helpful comments as to why.

I will look at the original issue this PR was conceived from and see if there is a simpler approach.

@@ -29,23 +32,24 @@ public class DefaultPrimaryKeyNameConvention : IColumnsConvention
/// <inheritdoc />
public IColumnsExpression Apply(IColumnsExpression expression)
{
if (expression.Columns.Count(x => x.IsPrimaryKey) > 1)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't understand why this is something that should be discouraged. It is perfectly valid for a table to have a primary key with multiple columns.

Copy link
Author

Choose a reason for hiding this comment

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

One primary key on many columns is good. But here we are talking specifically about multiple primary keys, each with its own name, am I wrong?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I am pretty sure you are wrong. But your questioning my statement honestly gives me pause. But I'm 99% sure if I integration test this on a compound key, it will fail.

foreach (var columnDefinition in expression.Columns)
{
if (string.IsNullOrEmpty(columnDefinition.Name))
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be handled through validation logic. There is a separate layer in the framework for validation of expressions.

Copy link
Author

Choose a reason for hiding this comment

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

This part of the code is about use column names. Isn't it good to recognize the error as early as possible? To which specific class do you propose to move this check?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why separate the two? Same reason you would separate input validation from a Controller Action method in ASP.NET MVC - it keeps the core business logic focused on the actual problem domain and allows for more precise errors / warnings if done as a ValidationResult rather than throwing an exception. If you throw, you lose Metadata that could be used to build even more nicer error messages, too - similar to what Patrik Svensson's SpectreConsole does. In general, throwing exceptions for input validation also prevents "railway oriented programming" where the client gets back a object representing success or failure.

That being said, our Validation layer isn't the best. I realize that's frustrating feedback considering I just told you to use it, but it was pretty good 7 years ago - but third party libraries like FluentValidation have made insane leaps forward since then. We currently pattern the existing one of off System.ComponentModel.DataAnnotations.Validator. I need to delete the areas of the code that still reference CollectErrors, as they have been marked obsolete for awhile.

But:

1.The interface for adding validation is here but doesn't let you explicitly handle each expression root type - you would have to do type tests and dispatch off a Type-switch (probably to something like FluentValidation): https://github.com/fluentmigrator/fluentmigrator/blob/main/src%2FFluentMigrator.Abstractions%2FValidation%2FIMigrationExpressionValidator.cs
2. The default implementation should be replaced here: https://github.com/fluentmigrator/fluentmigrator/blob/main/src%2FFluentMigrator.Abstractions%2FValidation%2FDefaultMigrationExpressionValidator.cs

  1. The CLI tool supports a Validate command. https://github.com/fluentmigrator/fluentmigrator/blob/main/src%2FFluentMigrator.DotNet.Cli%2FCommands%2FValidate.cs
  2. Each Model XxxDefinition class and XxxExpression class has a Validate member.

if (columnDefinition.IsPrimaryKey && string.IsNullOrEmpty(columnDefinition.PrimaryKeyName))
{
var tableName = string.IsNullOrEmpty(columnDefinition.TableName)
? expression.TableName
: columnDefinition.TableName;
columnDefinition.PrimaryKeyName = GetPrimaryKeyName(tableName);
columnDefinition.PrimaryKeyName = $"PK_{tableName}_{columnDefinition.Name}";
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the current behavior is what most users prefer. The actual column name(s) don't really matter to most developers except when needing to change the data type, as that requires dropping and recreating the column name.

Additionally, most DB engines like SQL Server have limit of, say, 255 characters for system object names.

Awhile ago I had the idea of an Opinions assembly that has a different set of default conventions and even some syntax shortcuts. This could live in something like that.

Copy link
Author

Choose a reason for hiding this comment

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

@jzabroski

I think the current behavior is what most users prefer. The actual column name(s) don't really matter to most developers except when needing to change the data type, as that requires dropping and recreating the column name.

If the column name doesn't matter then why shouldn't it be deterministic?

Additionally, most DB engines like SQL Server have limit of, say, 255 characters for system object names.

If the name is too long the user will just get an exception, as in the case of DefaultConstraintNameConvention.

Awhile ago I had the idea of an Opinions assembly that has a different set of default conventions and even some syntax shortcuts. This could live in something like that.

I don't think this is a good enough reason to complicate the project's ecosystem.

Copy link
Collaborator

Choose a reason for hiding this comment

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

From reading the original issue, it sounds like Create.PrimaryKey() uses DefaultConstraintNameConvention - this is a bug. It should use DefauktPrimaryKeyNameConvention.

Default constraints should just be for default values specified by the ANSI SQL DDL DEFAULT keyword.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants