Skip to content

Commit

Permalink
Testing for query strings and various type mapping fixes (#29051)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcvickers committed Sep 12, 2022
1 parent 7c87862 commit 1362d96
Show file tree
Hide file tree
Showing 8 changed files with 747 additions and 72 deletions.
17 changes: 15 additions & 2 deletions src/EFCore.SqlServer/Query/Internal/SqlServerQueryStringFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,25 @@ private static StringBuilder AppendPrecision(this StringBuilder builder, DbParam
return builder;
}

private static StringBuilder AppendScale(this StringBuilder builder, DbParameter parameter)
{
if (parameter.Scale > 0)
{
builder
.Append('(')
.Append(parameter.Scale.ToString(CultureInfo.InvariantCulture))
.Append(')');
}

return builder;
}

private static StringBuilder AppendPrecisionAndScale(this StringBuilder builder, DbParameter parameter)
{
if (parameter.Precision > 0
&& parameter.Scale > 0)
{
builder
return builder
.Append('(')
.Append(parameter.Precision.ToString(CultureInfo.InvariantCulture))
.Append(',')
Expand Down Expand Up @@ -161,7 +174,7 @@ public static string CreateTypeName(DbParameter parameter)
SqlDbType.SmallMoney => builder.Append("smallmoney"),
SqlDbType.Structured => builder.Append("structured"),
SqlDbType.Text => builder.Append("text"),
SqlDbType.Time => builder.Append("time").AppendPrecision(parameter),
SqlDbType.Time => builder.Append("time").AppendScale(parameter),
SqlDbType.Timestamp => builder.Append("rowversion"),
SqlDbType.TinyInt => builder.Append("tinyint"),
SqlDbType.Udt => builder.Append(sqlParameter.UdtTypeName),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class SqlServerDateTimeTypeMapping : DateTimeTypeMapping
private const string SmallDateTimeFormatConst = "'{0:yyyy-MM-ddTHH:mm:ss}'";
private const string DateTimeFormatConst = "'{0:yyyy-MM-ddTHH:mm:ss.fff}'";

private readonly SqlDbType? _sqlDbType;

// Note: this array will be accessed using the precision as an index
// so the order of the entries in this array is important
private readonly string[] _dateTime2Formats =
Expand All @@ -41,13 +43,15 @@ public class SqlServerDateTimeTypeMapping : DateTimeTypeMapping
public SqlServerDateTimeTypeMapping(
string storeType,
DbType? dbType = System.Data.DbType.DateTime2,
SqlDbType? sqlDbType = null,
StoreTypePostfix storeTypePostfix = StoreTypePostfix.Precision)
: base(
: this(
new RelationalTypeMappingParameters(
new CoreTypeMappingParameters(typeof(DateTime)),
storeType,
storeTypePostfix,
dbType))
dbType),
sqlDbType)
{
}

Expand All @@ -57,11 +61,21 @@ public SqlServerDateTimeTypeMapping(
/// 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>
protected SqlServerDateTimeTypeMapping(RelationalTypeMappingParameters parameters)
protected SqlServerDateTimeTypeMapping(RelationalTypeMappingParameters parameters, SqlDbType? sqlDbType)
: base(parameters)
{
_sqlDbType = sqlDbType;
}

/// <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 virtual SqlDbType? SqlType
=> _sqlDbType;

/// <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 All @@ -72,9 +86,13 @@ protected override void ConfigureParameter(DbParameter parameter)
{
base.ConfigureParameter(parameter);

// Workaround for a SQLClient bug
if (DbType == System.Data.DbType.Date)
if (_sqlDbType != null)
{
((SqlParameter)parameter).SqlDbType = _sqlDbType.Value;
}
else if (DbType == System.Data.DbType.Date)
{
// Workaround for a SQLClient bug
((SqlParameter)parameter).SqlDbType = SqlDbType.Date;
}

Expand All @@ -97,7 +115,7 @@ protected override void ConfigureParameter(DbParameter parameter)
/// <param name="parameters">The parameters for this mapping.</param>
/// <returns>The newly created mapping.</returns>
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new SqlServerDateTimeTypeMapping(parameters);
=> new SqlServerDateTimeTypeMapping(parameters, _sqlDbType);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Data;
using Microsoft.Data.SqlClient;

namespace Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;

Expand All @@ -13,6 +14,8 @@ namespace Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
/// </summary>
public class SqlServerDecimalTypeMapping : DecimalTypeMapping
{
private readonly SqlDbType? _sqlDbType;

/// <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 All @@ -24,14 +27,15 @@ public SqlServerDecimalTypeMapping(
DbType? dbType = System.Data.DbType.Decimal,
int? precision = null,
int? scale = null,
SqlDbType? sqlDbType = null,
StoreTypePostfix storeTypePostfix = StoreTypePostfix.PrecisionAndScale)
: base(
: this(
new RelationalTypeMappingParameters(
new CoreTypeMappingParameters(typeof(decimal)),
storeType,
storeTypePostfix,
dbType)
.WithPrecisionAndScale(precision, scale))
.WithPrecisionAndScale(precision, scale), sqlDbType)
{
}

Expand All @@ -41,19 +45,29 @@ public SqlServerDecimalTypeMapping(
/// 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>
protected SqlServerDecimalTypeMapping(RelationalTypeMappingParameters parameters)
protected SqlServerDecimalTypeMapping(RelationalTypeMappingParameters parameters, SqlDbType? sqlDbType)
: base(parameters)
{
_sqlDbType = sqlDbType;
}

/// <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 virtual SqlDbType? SqlType
=> _sqlDbType;

/// <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>
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
=> new SqlServerDecimalTypeMapping(parameters);
=> new SqlServerDecimalTypeMapping(parameters, _sqlDbType);

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand All @@ -65,6 +79,11 @@ protected override void ConfigureParameter(DbParameter parameter)
{
base.ConfigureParameter(parameter);

if (_sqlDbType != null)
{
((SqlParameter)parameter).SqlDbType = _sqlDbType.Value;
}

if (Size.HasValue
&& Size.Value != -1)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,17 @@ private readonly SqlServerByteArrayTypeMapping _fixedLengthBinary
private readonly SqlServerDateTimeTypeMapping _date
= new("date", DbType.Date);

private readonly SqlServerDateTimeTypeMapping _smallDatetime
= new("smalldatetime", DbType.DateTime, SqlDbType.SmallDateTime);

private readonly SqlServerDateTimeTypeMapping _datetime
= new("datetime", DbType.DateTime);

private readonly SqlServerDateTimeTypeMapping _datetime2
= new("datetime2", DbType.DateTime2);

private readonly SqlServerDateTimeTypeMapping _datetime2Alias
= new("placeholder", DbType.DateTime2, StoreTypePostfix.None);
= new("placeholder", DbType.DateTime2, null, StoreTypePostfix.None);

private readonly DoubleTypeMapping _double
= new SqlServerDoubleTypeMapping("float");
Expand All @@ -113,7 +116,7 @@ private readonly GuidTypeMapping _uniqueidentifier
= new("uniqueidentifier");

private readonly DecimalTypeMapping _decimal
= new SqlServerDecimalTypeMapping("decimal");
= new SqlServerDecimalTypeMapping("decimal", precision: 18, scale: 0);

private readonly DecimalTypeMapping _decimalAlias
= new SqlServerDecimalTypeMapping("placeholder", precision: 18, scale: 2, storeTypePostfix: StoreTypePostfix.None);
Expand All @@ -122,7 +125,11 @@ private readonly DecimalTypeMapping _decimal182
= new SqlServerDecimalTypeMapping("decimal(18, 2)", precision: 18, scale: 2);

private readonly DecimalTypeMapping _money
= new SqlServerDecimalTypeMapping("money", storeTypePostfix: StoreTypePostfix.None);
= new SqlServerDecimalTypeMapping("money", DbType.Currency, sqlDbType: SqlDbType.Money, storeTypePostfix: StoreTypePostfix.None);

private readonly DecimalTypeMapping _smallMoney
= new SqlServerDecimalTypeMapping(
"smallmoney", DbType.Currency, sqlDbType: SqlDbType.SmallMoney, storeTypePostfix: StoreTypePostfix.None);

private readonly TimeSpanTypeMapping _time
= new SqlServerTimeSpanTypeMapping("time");
Expand Down Expand Up @@ -214,9 +221,9 @@ public SqlServerTypeMappingSource(
{ "nvarchar(max)", _variableLengthMaxUnicodeString },
{ "real", _real },
{ "rowversion", _rowversion },
{ "smalldatetime", _datetime },
{ "smalldatetime", _smallDatetime },
{ "smallint", _short },
{ "smallmoney", _money },
{ "smallmoney", _smallMoney },
{ "sql_variant", _sqlVariant },
{ "text", _textAnsiString },
{ "time", _time },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ public virtual void Create_and_clone_with_converter(Type mappingType, Type type)
null,
null);

AssertClone(type, mapping);
}

protected static RelationalTypeMapping AssertClone(Type type, RelationalTypeMapping mapping)
{
var clone = mapping.Clone("<clone>", null);

Assert.NotSame(mapping, clone);
Expand Down Expand Up @@ -97,6 +102,8 @@ public virtual void Create_and_clone_with_converter(Type mappingType, Type type)
Assert.Same(mapping.ProviderValueComparer, clone.ProviderValueComparer);
Assert.Same(typeof(object), clone.ClrType);
Assert.Equal(StoreTypePostfix.PrecisionAndScale, clone.StoreTypePostfix);

return clone;
}

[ConditionalFact]
Expand Down Expand Up @@ -230,7 +237,7 @@ protected virtual void UnicodeConversionCloneTest(
Assert.Equal(StoreTypePostfix.Size, clone.StoreTypePostfix);
}

private class FakeTypeMapping : RelationalTypeMapping
protected class FakeTypeMapping : RelationalTypeMapping
{
private FakeTypeMapping(RelationalTypeMappingParameters parameters)
: base(parameters)
Expand Down
Loading

0 comments on commit 1362d96

Please sign in to comment.