Add option to use the normal short text type when mapping against an unbounded System.String instead of long text/memo. Jet has limitations when using memo (e.g. joins are not supported)

pull/137/head
Christopher Jolly 3 years ago
parent 950089a113
commit 12aca42198

@ -15,5 +15,6 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
DataAccessProviderType DataAccessProviderType { get; }
bool UseOuterSelectSkipEmulationViaDataReader { get; }
bool EnableMillisecondsSupport { get; }
bool UseShortTextForSystemString { get; }
}
}

@ -24,6 +24,7 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
private DbProviderFactory? _dataAccessProviderFactory;
private bool _useOuterSelectSkipEmulationViaDataReader;
private bool _enableMillisecondsSupport;
private bool _useShortTextForSystemString;
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@ -50,6 +51,7 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
_dataAccessProviderFactory = copyFrom._dataAccessProviderFactory;
_useOuterSelectSkipEmulationViaDataReader = copyFrom._useOuterSelectSkipEmulationViaDataReader;
_enableMillisecondsSupport = copyFrom._enableMillisecondsSupport;
_useShortTextForSystemString = copyFrom._useShortTextForSystemString;
}
/// <summary>
@ -111,7 +113,7 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
/// </summary>
public virtual JetOptionsExtension WithDataAccessProviderFactory(DbProviderFactory dataAccessProviderFactory)
{
var clone = (JetOptionsExtension) Clone();
var clone = (JetOptionsExtension)Clone();
clone._dataAccessProviderFactory = dataAccessProviderFactory;
@ -134,7 +136,7 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
/// </summary>
public virtual JetOptionsExtension WithUseOuterSelectSkipEmulationViaDataReader(bool enabled)
{
var clone = (JetOptionsExtension) Clone();
var clone = (JetOptionsExtension)Clone();
clone._useOuterSelectSkipEmulationViaDataReader = enabled;
@ -157,13 +159,36 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
/// </summary>
public virtual JetOptionsExtension WithEnableMillisecondsSupport(bool enabled)
{
var clone = (JetOptionsExtension) Clone();
var clone = (JetOptionsExtension)Clone();
clone._enableMillisecondsSupport = enabled;
return clone;
}
/// <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 bool UseShortTextForSystemString => _useShortTextForSystemString;
/// <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 JetOptionsExtension WithUseShortTextForSystemString(bool enabled)
{
var clone = (JetOptionsExtension)Clone();
clone._useShortTextForSystemString = enabled;
return clone;
}
/// <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
@ -184,7 +209,7 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
}
private new JetOptionsExtension Extension
=> (JetOptionsExtension) base.Extension;
=> (JetOptionsExtension)base.Extension;
public override bool IsDatabaseProvider => true;
@ -219,6 +244,10 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
{
builder.Append("EnableMillisecondsSupport ");
}
if (Extension._useShortTextForSystemString)
{
builder.Append("UseShortTextForSystemString ");
}
_logFragment = builder.ToString();
}
@ -234,7 +263,8 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
_serviceProviderHash = (base.GetServiceProviderHashCode() * 397) ^
(Extension._dataAccessProviderFactory?.GetHashCode() ?? 0) ^
(Extension._useOuterSelectSkipEmulationViaDataReader.GetHashCode() * 397) ^
(Extension._enableMillisecondsSupport.GetHashCode() * 397)/* ^
(Extension._enableMillisecondsSupport.GetHashCode() * 397) ^
(Extension._useShortTextForSystemString.GetHashCode() * 397)/* ^
(Extension._rowNumberPaging?.GetHashCode() ?? 0L)*/;
}
@ -255,6 +285,8 @@ namespace EntityFrameworkCore.Jet.Infrastructure.Internal
= Extension._useOuterSelectSkipEmulationViaDataReader.GetHashCode().ToString(CultureInfo.InvariantCulture);
debugInfo["Jet:" + nameof(JetDbContextOptionsBuilder.EnableMillisecondsSupport)]
= Extension._enableMillisecondsSupport.GetHashCode().ToString(CultureInfo.InvariantCulture);
debugInfo["Jet:" + nameof(JetDbContextOptionsBuilder.UseShortTextForSystemString)]
= Extension._useShortTextForSystemString.GetHashCode().ToString(CultureInfo.InvariantCulture);
}
}
}

@ -54,6 +54,18 @@ namespace EntityFrameworkCore.Jet.Infrastructure
public virtual JetDbContextOptionsBuilder EnableMillisecondsSupport(bool enabled = true)
=> WithOption(e => e.WithEnableMillisecondsSupport(enabled));
/// <summary>
/// Set this to enabled to map the System.String CLR type to the Jet `Short Text` data type instead of the
/// Long Text data type. This will limit the maximum length of strings to 255 characters.
/// As System.String does not have a size it is normally mapped to 'lonchar' or 'memo' (SQL Server is 'nvarchar(max)'
/// Jet/Ace has limitations when using memo for strings:
/// - Joins based on the memo column are not supported
/// - Ordering the column (specially the implicit ordering) can be a bit different to expected behaviour
/// </summary>
public virtual JetDbContextOptionsBuilder UseShortTextForSystemString(bool enabled = true)
=> WithOption(e => e.WithUseShortTextForSystemString(enabled));
/// <summary>
/// Configures the context to use the default retrying <see cref="IExecutionStrategy" />.
/// </summary>

