Skip to content

Commit 8033475

Browse files
ChrisJollyAUgithub-actions
andauthored
Sync to an RC2 build (#265)
* RC2 History Repo * return the right ValueGenerated if it is mapped to json * Since Jet doesn't do anything for GO we don't need to do anything like Sql server does * Update the HistoryRepository * Remove unused tests * [GitHub Actions] Update green tests. --------- Co-authored-by: github-actions <[email protected]>
1 parent b64c1d5 commit 8033475

File tree

12 files changed

+168
-167
lines changed

12 files changed

+168
-167
lines changed

Dependencies.targets

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project>
22
<PropertyGroup>
33
<DotNetVersion>[9.0.100-rc.1.24452.12,9.0.999]</DotNetVersion>
4-
<EFCoreVersion>[9.0.0-rc.1.24451.1,9.0.999]</EFCoreVersion>
5-
<MSLibVersion>[9.0.0-rc.1.24431.7,9.0.999]</MSLibVersion>
4+
<EFCoreVersion>[9.0.0-rc.2.24460.3,9.0.999]</EFCoreVersion>
5+
<MSLibVersion>[9.0.0-rc.2.24456.9,9.0.999]</MSLibVersion>
66
</PropertyGroup>
77

88
<ItemGroup>
@@ -26,7 +26,7 @@
2626
<PackageReference Update="System.Data.Odbc" Version="$(MSLibVersion)" />
2727
<PackageReference Update="System.Data.OleDb" Version="$(MSLibVersion)" />
2828
<PackageReference Update="Microsoft.EntityFrameworkCore.Design" Version="$(EFCoreVersion)" />
29-
<PackageReference Update="Microsoft.EntityFrameworkCore.Relational.Specification.Tests" Version="$(EFCoreVersion)" /> <!-- Should be same as efcoreversion. preview6 was broken and published separately -->
29+
<PackageReference Update="Microsoft.EntityFrameworkCore.Relational.Specification.Tests" Version="$(EFCoreVersion)" />
3030
<PackageReference Update="Microsoft.Extensions.Logging.Console" Version="$(MSLibVersion)" />
3131
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="17.11.1" />
3232
<PackageReference Update="MSTest.TestAdapter" Version="3.6.0" />

src/EFCore.Jet.Data/JetStoreSchemaDefinition/JetSchemaOperationsHandling.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace EntityFrameworkCore.Jet.Data.JetStoreSchemaDefinition
44
{
5-
internal static class JetSchemaOperationsHandling
5+
public static class JetSchemaOperationsHandling
66
{
77
private static readonly Regex _renameTableRegex = new Regex(
88
$@"^\s*alter\s+table\s+{GetIdentifierPattern("OldTableName")}\s+rename\s+to\s+{GetIdentifierPattern("NewTableName")}\s*$",
@@ -12,6 +12,9 @@ internal static class JetSchemaOperationsHandling
1212
$@"^\s*alter\s+table\s+{GetIdentifierPattern("TableName")}\s+rename\s+column\s+{GetIdentifierPattern("OldColumnName")}\s+to\s+{GetIdentifierPattern("NewColumnName")}\s*$",
1313
RegexOptions.IgnoreCase);
1414

15+
public static bool IsDatabaseOperation(string commandText)
16+
=> _renameTableRegex.IsMatch(commandText) || _renameTableColumnRegex.IsMatch(commandText);
17+
1518
public static bool TryDatabaseOperation(JetConnection connection, string commandText)
1619
{
1720
var match = _renameTableRegex.Match(commandText);

src/EFCore.Jet/Extensions/JetServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public static IServiceCollection AddEntityFrameworkJet([NotNull] this IServiceCo
5252
.TryAdd<IRelationalConnection>(p => p.GetRequiredService<IJetRelationalConnection>())
5353
.TryAdd<IMigrationsSqlGenerator, JetMigrationsSqlGenerator>()
5454
.TryAdd<IRelationalDatabaseCreator, JetDatabaseCreator>()
55+
.TryAdd<IMigrationCommandExecutor, JetMigrationCommandExecutor>()
5556
.TryAdd<IHistoryRepository, JetHistoryRepository>()
5657
.TryAdd<ICompiledQueryCacheKeyGenerator, JetCompiledQueryCacheKeyGenerator>()
5758
.TryAdd<IExecutionStrategyFactory, JetExecutionStrategyFactory>()

src/EFCore.Jet/Metadata/Conventions/JetValueGeneratorConvention.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.EntityFrameworkCore.Metadata.Builders;
77
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
88
using System.Linq;
9+
using Microsoft.EntityFrameworkCore.Metadata.Internal;
910

1011
// ReSharper disable once CheckNamespace
1112
namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
@@ -61,6 +62,14 @@ public override void ProcessPropertyAnnotationChanged(
6162
/// <returns> The store value generation strategy to set for the given property. </returns>
6263
protected override ValueGenerated? GetValueGenerated(IConventionProperty property)
6364
{
65+
if (property.DeclaringType.IsMappedToJson()
66+
#pragma warning disable EF1001 // Internal EF Core API usage.
67+
&& property.IsOrdinalKeyProperty()
68+
#pragma warning restore EF1001 // Internal EF Core API usage.
69+
&& (property.DeclaringType as IReadOnlyEntityType)?.FindOwnership()!.IsUnique == false)
70+
{
71+
return ValueGenerated.OnAdd;
72+
}
6473
var declaringTable = property.GetMappedStoreObjects(StoreObjectType.Table).FirstOrDefault();
6574
if (declaringTable.Name == null)
6675
{

src/EFCore.Jet/Migrations/Internal/JetHistoryRepository.cs

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ namespace EntityFrameworkCore.Jet.Migrations.Internal
3434
public class JetHistoryRepository : HistoryRepository
3535
{
3636
private static readonly TimeSpan _retryDelay = TimeSpan.FromSeconds(1);
37-
37+
public override LockReleaseBehavior LockReleaseBehavior => LockReleaseBehavior.Explicit;
3838
/// <summary>
3939
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
4040
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -128,18 +128,21 @@ public override string GetDeleteScript(string migrationId)
128128
.ToString();
129129
}
130130

131-
public override IDisposable GetDatabaseLock()
131+
public override IMigrationsDatabaseLock AcquireDatabaseLock()
132132
{
133-
if (!InterpretExistsResult(Dependencies.RawSqlCommandBuilder.Build(CreateExistsSql(LockTableName))
134-
.ExecuteScalar(CreateRelationalCommandParameters())))
133+
Dependencies.MigrationsLogger.AcquiringMigrationLock();
134+
135+
if (!InterpretExistsResult(
136+
Dependencies.RawSqlCommandBuilder.Build(CreateExistsSql(LockTableName))
137+
.ExecuteScalar(CreateRelationalCommandParameters())))
135138
{
136139
try
137140
{
138141
CreateLockTableCommand().ExecuteNonQuery(CreateRelationalCommandParameters());
139142
}
140-
catch (DbException)
143+
catch (DbException e)
141144
{
142-
//if (!e.Message.Contains("already exists")) throw;
145+
if (!e.Message.Contains("already exists")) throw;
143146
}
144147
}
145148

@@ -152,11 +155,11 @@ public override IDisposable GetDatabaseLock()
152155
try
153156
{
154157
insertCount = (int?)CreateInsertLockCommand(DateTimeOffset.UtcNow)
155-
.ExecuteScalar(CreateRelationalCommandParameters());
158+
.ExecuteScalar(CreateRelationalCommandParameters());
156159
}
157-
catch (DbException)
160+
catch (DbException e)
158161
{
159-
//if (!e.Message.Contains("duplicate")) throw;
162+
if (!e.Message.Contains("duplicate")) throw;
160163
}
161164
if ((int)insertCount! == 1)
162165
{
@@ -169,44 +172,28 @@ public override IDisposable GetDatabaseLock()
169172
retryDelay = retryDelay.Add(retryDelay);
170173
}
171174
}
172-
173-
throw new TimeoutException();
174175
}
175176

176-
public override async Task<IAsyncDisposable> GetDatabaseLockAsync(CancellationToken cancellationToken = new CancellationToken())
177+
public override async Task<IMigrationsDatabaseLock> AcquireDatabaseLockAsync(
178+
CancellationToken cancellationToken = default)
177179
{
178-
if (!InterpretExistsResult(await Dependencies.RawSqlCommandBuilder.Build(CreateExistsSql(LockTableName))
179-
.ExecuteScalarAsync(CreateRelationalCommandParameters(), cancellationToken).ConfigureAwait(false)))
180+
Dependencies.MigrationsLogger.AcquiringMigrationLock();
181+
182+
if (!InterpretExistsResult(
183+
await Dependencies.RawSqlCommandBuilder.Build(CreateExistsSql(LockTableName))
184+
.ExecuteScalarAsync(CreateRelationalCommandParameters(), cancellationToken).ConfigureAwait(false)))
180185
{
181-
//No CREATE TABLE IF EXISTS in Jet. We try a normal CREATE TABLE and catch the exception if it already exists
182-
try
183-
{
184-
await CreateLockTableCommand()
185-
.ExecuteNonQueryAsync(CreateRelationalCommandParameters(), cancellationToken)
186-
.ConfigureAwait(false);
187-
}
188-
catch (DbException)
189-
{
190-
//if (!e.Message.Contains("already exists")) throw;
191-
}
186+
await CreateLockTableCommand().ExecuteNonQueryAsync(CreateRelationalCommandParameters(), cancellationToken)
187+
.ConfigureAwait(false);
192188
}
193189

194190
var retryDelay = _retryDelay;
195191
while (true)
196192
{
197193
var dbLock = CreateMigrationDatabaseLock();
198-
int? insertCount = 0;
199-
try
200-
{
201-
insertCount = (int?)await CreateInsertLockCommand(DateTimeOffset.UtcNow)
194+
var insertCount = await CreateInsertLockCommand(DateTimeOffset.UtcNow)
202195
.ExecuteScalarAsync(CreateRelationalCommandParameters(), cancellationToken)
203196
.ConfigureAwait(false);
204-
205-
}
206-
catch (DbException)
207-
{
208-
//if (!e.Message.Contains("duplicate")) throw;
209-
}
210197
if ((int)insertCount! == 1)
211198
{
212199
return dbLock;
@@ -218,8 +205,6 @@ await CreateLockTableCommand()
218205
retryDelay = retryDelay.Add(retryDelay);
219206
}
220207
}
221-
222-
throw new TimeoutException();
223208
}
224209

225210
private IRelationalCommand CreateLockTableCommand()
@@ -254,7 +239,7 @@ DELETE FROM `{LockTableName}`
254239
}
255240

256241
private JetMigrationDatabaseLock CreateMigrationDatabaseLock()
257-
=> new(CreateDeleteLockCommand(), CreateRelationalCommandParameters());
242+
=> new(CreateDeleteLockCommand(), CreateRelationalCommandParameters(), this);
258243

259244
private RelationalCommandParameterObject CreateRelationalCommandParameters()
260245
=> new(
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading;
6+
using System.Threading.Tasks;
7+
using Microsoft.EntityFrameworkCore.Diagnostics;
8+
using Microsoft.EntityFrameworkCore.Migrations;
9+
using System.Transactions;
10+
using EntityFrameworkCore.Jet.Data.JetStoreSchemaDefinition;
11+
using Microsoft.EntityFrameworkCore.Migrations.Internal;
12+
using Microsoft.EntityFrameworkCore.Storage;
13+
14+
namespace EntityFrameworkCore.Jet.Migrations.Internal
15+
{
16+
public class JetMigrationCommandExecutor(IExecutionStrategy executionStrategy) : MigrationCommandExecutor(executionStrategy)
17+
{
18+
/// <summary>
19+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
20+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
21+
/// any release. You should only use it directly in your code with extreme caution and knowing that
22+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
23+
/// </summary>
24+
public override int ExecuteNonQuery(
25+
IReadOnlyList<MigrationCommand> migrationCommands,
26+
IRelationalConnection connection,
27+
MigrationExecutionState executionState,
28+
bool commitTransaction,
29+
System.Data.IsolationLevel? isolationLevel = null)
30+
{
31+
var batches = CreateMigrationBatches(migrationCommands);
32+
foreach (var batch in batches)
33+
{
34+
base.ExecuteNonQuery(batch, connection, executionState, true, isolationLevel);
35+
}
36+
37+
return -1;
38+
}
39+
40+
public override async Task<int> ExecuteNonQueryAsync(
41+
IReadOnlyList<MigrationCommand> migrationCommands,
42+
IRelationalConnection connection,
43+
MigrationExecutionState executionState,
44+
bool commitTransaction,
45+
System.Data.IsolationLevel? isolationLevel = null,
46+
CancellationToken cancellationToken = default)
47+
{
48+
var batches = CreateMigrationBatches(migrationCommands);
49+
foreach (var batch in batches)
50+
{
51+
await base.ExecuteNonQueryAsync(batch, connection, executionState, true, isolationLevel, cancellationToken);
52+
}
53+
54+
return -1;
55+
}
56+
57+
List<IReadOnlyList<MigrationCommand>> CreateMigrationBatches(IReadOnlyList<MigrationCommand> migrationCommands)
58+
{
59+
//create new batch if JetSchemaOperationsHandling.IsDatabaseOperation is true otherwise had to current batch
60+
var migrationBatches = new List<IReadOnlyList<MigrationCommand>>();
61+
var currentBatch = new List<MigrationCommand>();
62+
foreach (var migrationCommand in migrationCommands)
63+
{
64+
if (JetSchemaOperationsHandling.IsDatabaseOperation(migrationCommand.CommandText))
65+
{
66+
if (currentBatch.Any())
67+
{
68+
migrationBatches.Add(currentBatch);
69+
currentBatch = new List<MigrationCommand>();
70+
}
71+
migrationBatches.Add(new List<MigrationCommand> { migrationCommand });
72+
}
73+
else
74+
{
75+
currentBatch.Add(migrationCommand);
76+
}
77+
}
78+
if (currentBatch.Any())
79+
{
80+
migrationBatches.Add(currentBatch);
81+
}
82+
return migrationBatches;
83+
}
84+
}
85+
}

src/EFCore.Jet/Migrations/Internal/JetMigrationDatabaseLock.cs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Data.Common;
56
using System.Threading;
67
using System.Threading.Tasks;
8+
using Microsoft.EntityFrameworkCore.Migrations;
79
using Microsoft.EntityFrameworkCore.Storage;
810

911
namespace EntityFrameworkCore.Jet.Migrations.Internal;
@@ -15,19 +17,37 @@ namespace EntityFrameworkCore.Jet.Migrations.Internal;
1517
/// doing so can result in application failures when updating to a new Entity Framework Core release.
1618
/// </summary>
1719
public class JetMigrationDatabaseLock(
18-
IRelationalCommand relationalCommand,
20+
IRelationalCommand releaseLockCommand,
1921
RelationalCommandParameterObject relationalCommandParameters,
22+
IHistoryRepository historyRepository,
2023
CancellationToken cancellationToken = default)
21-
: IDisposable, IAsyncDisposable
24+
: IMigrationsDatabaseLock
2225
{
26+
/// <summary>
27+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
28+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
29+
/// any release. You should only use it directly in your code with extreme caution and knowing that
30+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
31+
/// </summary>
32+
public virtual IHistoryRepository HistoryRepository => historyRepository;
33+
2334
/// <summary>
2435
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
2536
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
2637
/// any release. You should only use it directly in your code with extreme caution and knowing that
2738
/// doing so can result in application failures when updating to a new Entity Framework Core release.
2839
/// </summary>
2940
public void Dispose()
30-
=> relationalCommand.ExecuteScalar(relationalCommandParameters);
41+
{
42+
try
43+
{
44+
releaseLockCommand.ExecuteScalar(relationalCommandParameters);
45+
}
46+
catch (DbException e)
47+
{
48+
if (!e.Message.Contains("cannot find the input table")) throw;
49+
}
50+
}
3151

3252
/// <summary>
3353
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -36,5 +56,14 @@ public void Dispose()
3656
/// doing so can result in application failures when updating to a new Entity Framework Core release.
3757
/// </summary>
3858
public async ValueTask DisposeAsync()
39-
=> await relationalCommand.ExecuteScalarAsync(relationalCommandParameters, cancellationToken).ConfigureAwait(false);
59+
{
60+
try
61+
{
62+
await releaseLockCommand.ExecuteScalarAsync(relationalCommandParameters, cancellationToken);
63+
}
64+
catch (DbException e)
65+
{
66+
if (!e.Message.Contains("cannot find the input table")) throw;
67+
}
68+
}
4069
}

0 commit comments

Comments
 (0)