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

[RevEng] Output the HasColumnType() and HasMaxLength() APIs correctly #4348

Merged
merged 1 commit into from
Jan 27, 2016

Conversation

lajones
Copy link
Contributor

@lajones lajones commented Jan 20, 2016

Fix for #4312.

For SQL Server this means for nvarchar columns (or synonyms) we use HasMaxLength() and not HasColumnType(), for other string types we use HasColumnType() and not HasMaxLength(). Similarly for varbinary (or synonyms) use HasMaxLength() and not HasColumnType(), but for other binary column types use HasColumnType() and not HasMaxLength().

@@ -18,6 +19,11 @@ public class SqlServerScaffoldingModelFactory : RelationalScaffoldingModelFactor
{
private const int DefaultTimeTimePrecision = 7;

private static readonly ISet<string> _dataTypesForbiddingLength =
Copy link
Contributor

Choose a reason for hiding this comment

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

Anyway we can capture this in the SqlServer type mapper? I thought it was already designed to handle lengths.

@natemcmaster
Copy link
Contributor

Seems like we could make improvements to reuse type mapping API. Perhaps we need new API, such as IRelationalTypeMapper.FindMapping(string typeName, int length). We already have some API for handling sized type mappings (RelationalSizedTypeMapping)

Thoughts on this @ajcvickers ?

@lajones
Copy link
Contributor Author

lajones commented Jan 20, 2016

@natemcmaster @ajcvickers Nit: It would definitely have to be int? length.

The problem is that different data types interpret having a null max length differently. For image, text etc it is legal (in fact expected) and means "max length doesn't apply to this data type", for nvarchar, varbinary etc it means "equivalent to nvarchar(max), varbinary(max)" etc. For other types it would make no sense (e.g. nchar, char) and would be an error.

@natemcmaster
Copy link
Contributor

It would definitely have to be int? length.

Or an overload.

The problem is that different data types interpret having a null max length differently....

To clarify, my point was that this logic could be placed in SqlServerTypeMapper instead of SqlServerScaffoldModelFactory.

@lajones
Copy link
Contributor Author

lajones commented Jan 21, 2016

@natemcmaster Sort of. This is not just about type mapping. It would be perfectly legal for us to output e.g. HasColumnType("nvarchar(100)") but we have chosen instead to write out HasMaxLength(100) and rely on the fact that the code we produce will define the CLR type for that column as a string and the default mapping for a string is back to nvarchar.

So in the end we need 2 pieces of information out: 1) should we use HasColumnType() or HasMaxLength() and 2) if HasColumnType(), what is the full definition of the column type we want to use, including any length qualifications.

I'll try to put all of that in SqlServerTypeMapper and see what it looks like.

@lajones lajones force-pushed the 160114-lajones_Varchar_MaxLength1_01 branch from 7b34777 to e4ddc3b Compare January 21, 2016 21:16
@lajones
Copy link
Contributor Author

lajones commented Jan 21, 2016

@ajcvickers Have updated as suggested above - could you give the final sign-off since Nate is away?

@lajones
Copy link
Contributor Author

lajones commented Jan 26, 2016

Removing "Needs Review" while I rebase this on the renamed codebase and get it working again. Will put it back on when ready for review again.

@@ -36,6 +38,11 @@ public class SqlServerTypeMapper : RelationalTypeMapper
private readonly RelationalTypeMapping _decimal = new RelationalTypeMapping("decimal(18, 2)", typeof(decimal));
private readonly RelationalTypeMapping _time = new RelationalTypeMapping("time", typeof(TimeSpan));

private static readonly ISet<string> _dataTypesForbiddingMaxLength =
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "image", "ntext", "text" };

Choose a reason for hiding this comment

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

What about rowversion and uniqueidentifier - would these map to byte[] and string CLR types, respectively, and need to be excluded?

Also, I don't think date, datetime, or smalldatetime allow max length (at least per SQL Server, not sure about HasMaxLength()), but those would be excluded implicitly by CLR type in MaxLengthQualifiedDataType

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please don't review just yet - I'm in the process of updating this and will add the "Needs Review" tag back when it's ready. Nonetheless I take your point and will check those scenarios.

@lajones lajones force-pushed the 160114-lajones_Varchar_MaxLength1_01 branch from e4ddc3b to 443c52b Compare January 27, 2016 19:37
@lajones
Copy link
Contributor Author

lajones commented Jan 27, 2016

I tried to put the code in SqlServerTypeMapper but what we are doing in scaffolding right there is overriding already assigned column types and max lengths. And sometimes it's important not to override the existing values - so it's not really a generic "output column type and max length for this column" method which would be more generally useful throughout the stack - it's quite specific to what scaffolding needs. I agree such a method would be useful and I'll raise another issue to suggest looking into SqlServerTypeMapper and redesigning so that there is such a method. But for this issue, after discussion with @natemcmaster, I've moved most of the code back into SqlServerScaffoldingModelFactory. I did have to leave in one change to SqlServerTypeMapper as a binary data type should not be mapped to _varbinary otherwise it thinks its DefaultTypeName is varbinary and we end up outputting HasMaxLength() instead of HasColumnType().

That said there are real synonyms for some types e.g. varbinary has the synonym binary varying. So I've updated the tests so we now test DDL using all data types including synonyms and check that we get the correct HasColumnType() and HasMaxLength() fluent API as a result of that.

@natemcmaster
Copy link
Contributor

LGTM. :shipit:

@lajones lajones merged commit 443c52b into dev Jan 27, 2016
@lajones
Copy link
Contributor Author

lajones commented Jan 27, 2016

Checked in with commit 443c52b.

@lajones
Copy link
Contributor Author

lajones commented Jan 28, 2016

Note: opened issue #4425 to track trying to make the SqlServerTypeMapper APIs more useful as discussed with @natemcmaster.

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.

4 participants