@ -25,11 +25,12 @@ namespace EntityFrameworkCore.Jet.Internal
var jetOptions = options.FindExtension<JetOptionsExtension>() ?? new JetOptionsExtension();
// RowNumberPagingEnabled = jetOptions.RowNumberPaging ?? false;
DataAccessProviderType = GetDataAccessProviderTypeFromOptions(jetOptions);
UseOuterSelectSkipEmulationViaDataReader = jetOptions.UseOuterSelectSkipEmulationViaDataReader;
EnableMillisecondsSupport = jetOptions.EnableMillisecondsSupport;
ConnectionString = jetOptions.Connection?.ConnectionString ?? jetOptions.ConnectionString!;
UseShortTextForSystemString = jetOptions.UseShortTextForSystemString;
}
/// <summary>
@ -73,15 +74,22 @@ namespace EntityFrameworkCore.Jet.Internal
nameof(JetOptionsExtension.EnableMillisecondsSupport),
nameof(DbContextOptionsBuilder.UseInternalServiceProvider)));
}
if (UseShortTextForSystemString != jetOptions.UseShortTextForSystemString)
{
throw new InvalidOperationException(
CoreStrings.SingletonOptionChanged(
nameof(JetOptionsExtension.UseShortTextForSystemString),
nameof(DbContextOptionsBuilder.UseInternalServiceProvider)));
}
}
private static DataAccessProviderType GetDataAccessProviderTypeFromOptions(JetOptionsExtension jetOptions)
{
if (jetOptions.DataAccessProviderFactory == null)
{
throw new InvalidOperationException(JetStrings.DataAccessProviderFactory);
}
if (jetOptions.DataAccessProviderFactory
.GetType()
.GetTypesInHierarchy()
@ -106,7 +114,7 @@ namespace EntityFrameworkCore.Jet.Internal
{
return DataAccessProviderType.Odbc;
}
throw new InvalidOperationException("The JetConnection.DataAccessProviderFactory property needs to be set to an object of type OdbcFactory or OleDbFactory.");
}
@ -142,6 +150,8 @@ namespace EntityFrameworkCore.Jet.Internal
/// </summary>
public bool EnableMillisecondsSupport { get; private set; }
public bool UseShortTextForSystemString { get; private set; }
/// <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

@ -64,6 +64,8 @@ namespace EntityFrameworkCore.Jet.Storage.Internal
private readonly Dictionary<Type, RelationalTypeMapping> _clrTypeMappings;
private readonly HashSet<string> _disallowedMappings;
private readonly IJetOptions _options;
/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
@ -225,6 +227,8 @@ namespace EntityFrameworkCore.Jet.Storage.Internal
"national char varying",
"national character varying",
};
_options = options;
}
/// <summary>
@ -324,6 +328,12 @@ namespace EntityFrameworkCore.Jet.Storage.Internal
size = isFixedLength ? maxCharColumnSize : (int?)null;
}
if (_options.UseShortTextForSystemString && size == null)
{
return new JetStringTypeMapping("varchar", unicode: true, size: 255);
}
return size == null
? _unboundedUnicodeString
: new JetStringTypeMapping(

@ -478,15 +478,17 @@ INNER JOIN (
await base.Join_navigation_deeply_nested_non_key_join(isAsync);
AssertSql(
$@"SELECT `l`.`Id` AS `Id4`, `l`.`Name` AS `Name4`, `t`.`Id` AS `Id1`, `t`.`Name` AS `Name1`
"""
SELECT `l`.`Id` AS `Id4`, `l`.`Name` AS `Name4`, `t`.`Id` AS `Id1`, `t`.`Name` AS `Name1`
FROM `LevelFour` AS `l`
INNER JOIN (
SELECT `l0`.`Id`, `l0`.`Date`, `l0`.`Name`, `l0`.`OneToMany_Optional_Self_Inverse1Id`, `l0`.`OneToMany_Required_Self_Inverse1Id`, `l0`.`OneToOne_Optional_Self1Id`, `l1`.`Id` AS `Id0`, `l1`.`Date` AS `Date0`, `l1`.`Level1_Optional_Id`, `l1`.`Level1_Required_Id`, `l1`.`Name` AS `Name0`, `l1`.`OneToMany_Optional_Inverse2Id`, `l1`.`OneToMany_Optional_Self_Inverse2Id`, `l1`.`OneToMany_Required_Inverse2Id`, `l1`.`OneToMany_Required_Self_Inverse2Id`, `l1`.`OneToOne_Optional_PK_Inverse2Id`, `l1`.`OneToOne_Optional_Self2Id`, `l2`.`Id` AS `Id1`, `l2`.`Level2_Optional_Id`, `l2`.`Level2_Required_Id`, `l2`.`Name` AS `Name1`, `l2`.`OneToMany_Optional_Inverse3Id`, `l2`.`OneToMany_Optional_Self_Inverse3Id`, `l2`.`OneToMany_Required_Inverse3Id`, `l2`.`OneToMany_Required_Self_Inverse3Id`, `l2`.`OneToOne_Optional_PK_Inverse3Id`, `l2`.`OneToOne_Optional_Self3Id`, `l3`.`Id` AS `Id2`, `l3`.`Level3_Optional_Id`, `l3`.`Level3_Required_Id`, `l3`.`Name` AS `Name2`, `l3`.`OneToMany_Optional_Inverse4Id`, `l3`.`OneToMany_Optional_Self_Inverse4Id`, `l3`.`OneToMany_Required_Inverse4Id`, `l3`.`OneToMany_Required_Self_Inverse4Id`, `l3`.`OneToOne_Optional_PK_Inverse4Id`, `l3`.`OneToOne_Optional_Self4Id`
SELECT `l0`.`Id`, `l0`.`Name`, `l3`.`Name` AS `Name2`
FROM ((`LevelOne` AS `l0`
LEFT JOIN `LevelTwo` AS `l1` ON `l0`.`Id` = `l1`.`Level1_Required_Id`)
LEFT JOIN `LevelThree` AS `l2` ON `l1`.`Id` = `l2`.`Level2_Optional_Id`)
LEFT JOIN `LevelFour` AS `l3` ON `l2`.`Id` = `l3`.`Id`
) AS `t` ON `l`.`Name` = `t`.`Name2`");
) AS `t` ON `l`.`Name` = `t`.`Name2`
""");
}
public override async Task Join_navigation_deeply_nested_required(bool isAsync)
@ -494,15 +496,17 @@ INNER JOIN (
await base.Join_navigation_deeply_nested_required(isAsync);
AssertSql(
$@"SELECT `t`.`Id` AS `Id4`, `t`.`Name` AS `Name4`, `l`.`Id` AS `Id1`, `l`.`Name` AS `Name1`
"""
SELECT `t`.`Id` AS `Id4`, `t`.`Name` AS `Name4`, `l`.`Id` AS `Id1`, `l`.`Name` AS `Name1`
FROM `LevelOne` AS `l`
INNER JOIN (
SELECT `l0`.`Id`, `l0`.`Level3_Optional_Id`, `l0`.`Level3_Required_Id`, `l0`.`Name`, `l0`.`OneToMany_Optional_Inverse4Id`, `l0`.`OneToMany_Optional_Self_Inverse4Id`, `l0`.`OneToMany_Required_Inverse4Id`, `l0`.`OneToMany_Required_Self_Inverse4Id`, `l0`.`OneToOne_Optional_PK_Inverse4Id`, `l0`.`OneToOne_Optional_Self4Id`, `l1`.`Id` AS `Id0`, `l1`.`Level2_Optional_Id`, `l1`.`Level2_Required_Id`, `l1`.`Name` AS `Name0`, `l1`.`OneToMany_Optional_Inverse3Id`, `l1`.`OneToMany_Optional_Self_Inverse3Id`, `l1`.`OneToMany_Required_Inverse3Id`, `l1`.`OneToMany_Required_Self_Inverse3Id`, `l1`.`OneToOne_Optional_PK_Inverse3Id`, `l1`.`OneToOne_Optional_Self3Id`, `l2`.`Id` AS `Id1`, `l2`.`Date`, `l2`.`Level1_Optional_Id`, `l2`.`Level1_Required_Id`, `l2`.`Name` AS `Name1`, `l2`.`OneToMany_Optional_Inverse2Id`, `l2`.`OneToMany_Optional_Self_Inverse2Id`, `l2`.`OneToMany_Required_Inverse2Id`, `l2`.`OneToMany_Required_Self_Inverse2Id`, `l2`.`OneToOne_Optional_PK_Inverse2Id`, `l2`.`OneToOne_Optional_Self2Id`, `l3`.`Id` AS `Id2`, `l3`.`Date` AS `Date0`, `l3`.`Name` AS `Name2`, `l3`.`OneToMany_Optional_Self_Inverse1Id`, `l3`.`OneToMany_Required_Self_Inverse1Id`, `l3`.`OneToOne_Optional_Self1Id`
SELECT `l0`.`Id`, `l0`.`Name`, `l3`.`Name` AS `Name2`
FROM ((`LevelFour` AS `l0`
INNER JOIN `LevelThree` AS `l1` ON `l0`.`Level3_Required_Id` = `l1`.`Id`)
INNER JOIN `LevelTwo` AS `l2` ON `l1`.`Level2_Required_Id` = `l2`.`Id`)
INNER JOIN `LevelOne` AS `l3` ON `l2`.`Id` = `l3`.`Id`
) AS `t` ON `l`.`Name` = `t`.`Name2`");
) AS `t` ON `l`.`Name` = `t`.`Name2`
""");
}
public override async Task Select_nav_prop_reference_optional1(bool isAsync)
@ -1215,7 +1219,7 @@ WHERE EXISTS (
SELECT 1
FROM `LevelThree` AS `l1`))");
}
public override async Task SelectMany_where_with_subquery(bool isAsync)
{
await base.SelectMany_where_with_subquery(isAsync);
@ -1723,13 +1727,15 @@ WHERE 1 IN (
await base.Required_navigation_on_a_subquery_with_First_in_projection(isAsync);
AssertSql(
$@"SELECT (
SELECT TOP 1 `l0`.`Name`
FROM `LevelTwo` AS `l`
INNER JOIN `LevelOne` AS `l0` ON `l`.`Level1_Required_Id` = `l0`.`Id`
ORDER BY `l`.`Id`)
FROM `LevelTwo` AS `l1`
WHERE `l1`.`Id` = 7");
"""
SELECT (
SELECT TOP 1 `l1`.`Name`
FROM `LevelTwo` AS `l0`
INNER JOIN `LevelOne` AS `l1` ON `l0`.`Level1_Required_Id` = `l1`.`Id`
ORDER BY `l0`.`Id`)
FROM `LevelTwo` AS `l`
WHERE `l`.`Id` = 7
""");
}
public override async Task Required_navigation_on_a_subquery_with_complex_projection_and_First(bool isAsync)
@ -1737,14 +1743,16 @@ WHERE `l1`.`Id` = 7");
await base.Required_navigation_on_a_subquery_with_complex_projection_and_First(isAsync);
AssertSql(
$@"SELECT (
SELECT TOP 1 `l1`.`Name`
FROM `LevelTwo` AS `l`
INNER JOIN `LevelOne` AS `l0` ON `l`.`Level1_Required_Id` = `l0`.`Id`
INNER JOIN `LevelOne` AS `l1` ON `l`.`Level1_Required_Id` = `l1`.`Id`
ORDER BY `l`.`Id`)
FROM `LevelTwo` AS `l2`
WHERE `l2`.`Id` = 7");
"""
SELECT (
SELECT TOP 1 `l2`.`Name`
FROM (`LevelTwo` AS `l0`
INNER JOIN `LevelOne` AS `l1` ON `l0`.`Level1_Required_Id` = `l1`.`Id`)
INNER JOIN `LevelOne` AS `l2` ON `l0`.`Level1_Required_Id` = `l2`.`Id`
ORDER BY `l0`.`Id`)
FROM `LevelTwo` AS `l`
WHERE `l`.`Id` = 7
""");
}
public override async Task Required_navigation_on_a_subquery_with_First_in_predicate(bool isAsync)
@ -1752,13 +1760,15 @@ WHERE `l2`.`Id` = 7");
await base.Required_navigation_on_a_subquery_with_First_in_predicate(isAsync);
AssertSql(
$@"SELECT `l`.`Id`, `l`.`Date`, `l`.`Level1_Optional_Id`, `l`.`Level1_Required_Id`, `l`.`Name`, `l`.`OneToMany_Optional_Inverse2Id`, `l`.`OneToMany_Optional_Self_Inverse2Id`, `l`.`OneToMany_Required_Inverse2Id`, `l`.`OneToMany_Required_Self_Inverse2Id`, `l`.`OneToOne_Optional_PK_Inverse2Id`, `l`.`OneToOne_Optional_Self2Id`
"""
SELECT `l`.`Id`, `l`.`Date`, `l`.`Level1_Optional_Id`, `l`.`Level1_Required_Id`, `l`.`Name`, `l`.`OneToMany_Optional_Inverse2Id`, `l`.`OneToMany_Optional_Self_Inverse2Id`, `l`.`OneToMany_Required_Inverse2Id`, `l`.`OneToMany_Required_Self_Inverse2Id`, `l`.`OneToOne_Optional_PK_Inverse2Id`, `l`.`OneToOne_Optional_Self2Id`
FROM `LevelTwo` AS `l`
WHERE (`l`.`Id` = 7) AND ((
WHERE `l`.`Id` = 7 AND (
SELECT TOP 1 `l1`.`Name`
FROM `LevelTwo` AS `l0`
INNER JOIN `LevelOne` AS `l1` ON `l0`.`Level1_Required_Id` = `l1`.`Id`
ORDER BY `l0`.`Id`) = 'L1 02')");
ORDER BY `l0`.`Id`) = 'L1 02'
""");
}
public override async Task Manually_created_left_join_propagates_nullability_to_navigations(bool isAsync)
@ -1881,7 +1891,7 @@ LEFT JOIN (
LEFT JOIN `LevelOne` AS `l1` ON `l0`.`Level1_Required_Id` = `l1`.`Id`
) AS `t` ON `l`.`Id` = `t`.`Level1_Required_Id`");
}
public override async Task GroupJoin_on_a_subquery_containing_another_GroupJoin_projecting_outer(bool isAsync)
{
await base.GroupJoin_on_a_subquery_containing_another_GroupJoin_projecting_outer(isAsync);
@ -2040,7 +2050,7 @@ WHERE (
LEFT JOIN `LevelTwo` AS `l3` ON `l2`.`Id` = `l3`.`Level1_Optional_Id`) > 7) > 4 AND `l`.`Id` < 2
""");
}
public override async Task GroupJoin_client_method_on_outer(bool isAsync)
{
await base.GroupJoin_client_method_on_outer(isAsync);
@ -2224,7 +2234,7 @@ INNER JOIN `LevelTwo` AS `l0` ON `l`.`OneToMany_Optional_Self_Inverse1Id` = `l0`
FROM `LevelOne` AS `l`
INNER JOIN `LevelTwo` AS `l0` ON (`l`.`OneToMany_Optional_Self_Inverse1Id` = `l0`.`Level1_Optional_Id` OR ((`l`.`OneToMany_Optional_Self_Inverse1Id` IS NULL) AND (`l0`.`Level1_Optional_Id` IS NULL))) AND (`l`.`OneToOne_Optional_Self1Id` = `l0`.`OneToMany_Optional_Self_Inverse2Id` OR ((`l`.`OneToOne_Optional_Self1Id` IS NULL) AND (`l0`.`OneToMany_Optional_Self_Inverse2Id` IS NULL)))");
}
public override async Task Nested_group_join_with_take(bool isAsync)
{
await base.Nested_group_join_with_take(isAsync);
@ -2363,12 +2373,14 @@ WHERE `l0`.`Id` IS NULL");
await base.Select_subquery_with_client_eval_and_navigation1(isAsync);
AssertSql(
$@"SELECT (
SELECT TOP 1 `l0`.`Name`
FROM `LevelTwo` AS `l`
INNER JOIN `LevelOne` AS `l0` ON `l`.`Level1_Required_Id` = `l0`.`Id`
ORDER BY `l`.`Id`)
FROM `LevelTwo` AS `l1`");
"""
SELECT (
SELECT TOP 1 `l1`.`Name`
FROM `LevelTwo` AS `l0`
INNER JOIN `LevelOne` AS `l1` ON `l0`.`Level1_Required_Id` = `l1`.`Id`
ORDER BY `l0`.`Id`)
FROM `LevelTwo` AS `l`
""");
}
public override async Task Select_subquery_with_client_eval_and_navigation2(bool isAsync)
@ -2376,19 +2388,18 @@ FROM `LevelTwo` AS `l1`");
await base.Select_subquery_with_client_eval_and_navigation2(isAsync);
AssertSql(
$@"SELECT CASE
WHEN ((
SELECT TOP 1 `l0`.`Name`
FROM `LevelTwo` AS `l`
INNER JOIN `LevelOne` AS `l0` ON `l`.`Level1_Required_Id` = `l0`.`Id`
ORDER BY `l`.`Id`) = 'L1 02') AND (
SELECT TOP 1 `l0`.`Name`
FROM `LevelTwo` AS `l`
INNER JOIN `LevelOne` AS `l0` ON `l`.`Level1_Required_Id` = `l0`.`Id`
ORDER BY `l`.`Id`) IS NOT NULL THEN True
ELSE False
END
FROM `LevelTwo` AS `l1`");
"""
SELECT IIF((
SELECT TOP 1 `l1`.`Name`
FROM `LevelTwo` AS `l0`
INNER JOIN `LevelOne` AS `l1` ON `l0`.`Level1_Required_Id` = `l1`.`Id`
ORDER BY `l0`.`Id`) = 'L1 02' AND ((
SELECT TOP 1 `l1`.`Name`
FROM `LevelTwo` AS `l0`
INNER JOIN `LevelOne` AS `l1` ON `l0`.`Level1_Required_Id` = `l1`.`Id`
ORDER BY `l0`.`Id`) IS NOT NULL), TRUE, FALSE)
FROM `LevelTwo` AS `l`
""");
}
public override async Task Select_subquery_with_client_eval_and_multi_level_navigation(bool isAsync)
@ -2958,12 +2969,13 @@ ORDER BY `l`.`Id`, `l0`.`Id`, `l1`.`Id`");
await base.Member_pushdown_chain_3_levels_deep(isAsync);
AssertSql(
@"SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `l`.`OneToMany_Optional_Self_Inverse1Id`, `l`.`OneToMany_Required_Self_Inverse1Id`, `l`.`OneToOne_Optional_Self1Id`
"""
SELECT `l`.`Id`, `l`.`Date`, `l`.`Name`, `l`.`OneToMany_Optional_Self_Inverse1Id`, `l`.`OneToMany_Required_Self_Inverse1Id`, `l`.`OneToOne_Optional_Self1Id`
FROM `LevelOne` AS `l`
WHERE ((
SELECT TOP(1) (
SELECT TOP(1) (
SELECT TOP(1) `l2`.`Name`
WHERE (
SELECT TOP 1 (
SELECT TOP 1 (
SELECT TOP 1 `l2`.`Name`
FROM `LevelFour` AS `l2`
WHERE `l2`.`Level3_Required_Id` = `l1`.`Id`
ORDER BY `l2`.`Id`)
@ -2972,10 +2984,10 @@ WHERE ((
ORDER BY `l1`.`Id`)
FROM `LevelTwo` AS `l0`
WHERE `l0`.`Level1_Optional_Id` = `l`.`Id`
ORDER BY `l0`.`Id`) <> N'Foo') OR ((
SELECT TOP(1) (
SELECT TOP(1) (
SELECT TOP(1) `l2`.`Name`
ORDER BY `l0`.`Id`) <> 'Foo' OR ((
SELECT TOP 1 (
SELECT TOP 1 (
SELECT TOP 1 `l2`.`Name`
FROM `LevelFour` AS `l2`
WHERE `l2`.`Level3_Required_Id` = `l1`.`Id`
ORDER BY `l2`.`Id`)
@ -2985,7 +2997,8 @@ WHERE ((
FROM `LevelTwo` AS `l0`
WHERE `l0`.`Level1_Optional_Id` = `l`.`Id`
ORDER BY `l0`.`Id`) IS NULL)
ORDER BY `l`.`Id`");
ORDER BY `l`.`Id`
""");
}
public override async Task Member_pushdown_chain_3_levels_deep_entity(bool isAsync)
@ -3048,24 +3061,26 @@ ORDER BY `l`.`Id`");
await base.Member_pushdown_with_multiple_collections(isAsync);
AssertSql(
@"SELECT (
"""
SELECT (
SELECT TOP 1 `l0`.`Name`
FROM `LevelThree` AS `l0`
WHERE ((
SELECT TOP 1 `l1`.`Id`
FROM `LevelTwo` AS `l1`
WHERE `l`.`Id` = `l1`.`OneToMany_Optional_Inverse2Id`
ORDER BY `l1`.`Id`) IS NOT NULL) AND (((
SELECT TOP(1) `l2`.`Id`
ORDER BY `l1`.`Id`) IS NOT NULL) AND ((
SELECT TOP 1 `l2`.`Id`
FROM `LevelTwo` AS `l2`
WHERE `l`.`Id` = `l2`.`OneToMany_Optional_Inverse2Id`
ORDER BY `l2`.`Id`) = `l0`.`OneToMany_Optional_Inverse3Id`) OR (((
SELECT TOP(1) `l2`.`Id`
ORDER BY `l2`.`Id`) = `l0`.`OneToMany_Optional_Inverse3Id` OR (((
SELECT TOP 1 `l2`.`Id`
FROM `LevelTwo` AS `l2`
WHERE `l`.`Id` = `l2`.`OneToMany_Optional_Inverse2Id`
ORDER BY `l2`.`Id`) IS NULL) AND (`l0`.`OneToMany_Optional_Inverse3Id` IS NULL)))
ORDER BY `l0`.`Id`)
FROM `LevelOne` AS `l`");
FROM `LevelOne` AS `l`
""");
}
public override async Task Null_check_removal_applied_recursively(bool isAsync)

@ -3939,15 +3939,17 @@ ORDER BY `g`.`Nickname`, `g`.`SquadId`
await base.Correlated_collections_basic_projection_ordered(isAsync);
AssertSql(
$@"SELECT `g`.`Nickname`, `g`.`SquadId`, `t`.`Id`, `t`.`AmmunitionType`, `t`.`IsAutomatic`, `t`.`Name`, `t`.`OwnerFullName`, `t`.`SynergyWithId`
"""
SELECT `g`.`Nickname`, `g`.`SquadId`, `t`.`Id`, `t`.`AmmunitionType`, `t`.`IsAutomatic`, `t`.`Name`, `t`.`OwnerFullName`, `t`.`SynergyWithId`
FROM `Gears` AS `g`
LEFT JOIN (
SELECT `w`.`Id`, `w`.`AmmunitionType`, `w`.`IsAutomatic`, `w`.`Name`, `w`.`OwnerFullName`, `w`.`SynergyWithId`
FROM `Weapons` AS `w`
WHERE (`w`.`IsAutomatic` = True) OR ((`w`.`Name` <> 'foo') OR `w`.`Name` IS NULL)
WHERE `w`.`IsAutomatic` = TRUE OR `w`.`Name` <> 'foo' OR (`w`.`Name` IS NULL)
) AS `t` ON `g`.`FullName` = `t`.`OwnerFullName`
WHERE `g`.`Discriminator` IN ('Gear', 'Officer') AND (`g`.`Nickname` <> 'Marcus')
ORDER BY `g`.`Nickname`, `g`.`SquadId`, `t`.`Name` DESC, `t`.`Id`");
WHERE `g`.`Nickname` <> 'Marcus'
ORDER BY `g`.`Nickname`, `g`.`SquadId`, `t`.`Name` DESC
""");
}
public override async Task Correlated_collections_basic_projection_composite_key(bool isAsync)
@ -6160,13 +6162,14 @@ ORDER BY IIF(`w`.`SynergyWithId` IS NULL, 0, `w`.`SynergyWithId`), `w`.`Id`");
await base.Query_with_complex_let_containing_ordering_and_filter_projecting_firstOrDefault_element_of_let(isAsync);
AssertSql(
"""
SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`Discriminator`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`
FROM `Gears` AS `g`
WHERE `g`.`FullName` <> 'Dom' AND EXISTS (
SELECT 1
"""
SELECT `g`.`Nickname`, (
SELECT TOP 1 `w`.`Name`
FROM `Weapons` AS `w`
WHERE `g`.`FullName` = `w`.`OwnerFullName` AND `w`.`IsAutomatic` = TRUE)
WHERE `g`.`FullName` = `w`.`OwnerFullName` AND `w`.`IsAutomatic` = TRUE
ORDER BY `w`.`AmmunitionType` DESC) AS `WeaponName`
FROM `Gears` AS `g`
WHERE `g`.`Nickname` <> 'Dom'
""");
}
@ -7229,23 +7232,17 @@ WHERE DATALENGTH(`s`.`Banner5`) = 5
AssertSql(
"""
@__prm_0='True'
@__prm2_1='Dom's Lancer' (Size = 4000)
@__prm2_1='Dom's Lancer' (Size = 255)
SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`Discriminator`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`
FROM `Gears` AS `g`
WHERE CASE
WHEN `g`.`HasSoulPatch` = @__prm_0 THEN CASE
WHEN (
SELECT TOP(1) `w`.`Name`
WHERE IIF(`g`.`HasSoulPatch` = @__prm_0, IIF((
SELECT TOP 1 `w`.`Name`
FROM `Weapons` AS `w`
WHERE `w`.`Id` = `g`.`SquadId`) = @__prm2_1 AND ((
SELECT TOP(1) `w`.`Name`
SELECT TOP 1 `w`.`Name`
FROM `Weapons` AS `w`
WHERE `w`.`Id` = `g`.`SquadId`) IS NOT NULL) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END
ELSE CAST(0 AS bit)
END = CAST(1 AS bit)
WHERE `w`.`Id` = `g`.`SquadId`) IS NOT NULL), TRUE, FALSE), FALSE) = TRUE
""");
}

@ -458,7 +458,7 @@ ORDER BY `a`.`Name`");
@"SELECT `a`.`Id`, `a`.`CountryId`, `a`.`Discriminator`, `a`.`Name`, `a`.`Species`, `a`.`EagleId`, `a`.`IsFlightless`, `a`.`Group`, `m`.`CountryId`, `m`.`Discriminator`, `m`.`Name`, `m`.`EagleId`, `m`.`IsFlightless`, `m`.`Group`, `m`.`FoundOn`
FROM `Animals` AS `a`
INNER JOIN (
Select * from ""Animals""
Select * from `Animals`
) AS `m` ON `a`.`Name` = `m`.`Name`
WHERE `a`.`Discriminator` = 'Eagle'");
}
@ -471,7 +471,7 @@ WHERE `a`.`Discriminator` = 'Eagle'");
@"SELECT `a`.`Id`, `a`.`CountryId`, `a`.`Discriminator`, `a`.`Name`, `a`.`Species`, `a`.`EagleId`, `a`.`IsFlightless`, `a`.`Group`, `a`.`FoundOn`
FROM `Animals` AS `a`
WHERE (
SELECT TOP(1) `a0`.`Discriminator`
SELECT TOP 1 `a0`.`Discriminator`
FROM `Animals` AS `a0`
WHERE `a0`.`Name` = 'Great spotted kiwi') = 'Kiwi'
ORDER BY `a`.`Species`");

@ -1188,12 +1188,11 @@ WHERE (MID(`e`.`NullableStringA`, 0 + 1, `e`.`IntA`) <> `e`.`NullableStringB` OR
await base.Null_semantics_join_with_composite_key(async);
AssertSql(
@"SELECT `e`.`Id`, `e`.`BoolA`, `e`.`BoolB`, `e`.`BoolC`, `e`.`IntA`, `e`.`IntB`, `e`.`IntC`, `e`.`NullableBoolA`, `e`.`NullableBoolB`, `e`.`NullableBoolC`, `e`.`NullableIntA`, `e`.`NullableIntB`, `e`.`NullableIntC`, `e`.`NullableStringA`, `e`.`NullableStringB`, `e`.`NullableStringC`, `e`.`StringA`, `e`.`StringB`, `e`.`StringC`, `e0`.`Id`, `e0`.`BoolA`, `e0`.`BoolB`, `e0`.`BoolC`, `e0`.`IntA`, `e0`.`IntB`, `e0`.`IntC`, `e0`.`NullableBoolA`, `e0`.`NullableBoolB`, `e0`.`NullableBoolC`, `e0`.`NullableIntA`, `e0`.`NullableIntB`, `e0`.`NullableIntC`, `e0`.`NullableStringA`, `e0`.`NullableStringB`, `e0`.`NullableStringC`, `e0`.`StringA`, `e0`.`StringB`, `e0`.`StringC`
"""
SELECT `e`.`Id`, `e`.`BoolA`, `e`.`BoolB`, `e`.`BoolC`, `e`.`IntA`, `e`.`IntB`, `e`.`IntC`, `e`.`NullableBoolA`, `e`.`NullableBoolB`, `e`.`NullableBoolC`, `e`.`NullableIntA`, `e`.`NullableIntB`, `e`.`NullableIntC`, `e`.`NullableStringA`, `e`.`NullableStringB`, `e`.`NullableStringC`, `e`.`StringA`, `e`.`StringB`, `e`.`StringC`, `e0`.`Id`, `e0`.`BoolA`, `e0`.`BoolB`, `e0`.`BoolC`, `e0`.`IntA`, `e0`.`IntB`, `e0`.`IntC`, `e0`.`NullableBoolA`, `e0`.`NullableBoolB`, `e0`.`NullableBoolC`, `e0`.`NullableIntA`, `e0`.`NullableIntB`, `e0`.`NullableIntC`, `e0`.`NullableStringA`, `e0`.`NullableStringB`, `e0`.`NullableStringC`, `e0`.`StringA`, `e0`.`StringB`, `e0`.`StringC`
FROM `Entities1` AS `e`
INNER JOIN `Entities2` AS `e0` ON ((`e`.`NullableStringA` = `e0`.`NullableStringB`) OR ((`e`.`NullableStringA` IS NULL) AND (`e0`.`NullableStringB` IS NULL))) AND (CASE
WHEN ((`e`.`NullableStringB` <> `e`.`NullableStringC`) OR ((`e`.`NullableStringB` IS NULL) OR (`e`.`NullableStringC` IS NULL))) AND ((`e`.`NullableStringB` IS NOT NULL) OR (`e`.`NullableStringC` IS NOT NULL)) THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END = COALESCE(`e0`.`NullableBoolA`, `e0`.`BoolC`))");
INNER JOIN `Entities2` AS `e0` ON (`e`.`NullableStringA` = `e0`.`NullableStringB` OR ((`e`.`NullableStringA` IS NULL) AND (`e0`.`NullableStringB` IS NULL))) AND IIF((`e`.`NullableStringB` <> `e`.`NullableStringC` OR (`e`.`NullableStringB` IS NULL) OR (`e`.`NullableStringC` IS NULL)) AND ((`e`.`NullableStringB` IS NOT NULL) OR (`e`.`NullableStringC` IS NOT NULL)), TRUE, FALSE) = IIF(`e0`.`NullableBoolA` IS NULL, `e0`.`BoolC`, `e0`.`NullableBoolA`)
""");
}
public override async Task Null_semantics_contains(bool async)

@ -109,7 +109,7 @@ LEFT JOIN (
WHERE `o`.`Discriminator` = N'LeafA'
ORDER BY `o`.`Id`, `t`.`ClientId`, `t`.`Id`, `t`.`OrderClientId`, `t`.`OrderId`");
}
public override async Task Query_when_subquery(bool isAsync)
{
await base.Query_when_subquery(isAsync);
@ -203,7 +203,7 @@ ORDER BY `o`.`Id`");
AssertSql(
@"SELECT (
SELECT TOP(1) `o1`.`PersonAddress_Country_Name`
SELECT TOP 1 `o1`.`PersonAddress_Country_Name`
FROM `Order` AS `o0`
LEFT JOIN `OwnedPerson` AS `o1` ON `o0`.`ClientId` = `o1`.`Id`
WHERE `o`.`Id` = `o0`.`ClientId`

@ -997,7 +997,7 @@ Queen of the Andals and the Rhoynar and the First Men, Khaleesi of the Great Gra
// AssertSql(
// $@"{AssertSqlHelper.Declaration("@__firstName_0='Foo' (Size = 450)")}
//@__8__locals1_details_LastName_1='Bar' (Size = 450)
//@__8__locals1_details_LastName_1='Bar' (Size = 450)
//SELECT `c`.`FirstName`, `c`.`LastName`
//FROM `Customer` AS `c`
@ -4629,7 +4629,7 @@ FROM `Prices` AS `p`");
AssertSql(
$@"SELECT `r`.`Id`, `r`.`MyTime`
FROM `ReproEntity` AS `r`
WHERE `r`.`MyTime` IN ('2018-10-07T00:00:00')");
WHERE `r`.`MyTime` = #2018-10-07#");
}
}
}

@ -22,22 +22,22 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
public const int CommandTimeout = 300;
public static JetTestStore GetNorthwindStore()
=> (JetTestStore) JetNorthwindTestStoreFactory.Instance
=> (JetTestStore)JetNorthwindTestStoreFactory.Instance
.GetOrCreate(JetNorthwindTestStoreFactory.Name)
.Initialize(null, (Func<DbContext>) null);
.Initialize(null, (Func<DbContext>)null);
public static JetTestStore GetOrCreate(string name, string scriptPath = null, string templatePath = null)
=> new JetTestStore(name, scriptPath: scriptPath, templatePath: templatePath);
public static JetTestStore GetOrCreateInitialized(string name)
=> new JetTestStore(name).InitializeJet(null, (Func<DbContext>) null, null);
=> new JetTestStore(name).InitializeJet(null, (Func<DbContext>)null, null);
public static JetTestStore Create(string name)
=> new JetTestStore(name, shared: false);
public static JetTestStore CreateInitialized(string name)
=> new JetTestStore(name, shared: false)
.InitializeJet(null, (Func<DbContext>) null, null);
.InitializeJet(null, (Func<DbContext>)null, null);
private readonly string _scriptPath;
private readonly string _templatePath;
@ -68,7 +68,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
ConnectionString = CreateConnectionString(Name);
var dataAccessProviderFactory = JetFactory.Instance.GetDataAccessProviderFactory(JetConnection.GetDataAccessProviderType(ConnectionString));
var connection = (JetConnection) JetFactory.Instance.CreateConnection();
var connection = (JetConnection)JetFactory.Instance.CreateConnection();
connection.ConnectionString = ConnectionString;
connection.DataAccessProviderFactory = dataAccessProviderFactory;
@ -77,7 +77,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
public JetTestStore InitializeJet(
IServiceProvider serviceProvider, Func<DbContext> createContext, Action<DbContext> seed)
=> (JetTestStore) Initialize(serviceProvider, createContext, seed);
=> (JetTestStore)Initialize(serviceProvider, createContext, seed);
public JetTestStore InitializeJet(
IServiceProvider serviceProvider, Func<JetTestStore, DbContext> createContext, Action<DbContext> seed)
@ -103,7 +103,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
}
public override DbContextOptionsBuilder AddProviderOptions(DbContextOptionsBuilder builder)
=> builder.UseJet(Connection, b => b.ApplyConfiguration()).EnableSensitiveDataLogging().EnableDetailedErrors();
=> builder.UseJet(Connection, b => b.ApplyConfiguration().UseShortTextForSystemString()).EnableSensitiveDataLogging().EnableDetailedErrors();
private bool CreateDatabase(Action<DbContext> clean)
{
@ -170,13 +170,13 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
=> ExecuteScalar<T>(Connection, sql, parameters);
private static T ExecuteScalar<T>(DbConnection connection, string sql, params object[] parameters)
=> Execute(connection, command => (T) command.ExecuteScalar(), sql, false, parameters);
=> Execute(connection, command => (T)command.ExecuteScalar(), sql, false, parameters);
public Task<T> ExecuteScalarAsync<T>(string sql, params object[] parameters)
=> ExecuteScalarAsync<T>(Connection, sql, parameters);
private static Task<T> ExecuteScalarAsync<T>(DbConnection connection, string sql, IReadOnlyList<object> parameters = null)
=> ExecuteAsync(connection, async command => (T) await command.ExecuteScalarAsync(), sql, false, parameters);
=> ExecuteAsync(connection, async command => (T)await command.ExecuteScalarAsync(), sql, false, parameters);
public int ExecuteNonQuery(string sql, params object[] parameters)
=> ExecuteNonQuery(Connection, sql, parameters);
@ -202,7 +202,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
var results = Enumerable.Empty<T>();
while (dataReader.Read())
{
results = results.Concat(new[] {dataReader.GetFieldValue<T>(0)});
results = results.Concat(new[] { dataReader.GetFieldValue<T>(0) });
}
return results;
@ -221,7 +221,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
var results = Enumerable.Empty<T>();
while (await dataReader.ReadAsync())
{
results = results.Concat(new[] {await dataReader.GetFieldValueAsync<T>(0)});
results = results.Concat(new[] { await dataReader.GetFieldValueAsync<T>(0) });
}
return results;
@ -374,7 +374,7 @@ namespace EntityFrameworkCore.Jet.FunctionalTests.TestUtilities
private static DbCommand CreateCommand(
DbConnection connection, string commandText = null, IReadOnlyList<object> parameters = null)
{
var command = (JetCommand) connection.CreateCommand();
var command = (JetCommand)connection.CreateCommand();
command.CommandText = commandText;
command.CommandTimeout = CommandTimeout;

Loading…
Cancel
Save