diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs
index f3843a9dbcb..21893c72895 100644
--- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs
+++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteUpdate.cs
@@ -861,6 +861,7 @@ static SqlExpression ProcessJsonQuery(JsonQueryExpression jsonQuery)
/// update function.
///
/// A scalar expression ready to be integrated into an UPDATE statement setter.
+ [Experimental(EFDiagnostics.ProviderExperimentalApi)] // TODO: This should probably move into the type mappings, #36729
protected virtual bool TrySerializeScalarToJson(
JsonScalarExpression target,
SqlExpression value,
diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs b/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs
index 1f96dec0ebf..677a0d3d17b 100644
--- a/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs
+++ b/src/EFCore.SqlServer/Infrastructure/Internal/ISqlServerSingletonOptions.cs
@@ -51,6 +51,18 @@ public interface ISqlServerSingletonOptions : ISingletonOptions
///
public bool SupportsJsonFunctions { get; }
+ ///
+ /// Whether the JSON_OBJECT() and JSON_ARRAY() functions are supported by the targeted
+ /// SQL Server engine.
+ ///
+ ///
+ /// 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.
+ ///
+ public bool SupportsJsonObjectArray { get; }
+
///
/// 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
diff --git a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs
index 98c5f8727ee..dc3f3736e3c 100644
--- a/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs
+++ b/src/EFCore.SqlServer/Infrastructure/Internal/SqlServerSingletonOptions.cs
@@ -60,6 +60,22 @@ public virtual bool SupportsJsonFunctions
_ => throw new UnreachableException()
};
+ ///
+ /// 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.
+ ///
+ public virtual bool SupportsJsonObjectArray
+ => EngineType switch
+ {
+ SqlServerEngineType.SqlServer => SqlServerCompatibilityLevel >= 160,
+ SqlServerEngineType.AzureSql => AzureSqlCompatibilityLevel >= 160,
+ SqlServerEngineType.AzureSynapse => false,
+ SqlServerEngineType.Unknown => false, // TODO: We shouldn't observe Unknown here, #36477
+ _ => throw new UnreachableException()
+ };
+
///
/// 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
diff --git a/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs b/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs
index e46b6abdb81..9851615076b 100644
--- a/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs
+++ b/src/EFCore.SqlServer/Properties/SqlServerStrings.Designer.cs
@@ -155,6 +155,12 @@ public static string DuplicateKeyMismatchedClustering(object? key1, object? enti
GetString("DuplicateKeyMismatchedClustering", nameof(key1), nameof(entityType1), nameof(key2), nameof(entityType2), nameof(table), nameof(keyName)),
key1, entityType1, key2, entityType2, table, keyName);
+ ///
+ /// 'ExecuteUpdate' cannot set a property in a JSON column to an expression containing a column on SQL Server versions before 2022. If you're on SQL Server 2022 and above, your compatibility level may be set to a lower value; consider raising it.
+ ///
+ public static string ExecuteUpdateCannotSetJsonPropertyOnOldSqlServer
+ => GetString("ExecuteUpdateCannotSetJsonPropertyOnOldSqlServer");
+
///
/// Identity value generation cannot be used for the property '{property}' on entity type '{entityType}' because the property type is '{propertyType}'. Identity value generation can only be used with signed integer properties.
///
diff --git a/src/EFCore.SqlServer/Properties/SqlServerStrings.resx b/src/EFCore.SqlServer/Properties/SqlServerStrings.resx
index 79128716e20..6a92672c5c0 100644
--- a/src/EFCore.SqlServer/Properties/SqlServerStrings.resx
+++ b/src/EFCore.SqlServer/Properties/SqlServerStrings.resx
@@ -168,6 +168,9 @@
The keys {key1} on '{entityType1}' and {key2} on '{entityType2}' are both mapped to '{table}.{keyName}', but have different clustering configurations.
+
+ 'ExecuteUpdate' cannot set a property in a JSON column to an expression containing a column on SQL Server versions before 2022. If you're on SQL Server 2022 and above, your compatibility level may be set to a lower value; consider raising it.
+
Identity value generation cannot be used for the property '{property}' on entity type '{entityType}' because the property type is '{propertyType}'. Identity value generation can only be used with signed integer properties.
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlExpressions/SqlServerJsonObjectExpression.cs b/src/EFCore.SqlServer/Query/Internal/SqlExpressions/SqlServerJsonObjectExpression.cs
new file mode 100644
index 00000000000..0a64bde7c95
--- /dev/null
+++ b/src/EFCore.SqlServer/Query/Internal/SqlExpressions/SqlServerJsonObjectExpression.cs
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
+using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
+
+namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlExpressions;
+
+///
+/// An expression that represents a SQL Server JSON_OBJECT() function call in a SQL tree.
+///
+///
+///
+/// See JSON_OBJECT (Transact-SQL)
+/// for more information and examples.
+///
+///
+/// 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.
+///
+///
+public sealed class SqlServerJsonObjectExpression : SqlFunctionExpression
+{
+ ///
+ /// 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.
+ ///
+ public SqlServerJsonObjectExpression(
+ IReadOnlyList propertyNames,
+ IReadOnlyList propertyValues,
+ RelationalTypeMapping typeMapping)
+ : base(
+ "JSON_OBJECT",
+ arguments: propertyValues,
+ nullable: false,
+ argumentsPropagateNullability: Enumerable.Repeat(false, propertyValues.Count).ToList(),
+ typeof(string),
+ typeMapping)
+ {
+ if (propertyNames.Count != propertyValues.Count)
+ {
+ throw new ArgumentException("The number of property names must match the number of property values.");
+ }
+
+ if (!typeMapping.StoreType.Equals("nvarchar(max)", StringComparison.OrdinalIgnoreCase))
+ {
+ throw new ArgumentException("Invalid type mapping for JSON_OBJECT.");
+ }
+
+ PropertyNames = propertyNames;
+ }
+
+ private static ConstructorInfo? _quotingConstructor;
+
+ ///
+ /// The JSON properties the object consists of.
+ ///
+ public IReadOnlyList PropertyNames { get; }
+
+ ///
+ public override Expression Quote()
+ => New(
+ _quotingConstructor ??= typeof(SqlServerJsonObjectExpression).GetConstructor(
+ [
+ typeof(IReadOnlyList),
+ typeof(IReadOnlyList),
+ typeof(SqlServerStringTypeMapping),
+ ])!,
+ NewArrayInit(typeof(string), initializers: PropertyNames.Select(Constant)),
+ Arguments is null
+ ? Constant(null, typeof(IEnumerable))
+ : NewArrayInit(typeof(SqlExpression), initializers: Arguments.Select(a => a.Quote())),
+ RelationalExpressionQuotingUtilities.QuoteTypeMapping(TypeMapping));
+
+ ///
+ protected override void Print(ExpressionPrinter expressionPrinter)
+ {
+ expressionPrinter.Append("JSON_OBJECT(");
+
+ for (var i = 0; i < PropertyNames.Count; i++)
+ {
+ var name = PropertyNames[i];
+ var value = Arguments![i];
+ if (i > 0)
+ {
+ expressionPrinter.Append(", ");
+ }
+
+ expressionPrinter.Append(name).Append(": ");
+ expressionPrinter.Visit(value);
+ }
+
+ expressionPrinter.Append(")");
+ }
+
+ ///
+ public override bool Equals(object? obj)
+ => obj != null
+ && (ReferenceEquals(this, obj)
+ || obj is SqlServerJsonObjectExpression other
+ && Equals(other));
+
+ private bool Equals(SqlServerJsonObjectExpression other)
+ => base.Equals(other) && PropertyNames.SequenceEqual(other.PropertyNames);
+
+ ///
+ public override int GetHashCode()
+ {
+ var hashCode = new HashCode();
+ hashCode.Add(base.GetHashCode());
+
+ foreach (var name in PropertyNames)
+ {
+ hashCode.Add(name);
+ }
+
+ return hashCode.ToHashCode();
+ }
+}
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs
index d4790b81704..edbd7b8d778 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQuerySqlGenerator.cs
@@ -5,6 +5,7 @@
using Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Internal;
+using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlExpressions;
using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
@@ -292,6 +293,26 @@ when string.Equals(sqlFunctionExpression.Name, "COALESCE", StringComparison.Ordi
return base.VisitSqlFunction(sqlFunctionExpression);
}
+ case SqlServerJsonObjectExpression jsonObject:
+ {
+ Sql.Append("JSON_OBJECT(");
+
+ for (var i = 0; i < jsonObject.PropertyNames.Count; i++)
+ {
+ if (i > 0)
+ {
+ Sql.Append(", ");
+ }
+
+ Sql.Append("'").Append(jsonObject.PropertyNames[i]).Append("': ");
+ Visit(jsonObject.Arguments![i]);
+ }
+
+ Sql.Append(")");
+
+ return sqlFunctionExpression;
+ }
+
// SQL Server 2025 modify method (https://learn.microsoft.com/sql/t-sql/data-types/json-data-type#modify-method)
// We get here only from within UPDATE setters.
// We generate the syntax here manually rather than just using the regular function visitation logic since
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
index d4c634aea00..71805ab0516 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerQueryableMethodTranslatingExpressionVisitor.cs
@@ -6,6 +6,8 @@
using Microsoft.EntityFrameworkCore.SqlServer.Infrastructure.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Internal;
using Microsoft.EntityFrameworkCore.SqlServer.Metadata.Internal;
+using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlExpressions;
+using Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
using Microsoft.VisualBasic;
namespace Microsoft.EntityFrameworkCore.SqlServer.Query.Internal;
@@ -570,6 +572,64 @@ protected override bool TryTranslateSetters(
}
#pragma warning restore EF1001 // Internal EF Core API usage.
+ ///
+ /// 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.
+ ///
+ protected override bool TrySerializeScalarToJson(
+ JsonScalarExpression target,
+ SqlExpression value,
+ [NotNullWhen(true)] out SqlExpression? jsonValue)
+ {
+#pragma warning disable EF9002 // TrySerializeScalarToJson is experimental
+ // The base implementation handles the types natively supported in JSON (int, string, bool), as well
+ // as constants/parameters.
+ if (base.TrySerializeScalarToJson(target, value, out jsonValue))
+ {
+ return true;
+ }
+#pragma warning restore EF9002
+
+ // geometry/geography are "user-defined types" and therefore not supported by JSON_OBJECT(), which we
+ // use below for serializing arbitrary relational expressions to JSON. Special-case them and serialize
+ // as WKT.
+ if (value.TypeMapping?.StoreType is "geometry" or "geography")
+ {
+ jsonValue = _sqlExpressionFactory.Function(
+ instance: value,
+ "STAsText",
+ arguments: [],
+ nullable: true,
+ instancePropagatesNullability: true,
+ argumentsPropagateNullability: [],
+ typeof(string),
+ _typeMappingSource.FindMapping("nvarchar(max)"));
+ return true;
+ }
+
+ // We have some arbitrary relational expression that isn't an int/string/bool; it needs to be converted
+ // to JSON. Do this by generating JSON_VALUE(JSON_OBJECT('v': foo), '$.v') (supported since SQL Server 2022)
+ if (_sqlServerSingletonOptions.SupportsJsonObjectArray)
+ {
+ jsonValue = new JsonScalarExpression(
+ new SqlServerJsonObjectExpression(
+ propertyNames: ["v"],
+ propertyValues: [value],
+ SqlServerStructuralJsonTypeMapping.NvarcharMaxDefault),
+ [new("v")],
+ typeof(string),
+ _typeMappingSource.FindMapping("nvarchar(max)"),
+ nullable: value is ColumnExpression column ? column.IsNullable : true);
+ return true;
+ }
+ else
+ {
+ throw new InvalidOperationException(SqlServerStrings.ExecuteUpdateCannotSetJsonPropertyOnOldSqlServer);
+ }
+ }
+
///
/// 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
diff --git a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs
index 89ee3a15224..a0bb693f889 100644
--- a/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/EFCore.Sqlite.Core/Query/Internal/SqliteQueryableMethodTranslatingExpressionVisitor.cs
@@ -635,7 +635,9 @@ protected override bool TrySerializeScalarToJson(
throw new InvalidOperationException(SqliteStrings.ExecuteUpdateJsonPartialUpdateDoesNotSupportUlong);
}
+#pragma warning disable EF9002 // TrySerializeScalarToJson is experimental
return base.TrySerializeScalarToJson(target, value, out jsonValue);
+#pragma warning restore EF9002
}
///
diff --git a/test/EFCore.Cosmos.FunctionalTests/Types/CosmosMiscellaneousTypeTest.cs b/test/EFCore.Cosmos.FunctionalTests/Types/CosmosMiscellaneousTypeTest.cs
index 9166b5e7461..49734c8f4c6 100644
--- a/test/EFCore.Cosmos.FunctionalTests/Types/CosmosMiscellaneousTypeTest.cs
+++ b/test/EFCore.Cosmos.FunctionalTests/Types/CosmosMiscellaneousTypeTest.cs
@@ -6,61 +6,49 @@ namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous;
public class BoolTypeTest(BoolTypeTest.BoolTypeFixture fixture)
: TypeTestBase(fixture)
{
- public class BoolTypeFixture : TypeTestFixture
+ public class BoolTypeFixture : CosmosTypeFixtureBase
{
public override bool Value { get; } = true;
public override bool OtherValue { get; } = false;
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class StringTypeTest(StringTypeTest.StringTypeFixture fixture)
: TypeTestBase(fixture)
{
- public class StringTypeFixture : TypeTestFixture
+ public class StringTypeFixture : CosmosTypeFixtureBase
{
public override string Value { get; } = "foo";
public override string OtherValue { get; } = "bar";
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class GuidTypeTest(GuidTypeTest.GuidTypeFixture fixture)
: TypeTestBase(fixture)
{
- public class GuidTypeFixture : TypeTestFixture
+ public class GuidTypeFixture : CosmosTypeFixtureBase
{
public override Guid Value { get; } = new("8f7331d6-cde9-44fb-8611-81fff686f280");
public override Guid OtherValue { get; } = new("ae192c36-9004-49b2-b785-8be10d169627");
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class ByteArrayTypeTest(ByteArrayTypeTest.ByteArrayTypeFixture fixture)
: TypeTestBase(fixture)
{
- public class ByteArrayTypeFixture : TypeTestFixture
+ public class ByteArrayTypeFixture : CosmosTypeFixtureBase
{
public override byte[] Value { get; } = [1, 2, 3];
public override byte[] OtherValue { get; } = [4, 5, 6, 7];
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
-
public override Func Comparer { get; } = (a, b) => a.SequenceEqual(b);
}
}
diff --git a/test/EFCore.Cosmos.FunctionalTests/Types/CosmosNumericTypeTest.cs b/test/EFCore.Cosmos.FunctionalTests/Types/CosmosNumericTypeTest.cs
index ab7772b2d5d..3aa78564b6a 100644
--- a/test/EFCore.Cosmos.FunctionalTests/Types/CosmosNumericTypeTest.cs
+++ b/test/EFCore.Cosmos.FunctionalTests/Types/CosmosNumericTypeTest.cs
@@ -5,98 +5,77 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric;
public class ByteTypeTest(ByteTypeTest.ByteTypeFixture fixture) : TypeTestBase(fixture)
{
- public class ByteTypeFixture : TypeTestFixture
+ public class ByteTypeFixture : CosmosTypeFixtureBase
{
public override byte Value { get; } = byte.MinValue;
public override byte OtherValue { get; } = byte.MaxValue;
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class ShortTypeTest(ShortTypeTest.ShortTypeFixture fixture) : TypeTestBase(fixture)
{
- public class ShortTypeFixture : TypeTestFixture
+ public class ShortTypeFixture : CosmosTypeFixtureBase
{
public override short Value { get; } = short.MinValue;
public override short OtherValue { get; } = short.MaxValue;
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class IntTypeTest(IntTypeTest.IntTypeFixture fixture) : TypeTestBase(fixture)
{
- public class IntTypeFixture : TypeTestFixture
+ public class IntTypeFixture : CosmosTypeFixtureBase
{
public override int Value { get; } = int.MinValue;
public override int OtherValue { get; } = int.MaxValue;
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class LongTypeTest(LongTypeTest.LongTypeFixture fixture) : TypeTestBase(fixture)
{
- public class LongTypeFixture : TypeTestFixture
+ public class LongTypeFixture : CosmosTypeFixtureBase
{
public override long Value { get; } = long.MinValue;
public override long OtherValue { get; } = long.MaxValue;
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class DecimalTypeTest(DecimalTypeTest.DecimalTypeFixture fixture) : TypeTestBase(fixture)
{
- public class DecimalTypeFixture : TypeTestFixture
+ public class DecimalTypeFixture : CosmosTypeFixtureBase
{
public override decimal Value { get; } = 30.5m;
public override decimal OtherValue { get; } = 30m;
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class DoubleTypeTest(DoubleTypeTest.DoubleTypeFixture fixture) : TypeTestBase(fixture)
{
- public class DoubleTypeFixture : TypeTestFixture
+ public class DoubleTypeFixture : CosmosTypeFixtureBase
{
public override double Value { get; } = 30.5d;
public override double OtherValue { get; } = 30d;
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class FloatTypeTest(FloatTypeTest.FloatTypeFixture fixture) : TypeTestBase(fixture)
{
- public class FloatTypeFixture : TypeTestFixture
+ public class FloatTypeFixture : CosmosTypeFixtureBase
{
public override float Value { get; } = 30.5f;
public override float OtherValue { get; } = 30f;
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
diff --git a/test/EFCore.Cosmos.FunctionalTests/Types/CosmosTemporalTypeTest.cs b/test/EFCore.Cosmos.FunctionalTests/Types/CosmosTemporalTypeTest.cs
index 147cc2f2e8d..7bcee3739c6 100644
--- a/test/EFCore.Cosmos.FunctionalTests/Types/CosmosTemporalTypeTest.cs
+++ b/test/EFCore.Cosmos.FunctionalTests/Types/CosmosTemporalTypeTest.cs
@@ -6,72 +6,57 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal;
public class DateTimeTypeTest(DateTimeTypeTest.DateTimeTypeFixture fixture)
: TypeTestBase(fixture)
{
- public class DateTimeTypeFixture : TypeTestFixture
+ public class DateTimeTypeFixture : CosmosTypeFixtureBase
{
public override DateTime Value { get; } = new DateTime(2020, 1, 5, 12, 30, 45, DateTimeKind.Unspecified);
public override DateTime OtherValue { get; } = new DateTime(2022, 5, 3, 0, 0, 0, DateTimeKind.Unspecified);
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class DateTimeOffsetTypeTest(DateTimeOffsetTypeTest.DateTimeOffsetTypeFixture fixture)
: TypeTestBase(fixture)
{
- public class DateTimeOffsetTypeFixture : TypeTestFixture
+ public class DateTimeOffsetTypeFixture : CosmosTypeFixtureBase
{
public override DateTimeOffset Value { get; } = new DateTimeOffset(2020, 1, 5, 12, 30, 45, TimeSpan.FromHours(2));
public override DateTimeOffset OtherValue { get; } = new DateTimeOffset(2020, 1, 5, 12, 30, 45, TimeSpan.FromHours(3));
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
-public class DateOnlyTypeTest(DateOnlyTypeTest.DateTypeFixture fixture) : TypeTestBase(fixture)
+public class DateOnlyTypeTest(DateOnlyTypeTest.DateOnlyTypeFixture fixture) : TypeTestBase(fixture)
{
- public class DateTypeFixture : TypeTestFixture
+ public class DateOnlyTypeFixture : CosmosTypeFixtureBase
{
public override DateOnly Value { get; } = new DateOnly(2020, 1, 5);
public override DateOnly OtherValue { get; } = new DateOnly(2022, 5, 3);
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
-public class TimeOnlyTypeTest(TimeOnlyTypeTest.TimeTypeFixture fixture)
- : TypeTestBase(fixture)
+public class TimeOnlyTypeTest(TimeOnlyTypeTest.TimeOnlyTypeFixture fixture)
+ : TypeTestBase(fixture)
{
- public class TimeTypeFixture : TypeTestFixture
+ public class TimeOnlyTypeFixture : CosmosTypeFixtureBase
{
public override TimeOnly Value { get; } = new TimeOnly(12, 30, 45);
public override TimeOnly OtherValue { get; } = new TimeOnly(14, 0, 0);
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
public class TimeSpanTypeTest(TimeSpanTypeTest.TimeSpanTypeFixture fixture) : TypeTestBase(fixture)
{
- public class TimeSpanTypeFixture : TypeTestFixture
+ public class TimeSpanTypeFixture : CosmosTypeFixtureBase
{
public override TimeSpan Value { get; } = new TimeSpan(12, 30, 45);
public override TimeSpan OtherValue { get; } = new TimeSpan(14, 0, 0);
protected override ITestStoreFactory TestStoreFactory => CosmosTestStoreFactory.Instance;
-
- public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
- => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
}
}
diff --git a/test/EFCore.Cosmos.FunctionalTests/Types/CosmosTypeFixtureBase.cs b/test/EFCore.Cosmos.FunctionalTests/Types/CosmosTypeFixtureBase.cs
new file mode 100644
index 00000000000..68784848c28
--- /dev/null
+++ b/test/EFCore.Cosmos.FunctionalTests/Types/CosmosTypeFixtureBase.cs
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Types;
+
+public abstract class CosmosTypeFixtureBase : TypeFixtureBase
+{
+ public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
+ => base.AddOptions(builder).ConfigureWarnings(c => c.Log(CosmosEventId.NoPartitionKeyDefined));
+}
diff --git a/test/EFCore.InMemory.FunctionalTests/InMemoryComplianceTest.cs b/test/EFCore.InMemory.FunctionalTests/InMemoryComplianceTest.cs
deleted file mode 100644
index 936daf32e3d..00000000000
--- a/test/EFCore.InMemory.FunctionalTests/InMemoryComplianceTest.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Microsoft.EntityFrameworkCore.BulkUpdates;
-using Microsoft.EntityFrameworkCore.Query.Associations;
-using Microsoft.EntityFrameworkCore.Query.Associations.ComplexProperties;
-using Microsoft.EntityFrameworkCore.Query.Associations.Navigations;
-using Microsoft.EntityFrameworkCore.Query.Associations.OwnedNavigations;
-
-namespace Microsoft.EntityFrameworkCore;
-
-public class InMemoryComplianceTest : ComplianceTestBase
-{
- protected override ICollection IgnoredTestBases { get; } = new HashSet
- {
- // No in-memory tests
- typeof(ComplexTypeQueryTestBase<>),
- typeof(AdHocComplexTypeQueryTestBase),
- typeof(PrimitiveCollectionsQueryTestBase<>),
- typeof(NonSharedPrimitiveCollectionsQueryTestBase),
- typeof(FunkyDataQueryTestBase<>),
- typeof(StoreGeneratedTestBase<>),
- typeof(ConferencePlannerTestBase<>),
- typeof(ManyToManyQueryTestBase<>),
- typeof(BulkUpdatesTestBase<>),
- typeof(FiltersInheritanceBulkUpdatesTestBase<>),
- typeof(InheritanceBulkUpdatesTestBase<>),
- typeof(NonSharedModelBulkUpdatesTestBase),
- typeof(NorthwindBulkUpdatesTestBase<>),
- typeof(JsonQueryTestBase<>),
- typeof(AdHocJsonQueryTestBase),
- typeof(TypeTestBase<,>),
-
- // Relationships tests - not implemented for InMemory
- typeof(AssociationsCollectionTestBase<>),
- typeof(AssociationsMiscellaneousTestBase<>),
- typeof(AssociationsPrimitiveCollectionTestBase<>),
- typeof(AssociationsProjectionTestBase<>),
- typeof(AssociationsSetOperationsTestBase<>),
- typeof(AssociationsStructuralEqualityTestBase<>),
- typeof(AssociationsBulkUpdateTestBase<>),
- typeof(ComplexPropertiesCollectionTestBase<>),
- typeof(ComplexPropertiesMiscellaneousTestBase<>),
- typeof(ComplexPropertiesPrimitiveCollectionTestBase<>),
- typeof(ComplexPropertiesProjectionTestBase<>),
- typeof(ComplexPropertiesSetOperationsTestBase<>),
- typeof(ComplexPropertiesStructuralEqualityTestBase<>),
- typeof(ComplexPropertiesBulkUpdateTestBase<>),
- typeof(NavigationsCollectionTestBase<>),
- typeof(NavigationsIncludeTestBase<>),
- typeof(NavigationsMiscellaneousTestBase<>),
- typeof(NavigationsPrimitiveCollectionTestBase<>),
- typeof(NavigationsProjectionTestBase<>),
- typeof(NavigationsSetOperationsTestBase<>),
- typeof(NavigationsStructuralEqualityTestBase<>),
- typeof(OwnedNavigationsCollectionTestBase<>),
- typeof(OwnedNavigationsMiscellaneousTestBase<>),
- typeof(OwnedNavigationsPrimitiveCollectionTestBase<>),
- typeof(OwnedNavigationsProjectionTestBase<>),
- typeof(OwnedNavigationsSetOperationsTestBase<>),
- typeof(OwnedNavigationsStructuralEqualityTestBase<>)
- };
-
- protected override Assembly TargetAssembly { get; } = typeof(InMemoryComplianceTest).Assembly;
-}
diff --git a/test/EFCore.Relational.Specification.Tests/Types/JsonTypeEntity.cs b/test/EFCore.Relational.Specification.Tests/Types/JsonTypeEntity.cs
new file mode 100644
index 00000000000..30cea610d32
--- /dev/null
+++ b/test/EFCore.Relational.Specification.Tests/Types/JsonTypeEntity.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Types;
+
+public class JsonTypeEntity
+{
+ public int Id { get; set; }
+
+ public required T Value { get; set; }
+ public required T OtherValue { get; set; }
+
+ public required JsonContainer JsonContainer { get; set; }
+}
+
+public class JsonContainer
+{
+ public required T Value { get; set; }
+ public required T OtherValue { get; set; }
+}
diff --git a/test/EFCore.Relational.Specification.Tests/Types/RelationalTypeFixtureBase.cs b/test/EFCore.Relational.Specification.Tests/Types/RelationalTypeFixtureBase.cs
new file mode 100644
index 00000000000..4d0565cf5b9
--- /dev/null
+++ b/test/EFCore.Relational.Specification.Tests/Types/RelationalTypeFixtureBase.cs
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Types;
+
+public abstract class RelationalTypeFixtureBase : TypeFixtureBase, ITestSqlLoggerFactory
+{
+ public virtual string? StoreType => null;
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
+ {
+ base.OnModelCreating(modelBuilder, context);
+
+ modelBuilder.Entity>(b =>
+ {
+ b.ToTable(nameof(TypeEntity<>));
+ b.Property(e => e.Value).HasColumnType(StoreType);
+ b.Property(e => e.OtherValue).HasColumnType(StoreType);
+ });
+
+ modelBuilder.Entity>(b =>
+ {
+ b.ToTable(nameof(JsonTypeEntity<>));
+
+ modelBuilder.Entity>().Property(e => e.Id).ValueGeneratedNever();
+
+ b.ComplexProperty(e => e.JsonContainer, jc =>
+ {
+ jc.ToJson();
+
+ jc.Property(e => e.Value).HasColumnType(StoreType);
+ jc.Property(e => e.OtherValue).HasColumnType(StoreType);
+ });
+ });
+ }
+
+ protected override async Task SeedAsync(DbContext context)
+ {
+ await base.SeedAsync(context);
+
+ context.Set>().AddRange(
+ new()
+ {
+ Id = 1,
+ Value = Value,
+ OtherValue = OtherValue,
+ JsonContainer = new()
+ {
+ Value = Value,
+ OtherValue = OtherValue
+ }
+ },
+ new()
+ {
+ Id = 2,
+ Value = OtherValue,
+ OtherValue = Value,
+ JsonContainer = new()
+ {
+ Value = OtherValue,
+ OtherValue = Value
+ }
+ });
+
+ await context.SaveChangesAsync();
+ }
+
+ public TestSqlLoggerFactory TestSqlLoggerFactory
+ => (TestSqlLoggerFactory)ListLoggerFactory;
+
+ public virtual void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
+ => facade.UseTransaction(transaction.GetDbTransaction());
+}
diff --git a/test/EFCore.Relational.Specification.Tests/RelationalTypeTestBase.cs b/test/EFCore.Relational.Specification.Tests/Types/RelationalTypeTestBase.cs
similarity index 52%
rename from test/EFCore.Relational.Specification.Tests/RelationalTypeTestBase.cs
rename to test/EFCore.Relational.Specification.Tests/Types/RelationalTypeTestBase.cs
index 57236e96ce7..5a506bdbab1 100644
--- a/test/EFCore.Relational.Specification.Tests/RelationalTypeTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Types/RelationalTypeTestBase.cs
@@ -1,10 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-namespace Microsoft.EntityFrameworkCore;
+namespace Microsoft.EntityFrameworkCore.Types;
public abstract class RelationalTypeTestBase(TFixture fixture) : TypeTestBase(fixture)
- where TFixture : RelationalTypeTestBase.RelationalTypeTestFixture
+ where TFixture : RelationalTypeFixtureBase
where T : notnull
{
public RelationalTypeTestBase(TFixture fixture, ITestOutputHelper testOutputHelper)
@@ -23,19 +23,18 @@ public virtual async Task SaveChanges_within_json()
Fixture.UseTransaction,
async context =>
{
- JsonTypeEntity entity;
+ JsonTypeEntity entity;
- using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents())
- {
- entity = await context.Set().SingleAsync(e => e.Id == 1);
- }
+ entity = await context.Set>().SingleAsync(e => e.Id == 1);
+
+ Fixture.TestSqlLoggerFactory.Clear();
entity.JsonContainer.Value = Fixture.OtherValue;
await context.SaveChangesAsync();
using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents())
{
- var result = await context.Set().Where(e => e.Id == 1).SingleAsync();
+ var result = await context.Set>().Where(e => e.Id == 1).SingleAsync();
Assert.Equal(Fixture.OtherValue, result.JsonContainer.Value, Fixture.Comparer);
}
});
@@ -51,11 +50,13 @@ public virtual async Task ExecuteUpdate_within_json_to_parameter()
Fixture.UseTransaction,
async context =>
{
- await context.Set().ExecuteUpdateAsync(s => s.SetProperty(e => e.JsonContainer.Value, e => Fixture.OtherValue));
+ Fixture.TestSqlLoggerFactory.Clear();
+
+ await context.Set>().ExecuteUpdateAsync(s => s.SetProperty(e => e.JsonContainer.Value, e => Fixture.OtherValue));
using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents())
{
- var result = await context.Set().Where(e => e.Id == 1).SingleAsync();
+ var result = await context.Set>().Where(e => e.Id == 1).SingleAsync();
Assert.Equal(Fixture.OtherValue, result.JsonContainer.Value, Fixture.Comparer);
}
});
@@ -67,17 +68,19 @@ public virtual async Task ExecuteUpdate_within_json_to_constant()
Fixture.UseTransaction,
async context =>
{
+ Fixture.TestSqlLoggerFactory.Clear();
+
// Manually inject a constant node into the query tree
- var parameter = Expression.Parameter(typeof(JsonTypeEntity));
- var valueExpression = Expression.Lambda>(
+ var parameter = Expression.Parameter(typeof(JsonTypeEntity));
+ var valueExpression = Expression.Lambda, T>>(
Expression.Constant(Fixture.OtherValue, typeof(T)),
parameter);
- await context.Set().ExecuteUpdateAsync(s => s.SetProperty(e => e.JsonContainer.Value, valueExpression));
+ await context.Set>().ExecuteUpdateAsync(s => s.SetProperty(e => e.JsonContainer.Value, valueExpression));
using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents())
{
- var result = await context.Set().Where(e => e.Id == 1).SingleAsync();
+ var result = await context.Set>().Where(e => e.Id == 1).SingleAsync();
Assert.Equal(Fixture.OtherValue, result.JsonContainer.Value, Fixture.Comparer);
}
});
@@ -89,11 +92,13 @@ public virtual async Task ExecuteUpdate_within_json_to_another_json_property()
Fixture.UseTransaction,
async context =>
{
- await context.Set().ExecuteUpdateAsync(s => s.SetProperty(e => e.JsonContainer.Value, e => e.JsonContainer.OtherValue));
+ Fixture.TestSqlLoggerFactory.Clear();
+
+ await context.Set>().ExecuteUpdateAsync(s => s.SetProperty(e => e.JsonContainer.Value, e => e.JsonContainer.OtherValue));
using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents())
{
- var result = await context.Set().Where(e => e.Id == 1).SingleAsync();
+ var result = await context.Set>().Where(e => e.Id == 1).SingleAsync();
Assert.Equal(Fixture.OtherValue, result.JsonContainer.Value, Fixture.Comparer);
}
});
@@ -105,102 +110,22 @@ public virtual async Task ExecuteUpdate_within_json_to_nonjson_column()
Fixture.UseTransaction,
async context =>
{
- await context.Set().ExecuteUpdateAsync(s => s.SetProperty(e => e.JsonContainer.Value, e => e.OtherValue));
+ Fixture.TestSqlLoggerFactory.Clear();
+
+ await context.Set>().ExecuteUpdateAsync(s => s.SetProperty(e => e.JsonContainer.Value, e => e.OtherValue));
using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents())
{
- var result = await context.Set().Where(e => e.Id == 1).SingleAsync();
+ var result = await context.Set>().Where(e => e.Id == 1).SingleAsync();
Assert.Equal(Fixture.OtherValue, result.JsonContainer.Value, Fixture.Comparer);
}
});
#endregion ExecuteUpdate
- protected class JsonTypeEntity
- {
- public int Id { get; set; }
-
- public required T Value { get; set; }
- public required T OtherValue { get; set; }
-
- public required JsonContainer JsonContainer { get; set; }
- }
-
- public class JsonContainer
- {
- public required T Value { get; set; }
- public required T OtherValue { get; set; }
- }
-
protected void AssertSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected);
protected void AssertExecuteUpdateSql(params string[] expected)
=> Fixture.TestSqlLoggerFactory.AssertBaseline(expected, forUpdate: true);
-
- public abstract class RelationalTypeTestFixture : TypeTestFixture, ITestSqlLoggerFactory
- {
- public virtual string? StoreType => null;
-
- protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
- {
- base.OnModelCreating(modelBuilder, context);
-
- modelBuilder.Entity(b =>
- {
- b.Property(e => e.Value).HasColumnType(StoreType);
- b.Property(e => e.OtherValue).HasColumnType(StoreType);
- });
-
- modelBuilder.Entity(b =>
- {
- modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever();
-
- b.ComplexProperty(e => e.JsonContainer, jc =>
- {
- jc.ToJson();
-
- jc.Property(e => e.Value).HasColumnType(StoreType);
- jc.Property(e => e.OtherValue).HasColumnType(StoreType);
- });
- });
- }
-
- protected override async Task SeedAsync(DbContext context)
- {
- await base.SeedAsync(context);
-
- context.Set().AddRange(
- new()
- {
- Id = 1,
- Value = Value,
- OtherValue = OtherValue,
- JsonContainer = new()
- {
- Value = Value,
- OtherValue = OtherValue
- }
- },
- new()
- {
- Id = 2,
- Value = OtherValue,
- OtherValue = Value,
- JsonContainer = new()
- {
- Value = OtherValue,
- OtherValue = Value
- }
- });
-
- await context.SaveChangesAsync();
- }
-
- public TestSqlLoggerFactory TestSqlLoggerFactory
- => (TestSqlLoggerFactory)ListLoggerFactory;
-
- public virtual void UseTransaction(DatabaseFacade facade, IDbContextTransaction transaction)
- => facade.UseTransaction(transaction.GetDbTransaction());
- }
}
diff --git a/test/EFCore.Specification.Tests/TypeTestBase.cs b/test/EFCore.Specification.Tests/TypeTestBase.cs
deleted file mode 100644
index ef7e764171a..00000000000
--- a/test/EFCore.Specification.Tests/TypeTestBase.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.EntityFrameworkCore;
-
-[Collection("Type tests")]
-public abstract class TypeTestBase(TFixture fixture) : IClassFixture
- where TFixture : TypeTestBase.TypeTestFixture
- where T : notnull
-{
- [ConditionalFact]
- public async virtual Task Equality_in_query()
- {
- await using var context = Fixture.CreateContext();
-
- var result = await context.Set().Where(e => e.Value.Equals(Fixture.Value)).SingleAsync();
-
- Assert.Equal(Fixture.Value, result.Value, Fixture.Comparer);
- }
-
- protected class TypeEntity
- {
- public int Id { get; set; }
-
- public required T Value { get; set; }
- public required T OtherValue { get; set; }
- }
-
- protected TFixture Fixture { get; } = fixture;
-
- public abstract class TypeTestFixture : SharedStoreFixtureBase
- {
- ///
- /// The main value used in the tests.
- ///
- public abstract T Value { get; }
-
- ///
- /// An additional value that is different from .
- ///
- public abstract T OtherValue { get; }
-
- protected override string StoreName => "TypeTest";
-
- public virtual Func Comparer { get; } = EqualityComparer.Default.Equals;
-
- protected override bool RecreateStore => true;
-
- protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
- {
- // Don't rely on database generated values, which aren't supported everywhere (e.g. Cosmos)
- modelBuilder.Entity().Property(e => e.Id).ValueGeneratedNever();
- }
-
- protected override async Task SeedAsync(DbContext context)
- {
- context.Set().AddRange(
- new()
- {
- Id = 1,
- Value = Value,
- OtherValue = OtherValue
- },
- new()
- {
- Id = 2,
- Value = OtherValue,
- OtherValue = Value
- });
-
- await context.SaveChangesAsync();
- }
- }
-}
diff --git a/test/EFCore.Specification.Tests/Types/TypeEntity.cs b/test/EFCore.Specification.Tests/Types/TypeEntity.cs
new file mode 100644
index 00000000000..4923e60dcd3
--- /dev/null
+++ b/test/EFCore.Specification.Tests/Types/TypeEntity.cs
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Types;
+
+public class TypeEntity
+{
+ public int Id { get; set; }
+
+ public required T Value { get; set; }
+ public required T OtherValue { get; set; }
+}
diff --git a/test/EFCore.Specification.Tests/Types/TypeFixtureBase.cs b/test/EFCore.Specification.Tests/Types/TypeFixtureBase.cs
new file mode 100644
index 00000000000..78e400d813c
--- /dev/null
+++ b/test/EFCore.Specification.Tests/Types/TypeFixtureBase.cs
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Types;
+
+public abstract class TypeFixtureBase : SharedStoreFixtureBase
+{
+ ///
+ /// The main value used in the tests.
+ ///
+ public abstract T Value { get; }
+
+ ///
+ /// An additional value that is different from .
+ ///
+ public abstract T OtherValue { get; }
+
+ protected override string StoreName => "TypeTest";
+
+ public virtual Func Comparer { get; } = EqualityComparer.Default.Equals;
+
+ protected override bool RecreateStore => true;
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context)
+ {
+ // Don't rely on database generated values, which aren't supported everywhere (e.g. Cosmos)
+ modelBuilder.Entity>().Property(e => e.Id).ValueGeneratedNever();
+ }
+
+ protected override async Task SeedAsync(DbContext context)
+ {
+ context.Set>().AddRange(
+ new()
+ {
+ Id = 1,
+ Value = Value,
+ OtherValue = OtherValue
+ },
+ new()
+ {
+ Id = 2,
+ Value = OtherValue,
+ OtherValue = Value
+ });
+
+ await context.SaveChangesAsync();
+ }
+}
diff --git a/test/EFCore.Specification.Tests/Types/TypeTestBase.cs b/test/EFCore.Specification.Tests/Types/TypeTestBase.cs
new file mode 100644
index 00000000000..44878d3ae2b
--- /dev/null
+++ b/test/EFCore.Specification.Tests/Types/TypeTestBase.cs
@@ -0,0 +1,23 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Types;
+
+[Collection("Type tests")]
+public abstract class TypeTestBase(TFixture fixture) : IClassFixture
+ where TFixture : TypeFixtureBase
+ where T : notnull
+{
+ [ConditionalFact]
+ public async virtual Task Equality_in_query()
+ {
+ await using var context = Fixture.CreateContext();
+
+ var result = await context.Set>().Where(e => e.Value.Equals(Fixture.Value)).SingleAsync();
+
+ Assert.Equal(Fixture.Value, result.Value, Fixture.Comparer);
+ }
+
+
+ protected TFixture Fixture { get; } = fixture;
+}
diff --git a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestEnvironment.cs b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestEnvironment.cs
index 0ddd04640af..53411c8a948 100644
--- a/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestEnvironment.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/TestUtilities/TestEnvironment.cs
@@ -462,6 +462,9 @@ public static bool IsVectorTypeSupported
public static byte SqlServerMajorVersion
=> GetProductMajorVersion();
+ public static DbContextOptionsBuilder SetCompatibilityLevelFromEnvironment(DbContextOptionsBuilder builder)
+ => builder.UseSqlServerCompatibilityLevel(SqlServerMajorVersion * 10);
+
public static string? ElasticPoolName { get; } = Config["ElasticPoolName"];
public static bool? GetFlag(string key)
diff --git a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerGeographyTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerGeographyTypeTest.cs
index b20b8b17d7b..f24c152ca18 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerGeographyTypeTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerGeographyTypeTest.cs
@@ -14,19 +14,36 @@ public override async Task Equality_in_query()
{
await using var context = Fixture.CreateContext();
- var result = await context.Set().Where(e => e.Value.EqualsTopologically(Fixture.Value)).SingleAsync();
+ var result = await context.Set>().Where(e => e.Value.EqualsTopologically(Fixture.Value)).SingleAsync();
Assert.Equal(Fixture.Value, result.Value, Fixture.Comparer);
}
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', [j].[OtherValue].STAsText())
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', [j].[OtherValue].STAsText())
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
}
- public abstract class GeographyTypeFixture() : RelationalTypeTestFixture
+ public abstract class GeographyTypeFixture : SqlServerTypeFixture
{
public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
=> base.AddOptions(builder).UseSqlServer(o => o.UseNetTopologySuite());
@@ -54,169 +71,181 @@ public class LineStringTypeFixture() : GeographyTypeFixture
[
new Coordinate(-122.34877, 47.6233355),
new Coordinate(-122.3308366, 47.5978429)
- ]) { SRID = 4326 };
+ ])
+ { SRID = 4326 };
public override LineString OtherValue { get; } = new(
[
new Coordinate(-121.5000, 46.9000),
new Coordinate(-121.2000, 46.6500),
new Coordinate(-121.0000, 46.4000)
- ]) { SRID = 4326 };
+ ])
+ { SRID = 4326 };
}
}
- public class PolygonTypeTest(PolygonTypeTest.PolygonTypeFixture fixture)
- : GeographyTypeTestBase(fixture)
+public class PolygonTypeTest(PolygonTypeTest.PolygonTypeFixture fixture)
+ : GeographyTypeTestBase(fixture)
+{
+ public class PolygonTypeFixture() : GeographyTypeFixture
{
- public class PolygonTypeFixture() : GeographyTypeFixture
- {
- // Simple rectangle
- public override Polygon Value { get; } = new(
- new LinearRing([
- new Coordinate(-122.3500, 47.6200), // NW
- new Coordinate(-122.3500, 47.6100), // SW
- new Coordinate(-122.3400, 47.6100), // SE
- new Coordinate(-122.3400, 47.6200), // NE
- new Coordinate(-122.3500, 47.6200) // Close
- ])) { SRID = 4326 };
-
- // Shifted rectangle; different area so not topologically equal
- public override Polygon OtherValue { get; } = new(
- new LinearRing([
- new Coordinate(-121.3000, 46.6000), // NW
- new Coordinate(-121.3000, 46.5900), // SW
- new Coordinate(-121.2800, 46.5900), // SE
- new Coordinate(-121.2800, 46.6000), // NE
- new Coordinate(-121.3000, 46.6000)
- ])) { SRID = 4326 };
- }
+ // Simple rectangle
+ public override Polygon Value { get; } = new(
+ new LinearRing([
+ new Coordinate(-122.3500, 47.6200), // NW
+ new Coordinate(-122.3500, 47.6100), // SW
+ new Coordinate(-122.3400, 47.6100), // SE
+ new Coordinate(-122.3400, 47.6200), // NE
+ new Coordinate(-122.3500, 47.6200) // Close
+ ]))
+ { SRID = 4326 };
+
+ // Shifted rectangle; different area so not topologically equal
+ public override Polygon OtherValue { get; } = new(
+ new LinearRing([
+ new Coordinate(-121.3000, 46.6000), // NW
+ new Coordinate(-121.3000, 46.5900), // SW
+ new Coordinate(-121.2800, 46.5900), // SE
+ new Coordinate(-121.2800, 46.6000), // NE
+ new Coordinate(-121.3000, 46.6000)
+ ]))
+ { SRID = 4326 };
}
+}
- public class MultiPointTypeTest(MultiPointTypeTest.MultiPointTypeFixture fixture)
- : GeographyTypeTestBase(fixture)
+public class MultiPointTypeTest(MultiPointTypeTest.MultiPointTypeFixture fixture)
+ : GeographyTypeTestBase(fixture)
+{
+ public class MultiPointTypeFixture() : GeographyTypeFixture
{
- public class MultiPointTypeFixture() : GeographyTypeFixture
- {
- public override MultiPoint Value { get; } = new([
- new Point(-122.3500, 47.6200) { SRID = 4326 },
- new Point(-122.3450, 47.6150) { SRID = 4326 }
- ]) { SRID = 4326 };
-
- public override MultiPoint OtherValue { get; } = new([
- new Point(-121.9000, 46.9500) { SRID = 4326 },
- new Point(-121.5000, 46.6000) { SRID = 4326 },
- new Point(-121.2000, 46.3000) { SRID = 4326 }
- ]) { SRID = 4326 };
- }
+ public override MultiPoint Value { get; } = new([
+ new Point(-122.3500, 47.6200) { SRID = 4326 },
+ new Point(-122.3450, 47.6150) { SRID = 4326 }
+ ])
+ { SRID = 4326 };
+
+ public override MultiPoint OtherValue { get; } = new([
+ new Point(-121.9000, 46.9500) { SRID = 4326 },
+ new Point(-121.5000, 46.6000) { SRID = 4326 },
+ new Point(-121.2000, 46.3000) { SRID = 4326 }
+ ])
+ { SRID = 4326 };
}
+}
- public class MultiLineStringTypeTest(MultiLineStringTypeTest.MultiLineStringTypeFixture fixture)
- : GeographyTypeTestBase(fixture)
+public class MultiLineStringTypeTest(MultiLineStringTypeTest.MultiLineStringTypeFixture fixture)
+ : GeographyTypeTestBase(fixture)
+{
+ public class MultiLineStringTypeFixture() : GeographyTypeFixture
{
- public class MultiLineStringTypeFixture() : GeographyTypeFixture
- {
- public override MultiLineString Value { get; } = new([
- new LineString([
- new Coordinate(-122.3500, 47.6200),
- new Coordinate(-122.3450, 47.6150)
- ]) { SRID = 4326 },
- new LineString([
- new Coordinate(-122.3480, 47.6180),
- new Coordinate(-122.3420, 47.6130)
- ]) { SRID = 4326 }
- ]) { SRID = 4326 };
-
- public override MultiLineString OtherValue { get; } = new([
- new LineString([
- new Coordinate(-121.9000, 46.9500),
- new Coordinate(-121.6000, 46.8200)
- ]) { SRID = 4326 },
- new LineString([
- new Coordinate(-121.7000, 46.7800),
- new Coordinate(-121.4000, 46.5500)
- ]) { SRID = 4326 }
- ]) { SRID = 4326 };
- }
+ public override MultiLineString Value { get; } = new([
+ new LineString([
+ new Coordinate(-122.3500, 47.6200),
+ new Coordinate(-122.3450, 47.6150)
+ ]) { SRID = 4326 },
+ new LineString([
+ new Coordinate(-122.3480, 47.6180),
+ new Coordinate(-122.3420, 47.6130)
+ ]) { SRID = 4326 }
+ ])
+ { SRID = 4326 };
+
+ public override MultiLineString OtherValue { get; } = new([
+ new LineString([
+ new Coordinate(-121.9000, 46.9500),
+ new Coordinate(-121.6000, 46.8200)
+ ]) { SRID = 4326 },
+ new LineString([
+ new Coordinate(-121.7000, 46.7800),
+ new Coordinate(-121.4000, 46.5500)
+ ]) { SRID = 4326 }
+ ])
+ { SRID = 4326 };
}
+}
- public class MultiPolygonTypeTest(MultiPolygonTypeTest.MultiPolygonTypeFixture fixture)
- : GeographyTypeTestBase(fixture)
+public class MultiPolygonTypeTest(MultiPolygonTypeTest.MultiPolygonTypeFixture fixture)
+ : GeographyTypeTestBase(fixture)
+{
+ public class MultiPolygonTypeFixture() : GeographyTypeFixture
{
- public class MultiPolygonTypeFixture() : GeographyTypeFixture
- {
- public override MultiPolygon Value { get; } = new(
- [
- new Polygon(new LinearRing([
- new Coordinate(-122.3500, 47.6200), // NW
- new Coordinate(-122.3500, 47.6150), // SW
- new Coordinate(-122.3450, 47.6150), // SE
- new Coordinate(-122.3450, 47.6200), // NE
- new Coordinate(-122.3500, 47.6200)
- ])) { SRID = 4326 },
- new Polygon(new LinearRing([
- new Coordinate(-122.3525, 47.6230), // NW
- new Coordinate(-122.3525, 47.6215), // SW
- new Coordinate(-122.3510, 47.6215), // SE
- new Coordinate(-122.3510, 47.6230), // NE
- new Coordinate(-122.3525, 47.6230)
- ])) { SRID = 4326 }
- ]) { SRID = 4326 };
-
- public override MultiPolygon OtherValue { get; } = new(
- [
- new Polygon(new LinearRing([
- new Coordinate(-121.3600, 46.6250), // NW
- new Coordinate(-121.3600, 46.6200), // SW
- new Coordinate(-121.3550, 46.6200), // SE
- new Coordinate(-121.3550, 46.6250), // NE
- new Coordinate(-121.3600, 46.6250)
- ])) { SRID = 4326 },
- new Polygon(new LinearRing([
- new Coordinate(-121.3540, 46.6240), // NW
- new Coordinate(-121.3540, 46.6220), // SW
- new Coordinate(-121.3525, 46.6220), // SE
- new Coordinate(-121.3525, 46.6240), // NE
- new Coordinate(-121.3540, 46.6240)
- ])) { SRID = 4326 }
- ]) { SRID = 4326 };
- }
+ public override MultiPolygon Value { get; } = new(
+ [
+ new Polygon(new LinearRing([
+ new Coordinate(-122.3500, 47.6200), // NW
+ new Coordinate(-122.3500, 47.6150), // SW
+ new Coordinate(-122.3450, 47.6150), // SE
+ new Coordinate(-122.3450, 47.6200), // NE
+ new Coordinate(-122.3500, 47.6200)
+ ])) { SRID = 4326 },
+ new Polygon(new LinearRing([
+ new Coordinate(-122.3525, 47.6230), // NW
+ new Coordinate(-122.3525, 47.6215), // SW
+ new Coordinate(-122.3510, 47.6215), // SE
+ new Coordinate(-122.3510, 47.6230), // NE
+ new Coordinate(-122.3525, 47.6230)
+ ])) { SRID = 4326 }
+ ])
+ { SRID = 4326 };
+
+ public override MultiPolygon OtherValue { get; } = new(
+ [
+ new Polygon(new LinearRing([
+ new Coordinate(-121.3600, 46.6250), // NW
+ new Coordinate(-121.3600, 46.6200), // SW
+ new Coordinate(-121.3550, 46.6200), // SE
+ new Coordinate(-121.3550, 46.6250), // NE
+ new Coordinate(-121.3600, 46.6250)
+ ])) { SRID = 4326 },
+ new Polygon(new LinearRing([
+ new Coordinate(-121.3540, 46.6240), // NW
+ new Coordinate(-121.3540, 46.6220), // SW
+ new Coordinate(-121.3525, 46.6220), // SE
+ new Coordinate(-121.3525, 46.6240), // NE
+ new Coordinate(-121.3540, 46.6240)
+ ])) { SRID = 4326 }
+ ])
+ { SRID = 4326 };
}
+}
- public class GeometryCollectionTypeTest(GeometryCollectionTypeTest.GeometryCollectionTypeFixture fixture)
- : GeographyTypeTestBase(fixture)
+public class GeometryCollectionTypeTest(GeometryCollectionTypeTest.GeometryCollectionTypeFixture fixture)
+ : GeographyTypeTestBase(fixture)
+{
+ public class GeometryCollectionTypeFixture() : GeographyTypeFixture
{
- public class GeometryCollectionTypeFixture() : GeographyTypeFixture
- {
- public override GeometryCollection Value { get; } = new(
- [
- new Point(-122.3500, 47.6200) { SRID = 4326 },
- new LineString([
- new Coordinate(-122.3500, 47.6200),
- new Coordinate(-122.3450, 47.6150)
- ]) { SRID = 4326 },
- new Polygon(new LinearRing([
- new Coordinate(-122.3480, 47.6190), // NW
- new Coordinate(-122.3480, 47.6170), // SW
- new Coordinate(-122.3460, 47.6170), // SE
- new Coordinate(-122.3460, 47.6190), // NE
- new Coordinate(-122.3480, 47.6190)
- ])) { SRID = 4326 }
- ]) { SRID = 4326 };
-
- public override GeometryCollection OtherValue { get; } = new(
- [
- new Point(-121.9000, 46.9500) { SRID = 4326 },
- new LineString([
- new Coordinate(-121.9000, 46.9500),
- new Coordinate(-121.6000, 46.8200)
- ]) { SRID = 4326 },
- new Polygon(new LinearRing([
- new Coordinate(-121.8800, 46.9400), // NW
- new Coordinate(-121.8800, 46.9200), // SW
- new Coordinate(-121.8600, 46.9200), // SE
- new Coordinate(-121.8600, 46.9400), // NE
- new Coordinate(-121.8800, 46.9400)
- ])) { SRID = 4326 }
- ]) { SRID = 4326 };
- }
+ public override GeometryCollection Value { get; } = new(
+ [
+ new Point(-122.3500, 47.6200) { SRID = 4326 },
+ new LineString([
+ new Coordinate(-122.3500, 47.6200),
+ new Coordinate(-122.3450, 47.6150)
+ ]) { SRID = 4326 },
+ new Polygon(new LinearRing([
+ new Coordinate(-122.3480, 47.6190), // NW
+ new Coordinate(-122.3480, 47.6170), // SW
+ new Coordinate(-122.3460, 47.6170), // SE
+ new Coordinate(-122.3460, 47.6190), // NE
+ new Coordinate(-122.3480, 47.6190)
+ ])) { SRID = 4326 }
+ ])
+ { SRID = 4326 };
+
+ public override GeometryCollection OtherValue { get; } = new(
+ [
+ new Point(-121.9000, 46.9500) { SRID = 4326 },
+ new LineString([
+ new Coordinate(-121.9000, 46.9500),
+ new Coordinate(-121.6000, 46.8200)
+ ]) { SRID = 4326 },
+ new Polygon(new LinearRing([
+ new Coordinate(-121.8800, 46.9400), // NW
+ new Coordinate(-121.8800, 46.9200), // SW
+ new Coordinate(-121.8600, 46.9200), // SE
+ new Coordinate(-121.8600, 46.9400), // NE
+ new Coordinate(-121.8800, 46.9400)
+ ])) { SRID = 4326 }
+ ])
+ { SRID = 4326 };
}
+}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerGeometryTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerGeometryTypeTest.cs
index d6b4a463e0e..a9a04cc2342 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerGeometryTypeTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerGeometryTypeTest.cs
@@ -15,19 +15,36 @@ public override async Task Equality_in_query()
{
await using var context = Fixture.CreateContext();
- var result = await context.Set().Where(e => e.Value.EqualsTopologically(Fixture.Value)).SingleAsync();
+ var result = await context.Set>().Where(e => e.Value.EqualsTopologically(Fixture.Value)).SingleAsync();
Assert.Equal(Fixture.Value, result.Value, Fixture.Comparer);
}
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', [j].[OtherValue].STAsText())
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', [j].[OtherValue].STAsText())
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
}
- public abstract class GeometryTypeFixture : RelationalTypeTestFixture
+ public abstract class GeometryTypeFixture : SqlServerTypeFixture
{
public override string? StoreType => "geometry";
@@ -196,12 +213,24 @@ public override async Task ExecuteUpdate_within_json_to_constant()
{
await base.ExecuteUpdate_within_json_to_constant();
- AssertSql(
- """
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', N'GEOMETRYCOLLECTION (POINT (-120.9 46.95), LINESTRING (-120.9 46.95, -120.4 46.82), POLYGON ((-120.8 46.94, -120.8 46.92, -120.78 46.92, -120.78 46.94, -120.8 46.94)))')
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
UPDATE [j]
SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', N'GEOMETRYCOLLECTION (POINT (-120.9 46.95), LINESTRING (-120.9 46.95, -120.4 46.82), POLYGON ((-120.8 46.94, -120.8 46.92, -120.78 46.92, -120.78 46.94, -120.8 46.94)))')
FROM [JsonTypeEntity] AS [j]
""");
+ }
}
public class GeometryCollectionTypeFixture() : GeometryTypeFixture
diff --git a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerMiscellaneousTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerMiscellaneousTypeTest.cs
index e78701dead3..a465ae4405d 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerMiscellaneousTypeTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerMiscellaneousTypeTest.cs
@@ -6,7 +6,7 @@ namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous;
public class BoolTypeTest(BoolTypeTest.BoolTypeFixture fixture)
: RelationalTypeTestBase(fixture)
{
- public class BoolTypeFixture : RelationalTypeTestFixture
+ public class BoolTypeFixture : SqlServerTypeFixture
{
public override bool Value { get; } = true;
public override bool OtherValue { get; } = false;
@@ -18,7 +18,7 @@ public class BoolTypeFixture : RelationalTypeTestFixture
public class StringTypeTest(StringTypeTest.StringTypeFixture fixture)
: RelationalTypeTestBase(fixture)
{
- public class StringTypeFixture : RelationalTypeTestFixture
+ public class StringTypeFixture : SqlServerTypeFixture
{
public override string Value { get; } = "foo";
public override string OtherValue { get; } = "bar";
@@ -30,33 +30,85 @@ public class StringTypeFixture : RelationalTypeTestFixture
public class GuidTypeTest(GuidTypeTest.GuidTypeFixture fixture)
: RelationalTypeTestBase(fixture)
{
+ [SqlServerCondition(SqlServerCondition.SupportsFunctions2022)]
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ // TODO: Currently failing on Helix only, see #36746
+ if (Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null)
+ {
+ return;
+ }
+
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+
}
- public class GuidTypeFixture : RelationalTypeTestFixture
+ public class GuidTypeFixture : SqlServerTypeFixture
{
public override Guid Value { get; } = new("8f7331d6-cde9-44fb-8611-81fff686f280");
public override Guid OtherValue { get; } = new("ae192c36-9004-49b2-b785-8be10d169627");
protected override ITestStoreFactory TestStoreFactory => SqlServerTestStoreFactory.Instance;
+
+ public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
+ => TestEnvironment.SetCompatibilityLevelFromEnvironment(base.AddOptions(builder));
}
}
public class ByteArrayTypeTest(ByteArrayTypeTest.ByteArrayTypeFixture fixture)
: RelationalTypeTestBase(fixture)
{
+ [SqlServerCondition(SqlServerCondition.SupportsFunctions2022)]
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ // TODO: Currently failing on Helix only, see #36746
+ if (Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null)
+ {
+ return;
+ }
+
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
}
- public class ByteArrayTypeFixture() : RelationalTypeTestFixture
+ public class ByteArrayTypeFixture() : SqlServerTypeFixture
{
public override byte[] Value { get; } = [1, 2, 3];
public override byte[] OtherValue { get; } = [4, 5, 6, 7];
@@ -64,5 +116,8 @@ public class ByteArrayTypeFixture() : RelationalTypeTestFixture
public override Func Comparer { get; } = (a, b) => a.SequenceEqual(b);
protected override ITestStoreFactory TestStoreFactory => SqlServerTestStoreFactory.Instance;
+
+ public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
+ => TestEnvironment.SetCompatibilityLevelFromEnvironment(base.AddOptions(builder));
}
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerNumericTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerNumericTypeTest.cs
index cace1fd6d13..3ca93bcdf2d 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerNumericTypeTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerNumericTypeTest.cs
@@ -5,7 +5,7 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric;
public class ByteTypeTest(ByteTypeTest.ByteTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class ByteTypeFixture : RelationalTypeTestFixture
+ public class ByteTypeFixture : SqlServerTypeFixture
{
public override byte Value { get; } = byte.MinValue;
public override byte OtherValue { get; } = byte.MaxValue;
@@ -16,7 +16,7 @@ public class ByteTypeFixture : RelationalTypeTestFixture
public class ShortTypeTest(ShortTypeTest.ShortTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class ShortTypeFixture : RelationalTypeTestFixture
+ public class ShortTypeFixture : SqlServerTypeFixture
{
public override short Value { get; } = short.MinValue;
public override short OtherValue { get; } = short.MaxValue;
@@ -27,7 +27,7 @@ public class ShortTypeFixture : RelationalTypeTestFixture
public class IntTypeTest(IntTypeTest.IntTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class IntTypeFixture : RelationalTypeTestFixture
+ public class IntTypeFixture : SqlServerTypeFixture
{
public override int Value { get; } = int.MinValue;
public override int OtherValue { get; } = int.MaxValue;
@@ -38,7 +38,7 @@ public class IntTypeFixture : RelationalTypeTestFixture
public class LongTypeTest(LongTypeTest.LongTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class LongTypeFixture : RelationalTypeTestFixture
+ public class LongTypeFixture : SqlServerTypeFixture
{
public override long Value { get; } = long.MinValue;
public override long OtherValue { get; } = long.MaxValue;
@@ -49,7 +49,7 @@ public class LongTypeFixture : RelationalTypeTestFixture
public class DecimalTypeTest(DecimalTypeTest.DecimalTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class DecimalTypeFixture : RelationalTypeTestFixture
+ public class DecimalTypeFixture : SqlServerTypeFixture
{
public override decimal Value { get; } = 30.5m;
public override decimal OtherValue { get; } = 30m;
@@ -64,7 +64,7 @@ public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder build
public class DoubleTypeTest(DoubleTypeTest.DoubleTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class DoubleTypeFixture : RelationalTypeTestFixture
+ public class DoubleTypeFixture : SqlServerTypeFixture
{
public override double Value { get; } = 30.5d;
public override double OtherValue { get; } = 30d;
@@ -75,7 +75,7 @@ public class DoubleTypeFixture : RelationalTypeTestFixture
public class FloatTypeTest(FloatTypeTest.FloatTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class FloatTypeFixture : RelationalTypeTestFixture
+ public class FloatTypeFixture : SqlServerTypeFixture
{
public override float Value { get; } = 30.5f;
public override float OtherValue { get; } = 30f;
diff --git a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerTemporalTypeTest.cs b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerTemporalTypeTest.cs
index e9fde6eb679..4ca3f0f049e 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerTemporalTypeTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerTemporalTypeTest.cs
@@ -6,7 +6,7 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal;
public class DateTimeTypeTest(DateTimeTypeTest.DateTimeTypeFixture fixture, ITestOutputHelper testOutputHelper)
: RelationalTypeTestBase(fixture, testOutputHelper)
{
- public class DateTimeTypeFixture : RelationalTypeTestFixture
+ public class DateTimeTypeFixture : SqlServerTypeFixture
{
public override DateTime Value { get; } = new DateTime(2020, 1, 5, 12, 30, 45, DateTimeKind.Unspecified);
public override DateTime OtherValue { get; } = new DateTime(2022, 5, 3, 0, 0, 0, DateTimeKind.Unspecified);
@@ -35,19 +35,55 @@ public override async Task ExecuteUpdate_within_json_to_constant()
{
await base.ExecuteUpdate_within_json_to_constant();
- AssertSql(
- """
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', N'2022-05-03T00:00:00')
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
UPDATE [j]
SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', N'2022-05-03T00:00:00')
FROM [JsonTypeEntity] AS [j]
""");
+ }
}
+ [SqlServerCondition(SqlServerCondition.SupportsFunctions2022)]
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ // TODO: Currently failing on Helix only, see #36746
+ if (Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null)
+ {
+ return;
+ }
+
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+ UPDATE [j]
+ SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+ FROM [JsonTypeEntity] AS [j]
+ """);
+ }
}
}
@@ -75,22 +111,58 @@ public override async Task ExecuteUpdate_within_json_to_constant()
{
await base.ExecuteUpdate_within_json_to_constant();
- AssertSql(
- """
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', N'2020-01-05T12:30:45+03:00')
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
UPDATE [j]
SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', N'2020-01-05T12:30:45+03:00')
FROM [JsonTypeEntity] AS [j]
""");
+ }
}
+ [SqlServerCondition(SqlServerCondition.SupportsFunctions2022)]
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ // TODO: Currently failing on Helix only, see #36746
+ if (Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null)
+ {
+ return;
+ }
+
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
}
- public class DateTimeOffsetTypeFixture : RelationalTypeTestFixture
+ public class DateTimeOffsetTypeFixture : SqlServerTypeFixture
{
public override DateTimeOffset Value { get; } = new DateTimeOffset(2020, 1, 5, 12, 30, 45, TimeSpan.FromHours(2));
public override DateTimeOffset OtherValue { get; } = new DateTimeOffset(2020, 1, 5, 12, 30, 45, TimeSpan.FromHours(3));
@@ -123,22 +195,58 @@ public override async Task ExecuteUpdate_within_json_to_constant()
{
await base.ExecuteUpdate_within_json_to_constant();
- AssertSql(
- """
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', N'2022-05-03')
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
UPDATE [j]
SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', N'2022-05-03')
FROM [JsonTypeEntity] AS [j]
""");
+ }
}
+ [SqlServerCondition(SqlServerCondition.SupportsFunctions2022)]
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ // TODO: Currently failing on Helix only, see #36746
+ if (Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null)
+ {
+ return;
+ }
+
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+ UPDATE [j]
+ SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+ FROM [JsonTypeEntity] AS [j]
+ """);
+ }
}
- public class DateTypeFixture : RelationalTypeTestFixture
+ public class DateTypeFixture : SqlServerTypeFixture
{
public override DateOnly Value { get; } = new DateOnly(2020, 1, 5);
public override DateOnly OtherValue { get; } = new DateOnly(2022, 5, 3);
@@ -147,8 +255,8 @@ public class DateTypeFixture : RelationalTypeTestFixture
}
}
-public class TimeOnlyTypeTest(TimeOnlyTypeTest.TimeTypeFixture fixture, ITestOutputHelper testOutputHelper)
- : RelationalTypeTestBase(fixture, testOutputHelper)
+public class TimeOnlyTypeTest(TimeOnlyTypeTest.TimeOnlyTypeFixture fixture, ITestOutputHelper testOutputHelper)
+ : RelationalTypeTestBase(fixture, testOutputHelper)
{
public override async Task SaveChanges_within_json()
{
@@ -171,22 +279,58 @@ public override async Task ExecuteUpdate_within_json_to_constant()
{
await base.ExecuteUpdate_within_json_to_constant();
- AssertSql(
- """
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', N'14:00:00.0000000')
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
UPDATE [j]
SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', N'14:00:00.0000000')
FROM [JsonTypeEntity] AS [j]
""");
+ }
}
+ [SqlServerCondition(SqlServerCondition.SupportsFunctions2022)]
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ // TODO: Currently failing on Helix only, see #36746
+ if (Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null)
+ {
+ return;
+ }
+
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
}
- public class TimeTypeFixture : RelationalTypeTestFixture
+ public class TimeOnlyTypeFixture : SqlServerTypeFixture
{
public override TimeOnly Value { get; } = new TimeOnly(12, 30, 45);
public override TimeOnly OtherValue { get; } = new TimeOnly(14, 0, 0);
@@ -219,22 +363,58 @@ public override async Task ExecuteUpdate_within_json_to_constant()
{
await base.ExecuteUpdate_within_json_to_constant();
- AssertSql(
- """
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', N'14:00:00')
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
UPDATE [j]
SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', N'14:00:00')
FROM [JsonTypeEntity] AS [j]
""");
+ }
}
+ [SqlServerCondition(SqlServerCondition.SupportsFunctions2022)]
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ // TODO: Currently failing on Helix only, see #36746
+ if (Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT") is not null)
+ {
+ return;
+ }
+
+ await base.ExecuteUpdate_within_json_to_nonjson_column();
+
+ if (Fixture.UsingJsonType)
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [JsonContainer].modify('$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
+ else
+ {
+ AssertSql(
+ """
+UPDATE [j]
+SET [j].[JsonContainer] = JSON_MODIFY([j].[JsonContainer], '$.Value', JSON_VALUE(JSON_OBJECT('v': [j].[OtherValue]), '$.v'))
+FROM [JsonTypeEntity] AS [j]
+""");
+ }
}
- public class TimeSpanTypeFixture : RelationalTypeTestFixture
+ public class TimeSpanTypeFixture : SqlServerTypeFixture
{
public override TimeSpan Value { get; } = new TimeSpan(12, 30, 45);
public override TimeSpan OtherValue { get; } = new TimeSpan(14, 0, 0);
diff --git a/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerTypeFixture.cs b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerTypeFixture.cs
new file mode 100644
index 00000000000..30df874e1e0
--- /dev/null
+++ b/test/EFCore.SqlServer.FunctionalTests/Types/SqlServerTypeFixture.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Types;
+
+public abstract class SqlServerTypeFixture : RelationalTypeFixtureBase
+{
+ public override DbContextOptionsBuilder AddOptions(DbContextOptionsBuilder builder)
+ => TestEnvironment.SetCompatibilityLevelFromEnvironment(base.AddOptions(builder));
+
+ public virtual bool UsingJsonType
+ => TestEnvironment.SqlServerMajorVersion >= 17;
+}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Types/SqliteMiscellaneousTypeTest.cs b/test/EFCore.Sqlite.FunctionalTests/Types/SqliteMiscellaneousTypeTest.cs
index c33a42acd12..efca0f9f78c 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Types/SqliteMiscellaneousTypeTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Types/SqliteMiscellaneousTypeTest.cs
@@ -6,7 +6,7 @@ namespace Microsoft.EntityFrameworkCore.Types.Miscellaneous;
public class BoolTypeTest(BoolTypeTest.BoolTypeFixture fixture)
: RelationalTypeTestBase(fixture)
{
- public class BoolTypeFixture : RelationalTypeTestFixture
+ public class BoolTypeFixture : RelationalTypeFixtureBase
{
public override bool Value { get; } = true;
public override bool OtherValue { get; } = false;
@@ -18,7 +18,7 @@ public class BoolTypeFixture : RelationalTypeTestFixture
public class StringTypeTest(StringTypeTest.StringTypeFixture fixture)
: RelationalTypeTestBase(fixture)
{
- public class StringTypeFixture : RelationalTypeTestFixture
+ public class StringTypeFixture : RelationalTypeFixtureBase
{
public override string Value { get; } = "foo";
public override string OtherValue { get; } = "bar";
@@ -32,12 +32,12 @@ public class GuidTypeTest(GuidTypeTest.GuidTypeFixture fixture)
{
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
+ // See #36688 for supporting this for Sqlite types other than string/numeric/bool
var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
}
- public class GuidTypeFixture : RelationalTypeTestFixture
+ public class GuidTypeFixture : RelationalTypeFixtureBase
{
public override Guid Value { get; } = new("8f7331d6-cde9-44fb-8611-81fff686f280");
public override Guid OtherValue { get; } = new("ae192c36-9004-49b2-b785-8be10d169627");
@@ -51,12 +51,12 @@ public class ByteArrayTypeTest(ByteArrayTypeTest.ByteArrayTypeFixture fixture)
{
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
+ // See #36688 for supporting this for Sqlite types other than string/numeric/bool
var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
}
- public class ByteArrayTypeFixture : RelationalTypeTestFixture
+ public class ByteArrayTypeFixture : RelationalTypeFixtureBase
{
public override byte[] Value { get; } = [1, 2, 3];
public override byte[] OtherValue { get; } = [4, 5, 6, 7];
diff --git a/test/EFCore.Sqlite.FunctionalTests/Types/SqliteNumericTypeTest.cs b/test/EFCore.Sqlite.FunctionalTests/Types/SqliteNumericTypeTest.cs
index 36a83927998..ac44eee3c3e 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Types/SqliteNumericTypeTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Types/SqliteNumericTypeTest.cs
@@ -5,7 +5,7 @@ namespace Microsoft.EntityFrameworkCore.Types.Numeric;
public class ByteTypeTest(ByteTypeTest.ByteTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class ByteTypeFixture : RelationalTypeTestFixture
+ public class ByteTypeFixture : RelationalTypeFixtureBase
{
public override byte Value { get; } = byte.MinValue;
public override byte OtherValue { get; } = byte.MaxValue;
@@ -16,7 +16,7 @@ public class ByteTypeFixture : RelationalTypeTestFixture
public class ShortTypeTest(ShortTypeTest.ShortTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class ShortTypeFixture : RelationalTypeTestFixture
+ public class ShortTypeFixture : RelationalTypeFixtureBase
{
public override short Value { get; } = short.MinValue;
public override short OtherValue { get; } = short.MaxValue;
@@ -27,7 +27,7 @@ public class ShortTypeFixture : RelationalTypeTestFixture
public class IntTypeTest(IntTypeTest.IntTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class IntTypeFixture : RelationalTypeTestFixture
+ public class IntTypeFixture : RelationalTypeFixtureBase
{
public override int Value { get; } = int.MinValue;
public override int OtherValue { get; } = int.MaxValue;
@@ -38,7 +38,7 @@ public class IntTypeFixture : RelationalTypeTestFixture
public class LongTypeTest(LongTypeTest.LongTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class LongTypeFixture : RelationalTypeTestFixture
+ public class LongTypeFixture : RelationalTypeFixtureBase
{
public override long Value { get; } = long.MinValue;
public override long OtherValue { get; } = long.MaxValue;
@@ -49,7 +49,7 @@ public class LongTypeFixture : RelationalTypeTestFixture
public class DecimalTypeTest(DecimalTypeTest.DecimalTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class DecimalTypeFixture : RelationalTypeTestFixture
+ public class DecimalTypeFixture : RelationalTypeFixtureBase
{
public override decimal Value { get; } = 30.5m;
public override decimal OtherValue { get; } = 30m;
@@ -60,7 +60,7 @@ public class DecimalTypeFixture : RelationalTypeTestFixture
public class DoubleTypeTest(DoubleTypeTest.DoubleTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class DoubleTypeFixture : RelationalTypeTestFixture
+ public class DoubleTypeFixture : RelationalTypeFixtureBase
{
public override double Value { get; } = 30.5d;
public override double OtherValue { get; } = 30d;
@@ -71,7 +71,7 @@ public class DoubleTypeFixture : RelationalTypeTestFixture
public class FloatTypeTest(FloatTypeTest.FloatTypeFixture fixture) : RelationalTypeTestBase(fixture)
{
- public class FloatTypeFixture : RelationalTypeTestFixture
+ public class FloatTypeFixture : RelationalTypeFixtureBase
{
public override float Value { get; } = 30.5f;
public override float OtherValue { get; } = 30f;
diff --git a/test/EFCore.Sqlite.FunctionalTests/Types/SqliteTemporalTypeTest.cs b/test/EFCore.Sqlite.FunctionalTests/Types/SqliteTemporalTypeTest.cs
index 80e0b361aed..405de087189 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Types/SqliteTemporalTypeTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Types/SqliteTemporalTypeTest.cs
@@ -6,20 +6,20 @@ namespace Microsoft.EntityFrameworkCore.Types.Temporal;
public class DateTimeTypeTest(DateTimeTypeTest.DateTimeTypeFixture fixture)
: RelationalTypeTestBase(fixture)
{
- public class DateTimeTypeFixture : RelationalTypeTestFixture
+ public override async Task ExecuteUpdate_within_json_to_nonjson_column()
+ {
+ // See #36688 for supporting this for Sqlite types other than string/numeric/bool
+ var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
+ Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
+ }
+
+ public class DateTimeTypeFixture : RelationalTypeFixtureBase
{
public override DateTime Value { get; } = new DateTime(2020, 1, 5, 12, 30, 45, DateTimeKind.Unspecified);
public override DateTime OtherValue { get; } = new DateTime(2022, 5, 3, 0, 0, 0, DateTimeKind.Unspecified);
protected override ITestStoreFactory TestStoreFactory => SqliteTestStoreFactory.Instance;
}
-
- public override async Task ExecuteUpdate_within_json_to_nonjson_column()
- {
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
- var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
- Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
- }
}
public class DateTimeOffsetTypeTest(DateTimeOffsetTypeTest.DateTimeOffsetTypeFixture fixture)
@@ -27,12 +27,12 @@ public class DateTimeOffsetTypeTest(DateTimeOffsetTypeTest.DateTimeOffsetTypeFix
{
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
+ // See #36688 for supporting this for Sqlite types other than string/numeric/bool
var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
}
- public class DateTimeOffsetTypeFixture : RelationalTypeTestFixture
+ public class DateTimeOffsetTypeFixture : RelationalTypeFixtureBase
{
public override DateTimeOffset Value { get; } = new DateTimeOffset(2020, 1, 5, 12, 30, 45, TimeSpan.FromHours(2));
public override DateTimeOffset OtherValue { get; } = new DateTimeOffset(2020, 1, 5, 12, 30, 45, TimeSpan.FromHours(3));
@@ -45,12 +45,12 @@ public class DateOnlyTypeTest(DateOnlyTypeTest.DateTypeFixture fixture) : Relati
{
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
+ // See #36688 for supporting this for Sqlite types other than string/numeric/bool
var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
}
- public class DateTypeFixture : RelationalTypeTestFixture
+ public class DateTypeFixture : RelationalTypeFixtureBase
{
public override DateOnly Value { get; } = new DateOnly(2020, 1, 5);
public override DateOnly OtherValue { get; } = new DateOnly(2022, 5, 3);
@@ -64,12 +64,12 @@ public class TimeOnlyTypeTest(TimeOnlyTypeTest.TimeTypeFixture fixture)
{
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
+ // See #36688 for supporting this for Sqlite types other than string/numeric/bool
var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
}
- public class TimeTypeFixture : RelationalTypeTestFixture
+ public class TimeTypeFixture : RelationalTypeFixtureBase
{
public override TimeOnly Value { get; } = new TimeOnly(12, 30, 45);
public override TimeOnly OtherValue { get; } = new TimeOnly(14, 0, 0);
@@ -82,12 +82,12 @@ public class TimeSpanTypeTest(TimeSpanTypeTest.TimeSpanTypeFixture fixture) : Re
{
public override async Task ExecuteUpdate_within_json_to_nonjson_column()
{
- // See #36688 for supporting this for SQL Server types other than string/numeric/bool
+ // See #36688 for supporting this for Sqlite types other than string/numeric/bool
var exception = await Assert.ThrowsAsync(() => base.ExecuteUpdate_within_json_to_nonjson_column());
Assert.Equal(RelationalStrings.ExecuteUpdateCannotSetJsonPropertyToNonJsonColumn, exception.Message);
}
- public class TimeSpanTypeFixture : RelationalTypeTestFixture
+ public class TimeSpanTypeFixture : RelationalTypeFixtureBase
{
public override TimeSpan Value { get; } = new TimeSpan(12, 30, 45);
public override TimeSpan OtherValue { get; } = new TimeSpan(14, 0, 0);