Skip to content

Commit

Permalink
SQLite Scaffolding: Use column type and values to provide a better CL…
Browse files Browse the repository at this point in the history
…R type

Here's a table highlighting some of the improvements.

Column type | Sample value                           | Before | After
----------- | -------------------------------------- | ------ | -----
BOOLEAN     | 0                                      | byte[] | bool
SMALLINT    | 0                                      | long   | short
INT         | 0                                      | long   | int
BIGINT      | 0                                      | long   | long
TEXT        | '0.0'                                  | string | decimal
TEXT        | '1970-01-01'                           | string | DateOnly
TEXT        | '1970-01-01 00:00:00'                  | string | DateTime
TEXT        | '00:00:00'                             | string | TimeSpan
TEXT        | '00000000-0000-0000-0000-000000000000' | string | Guid
STRING      | 'ABC'                                  | byte[] | string

Resolves dotnet#8824
  • Loading branch information
bricelam committed May 9, 2023
1 parent c63634b commit 794e31c
Show file tree
Hide file tree
Showing 13 changed files with 901 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ public static class ScaffoldingAnnotationNames
/// </summary>
public const string ConcurrencyToken = "ConcurrencyToken";

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public const string ClrType = "ClrType";

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ public interface IScaffoldingTypeMapper
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
TypeScaffoldingInfo? FindMapping(string storeType, bool keyOrIndex, bool rowVersion);
TypeScaffoldingInfo? FindMapping(string storeType, bool keyOrIndex, bool rowVersion, Type? clrType = null);
}
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,8 @@ protected virtual EntityTypeBuilder VisitColumns(EntityTypeBuilder builder, ICol

property.Metadata.AddAnnotations(
column.GetAnnotations().Where(
a => a.Name != ScaffoldingAnnotationNames.ConcurrencyToken));
a => a.Name != ScaffoldingAnnotationNames.ConcurrencyToken
&& a.Name != ScaffoldingAnnotationNames.ClrType));

return property;
}
Expand Down Expand Up @@ -967,7 +968,8 @@ protected virtual List<string> ExistingIdentifiers(IReadOnlyEntityType entityTyp
return _scaffoldingTypeMapper.FindMapping(
column.StoreType,
column.IsKeyOrIndex(),
column.IsRowVersion());
column.IsRowVersion(),
(Type?)column[ScaffoldingAnnotationNames.ClrType]);
}

private static void AssignOnDeleteAction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ public ScaffoldingTypeMapper(IRelationalTypeMappingSource typeMappingSource)
public virtual TypeScaffoldingInfo? FindMapping(
string storeType,
bool keyOrIndex,
bool rowVersion)
bool rowVersion,
Type? clrType = null)
{
var mapping = _typeMappingSource.FindMapping(storeType);
var mapping = clrType is null
? _typeMappingSource.FindMapping(storeType)
: _typeMappingSource.FindMapping(clrType, storeType);
if (mapping == null)
{
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,28 @@ public class SqliteLoggingDefinitions : RelationalLoggingDefinitions
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public EventDefinitionBase? LogCompositeKeyWithValueGeneration;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public EventDefinitionBase? LogInferringTypes;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public EventDefinitionBase? LogOutOfRangeWarning;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public EventDefinitionBase? LogFormatWarning;
}
29 changes: 28 additions & 1 deletion src/EFCore.Sqlite.Core/Diagnostics/SqliteEventId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ private enum Id
PrimaryKeyFound,
SchemasNotSupportedWarning,
TableFound,
UniqueConstraintFound
UniqueConstraintFound,
InferringTypes,
OutOfRangeWarning,
FormatWarning
}

private static readonly string ValidationPrefix = DbLoggerCategory.Model.Validation.Name + ".";
Expand Down Expand Up @@ -213,4 +216,28 @@ private static EventId MakeScaffoldingId(Id id)
/// This event is in the <see cref="DbLoggerCategory.Scaffolding" /> category.
/// </remarks>
public static readonly EventId UniqueConstraintFound = MakeScaffoldingId(Id.UniqueConstraintFound);

/// <summary>
/// Inferring CLR types.
/// </summary>
/// <remarks>
/// This event is in the <see cref="DbLoggerCategory.Scaffolding" /> category.
/// </remarks>
public static readonly EventId InferringTypes = MakeScaffoldingId(Id.InferringTypes);

/// <summary>
/// Values are out of range for the type.
/// </summary>
/// <remarks>
/// This event is in the <see cref="DbLoggerCategory.Scaffolding" /> category.
/// </remarks>
public static readonly EventId OutOfRangeWarning = MakeScaffoldingId(Id.OutOfRangeWarning);

/// <summary>
/// Values are in an invalid format for the type.
/// </summary>
/// <remarks>
/// This event is in the <see cref="DbLoggerCategory.Scaffolding" /> category.
/// </remarks>
public static readonly EventId FormatWarning = MakeScaffoldingId(Id.FormatWarning);
}
Original file line number Diff line number Diff line change
Expand Up @@ -413,4 +413,68 @@ private static string CompositeKeyWithValueGeneration(EventDefinitionBase defini
p.Key.DeclaringEntityType.DisplayName(),
p.Key.Properties.Format());
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static void InferringTypes(
this IDiagnosticsLogger<DbLoggerCategory.Scaffolding> diagnostics,
string? tableName)
{
var definition = SqliteResources.LogInferringTypes(diagnostics);

if (diagnostics.ShouldLog(definition))
{
definition.Log(diagnostics, tableName);
}

// No DiagnosticsSource events because these are purely design-time messages
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static void OutOfRangeWarning(
this IDiagnosticsLogger<DbLoggerCategory.Scaffolding> diagnostics,
string? columnName,
string? tableName,
string? type)
{
var definition = SqliteResources.LogOutOfRangeWarning(diagnostics);

if (diagnostics.ShouldLog(definition))
{
definition.Log(diagnostics, columnName, tableName, type);
}

// No DiagnosticsSource events because these are purely design-time messages
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static void FormatWarning(
this IDiagnosticsLogger<DbLoggerCategory.Scaffolding> diagnostics,
string? columnName,
string? tableName,
string? type)
{
var definition = SqliteResources.LogFormatWarning(diagnostics);

if (diagnostics.ShouldLog(definition))
{
definition.Log(diagnostics, columnName, tableName, type);
}

// No DiagnosticsSource events because these are purely design-time messages
}
}
75 changes: 75 additions & 0 deletions src/EFCore.Sqlite.Core/Properties/SqliteStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions src/EFCore.Sqlite.Core/Properties/SqliteStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@
<value>Skipping foreign key with identity '{id}' on table '{tableName}' since principal table '{principalTableName}' was not found in the model. This usually happens when the principal table was not included in the selection set.</value>
<comment>Warning SqliteEventId.ForeignKeyReferencesMissingTableWarning string? string? string?</comment>
</data>
<data name="LogFormatWarning" xml:space="preserve">
<value>The column '{columnName}' on table '{tableName}' should map to a property of type '{type}', but its values are in an incompatible format. Using a different type.</value>
<comment>Warning SqliteEventId.FormatWarning string? string? string?</comment>
</data>
<data name="LogFoundColumn" xml:space="preserve">
<value>Found column on table '{tableName}' with name: '{columnName}', data type: {dataType}, not nullable: {notNullable}, default value: {defaultValue}.</value>
<comment>Debug SqliteEventId.ColumnFound string? string? string? bool string?</comment>
Expand All @@ -167,10 +171,18 @@
<value>Found unique constraint on table '{tableName}' with name: {uniqueConstraintName}.</value>
<comment>Debug SqliteEventId.UniqueConstraintFound string? string?</comment>
</data>
<data name="LogInferringTypes" xml:space="preserve">
<value>Querying table '{tableName}' to determine an appropriate CLR type for each column.</value>
<comment>Debug SqliteEventId.InferringTypes string?</comment>
</data>
<data name="LogMissingTable" xml:space="preserve">
<value>Unable to find a table in the database matching the selected table '{table}'.</value>
<comment>Warning SqliteEventId.MissingTableWarning string?</comment>
</data>
<data name="LogOutOfRangeWarning" xml:space="preserve">
<value>The column '{columnName}' on table '{tableName}' should map to a property of type '{type}', but its values are out of range. Using a different type.</value>
<comment>Warning SqliteEventId.OutOfRangeWarning string? string? string?</comment>
</data>
<data name="LogPrincipalColumnNotFound" xml:space="preserve">
<value>Skipping foreign key with identity '{id}' on table '{tableName}', since the principal column '{principalColumnName}' on the foreign key's principal table, '{principalTableName}', was not found in the model.</value>
<comment>Warning SqliteEventId.ForeignKeyPrincipalColumnMissingWarning string? string? string? string?</comment>
Expand Down
Loading

0 comments on commit 794e31c

Please sign in to comment.