Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 14 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
###############################################################################
* text=auto

###############################################################################
# C# sources check out CRLF on every platform.
#
# .editorconfig pins end_of_line = crlf for [*.cs] and [*.{cs,vb}], and
# EnforceCodeStyleInBuild makes IDE0055 a build error in src. Under `text=auto`
# alone the working tree takes the platform's ending, so a Linux or macOS
# checkout gets LF and every line then violates that rule while Windows builds
# clean. Pinning the checkout here keeps the one setting that decides this in
# agreement with the one that enforces it. The index is unaffected — it stores
# LF either way.
###############################################################################
*.cs text eol=crlf
*.vb text eol=crlf

###############################################################################
# Set default behavior for command prompt diff.
#
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ jobs:
- 'src/LibRed/**'
- 'test/LibRed.Ado.Tests/**'
- 'test/LibRed.Core.Tests/**'
- 'test/LibRed.Core.AccessTests/**'
- 'test/LibRed.EFCore.Tests/**'
- 'test/LibRed.Engine.Tests/**'
- 'test/LibRed.Engine.AccessTests/**'
Expand Down Expand Up @@ -676,6 +677,13 @@ jobs:
- name: 'Run Tests: LibRed.Engine.Tests'
if: env.skipTests != 'true'
run: dotnet test ./test/LibRed.Engine.Tests --configuration ${{ env.buildConfiguration }} -p:FixedTestOrder=${{ env.deterministicTests }} --blame-hang-timeout 3m
# The file-format half of LibRed.Core.Tests. It reads and writes .accdb files with LibRed alone — the
# cross-checks against the real Access engine live in LibRed.Core.AccessTests — so it belongs on this
# matrix rather than the Windows one, and reading the on-disk format on Linux/macOS/ARM64 is the part
# of the cross-platform claim that was previously only asserted for the engine.
- name: 'Run Tests: LibRed.Core.Tests'
if: always() && env.skipTests != 'true'
run: dotnet test ./test/LibRed.Core.Tests --configuration ${{ env.buildConfiguration }} -p:FixedTestOrder=${{ env.deterministicTests }} --blame-hang-timeout 3m

# The rest of the LibRed suites cross-check LibRed's output against the real engine over OLE DB,
# so unlike the job above they do need Windows with ACE installed.
Expand Down Expand Up @@ -718,10 +726,12 @@ jobs:
}
$v
}
- name: 'Run Tests: LibRed.Core.Tests'
# The file-format tests that cross-check against ACE. Their ACE-free half runs on the five-platform
# LibRed job above.
- name: 'Run Tests: LibRed.Core.AccessTests'
if: env.skipTests != 'true'
shell: pwsh
run: dotnet test .\test\LibRed.Core.Tests --configuration '${{ env.buildConfiguration }}' -p:FixedTestOrder=${{ env.deterministicTests }} --blame-hang-timeout 5m
run: dotnet test .\test\LibRed.Core.AccessTests --configuration '${{ env.buildConfiguration }}' -p:FixedTestOrder=${{ env.deterministicTests }} --blame-hang-timeout 5m
# The engine tests that cross-check against ACE. They belong here rather than in the cross-platform
# LibRed job above, which runs on five platforms precisely to prove LibRed needs no ACE at all.
- name: 'Run Tests: LibRed.Engine.AccessTests'
Expand Down
16 changes: 13 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ dotnet build EFCore.Jet.sln

Assemblies are **strong-name signed** using `Key.snk`. `TreatWarningsAsErrors=True` is set globally — fix all warnings.

`src/Directory.Build.props` also turns on `AnalysisMode=Recommended` and `EnforceCodeStyleInBuild`, so **in `src`
every CA/IDE diagnostic is a build error** (the test projects import the repo-root props and stay on the SDK
default). Fix them rather than suppress them; where a rule's own fix would change behaviour, a `#pragma` carries a
written reason. Two traps: `dotnet format whitespace` handles IDE0055 and `dotnet format style` the other IDE rules,
but **never run either against a single project when the change can touch `src/Shared`** — IDE0005 is evaluated per
project, and formatting one will delete a using the other four consumers still need. The implicit usings those
shared files rely on are declared once in `src/Shared/SharedSource.props`.

### Local EFCore Repository (optional)

To develop against a local EF Core build instead of NuGet packages, copy `Development.props.sample` to `Development.props` and set `LocalEFCoreRepository` to your EF Core checkout. That local build must be compiled with `AssemblyVersion=11.0.0.0` to avoid binding conflicts.
Expand Down Expand Up @@ -267,9 +275,11 @@ The Jet provider (`src/EFCore.Jet*`) has **no** equivalent — it does no ACE ve
`JetTypeMappingSource` keeps `{"bigint", …}` commented out, so `long` maps to `decimal(20,0)` regardless of the
installed engine. That asymmetry is deliberate for now; don't "fix" one side by assuming the other behaves the same.

**Build configuration:** `src/LibRed/Directory.Build.props` bypasses `src/Directory.Build.props` (it imports the
repo-root props directly) to set its own build options — not packable, no documentation file, its own `NoWarn`,
`ImplicitUsings`/`Nullable` on. The Windows stamp is no longer a reason: each driver-bound project applies
**Build configuration:** `src/LibRed/Directory.Build.props` **imports** `src/Directory.Build.props` and adds to it:
`ImplicitUsings`/`Nullable` on, `GenerateDocumentationFile` on (IDE0005 cannot run without it), its own `NoWarn`,
and a LibRed-specific package readme in place of the Jet one the repo root packs. Because it imports rather than
bypasses, the LibRed projects inherit the same `AnalysisMode`/`EnforceCodeStyleInBuild` as the rest of `src`. The
Windows stamp is no longer a reason for any of it: each driver-bound project applies
`[SupportedOSPlatform("windows")]` itself. Strong-naming is preserved.

**SQL pipeline** (always run end-to-end, even for trivial queries, so new features add
Expand Down
16 changes: 13 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ dotnet build EFCore.Jet.sln

Assemblies are **strong-name signed** using `Key.snk`. `TreatWarningsAsErrors=True` is set globally — fix all warnings.

`src/Directory.Build.props` also turns on `AnalysisMode=Recommended` and `EnforceCodeStyleInBuild`, so **in `src`
every CA/IDE diagnostic is a build error** (the test projects import the repo-root props and stay on the SDK
default). Fix them rather than suppress them; where a rule's own fix would change behaviour, a `#pragma` carries a
written reason. Two traps: `dotnet format whitespace` handles IDE0055 and `dotnet format style` the other IDE rules,
but **never run either against a single project when the change can touch `src/Shared`** — IDE0005 is evaluated per
project, and formatting one will delete a using the other four consumers still need. The implicit usings those
shared files rely on are declared once in `src/Shared/SharedSource.props`.

### Local EFCore Repository (optional)

To develop against a local EF Core build instead of NuGet packages, copy `Development.props.sample` to `Development.props` and set `LocalEFCoreRepository` to your EF Core checkout. That local build must be compiled with `AssemblyVersion=11.0.0.0` to avoid binding conflicts.
Expand Down Expand Up @@ -282,9 +290,11 @@ The Jet provider (`src/EFCore.Jet*`) has **no** equivalent — it does no ACE ve
`JetTypeMappingSource` keeps `{"bigint", …}` commented out, so `long` maps to `decimal(20,0)` regardless of the
installed engine. That asymmetry is deliberate for now; don't "fix" one side by assuming the other behaves the same.

**Build configuration:** `src/LibRed/Directory.Build.props` bypasses `src/Directory.Build.props` (it imports the
repo-root props directly) to set its own build options — not packable, no documentation file, its own `NoWarn`,
`ImplicitUsings`/`Nullable` on. The Windows stamp is no longer a reason: each driver-bound project applies
**Build configuration:** `src/LibRed/Directory.Build.props` **imports** `src/Directory.Build.props` and adds to it:
`ImplicitUsings`/`Nullable` on, `GenerateDocumentationFile` on (IDE0005 cannot run without it), its own `NoWarn`,
and a LibRed-specific package readme in place of the Jet one the repo root packs. Because it imports rather than
bypasses, the LibRed projects inherit the same `AnalysisMode`/`EnforceCodeStyleInBuild` as the rest of `src`. The
Windows stamp is no longer a reason for any of it: each driver-bound project applies
`[SupportedOSPlatform("windows")]` itself. Strong-naming is preserved.

**SQL pipeline** (always run end-to-end, even for trivial queries, so new features add
Expand Down
4 changes: 4 additions & 0 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
<NoWarn>$(NoWarn);CS1574;CS1587;CS1591;EF1001;NU1903</NoWarn>
<!--<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)..\rulesets\EFCore.ruleset</CodeAnalysisRuleSet>-->
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!-- Code analysis and code-style analysis, for the shipping code only. The test projects import the
repo-root props instead, so they stay on the SDK's default rule set. -->
<AnalysisMode>Recommended</AnalysisMode>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected override bool IsHandledByConvention(IModel model, IAnnotation annotati
// CHECK: Jet default schema handling.
if (annotation.Name == RelationalAnnotationNames.DefaultSchema)
{
return string.Equals(null, (string?)annotation.Value);
return string.Equals(null, (string?)annotation.Value, StringComparison.Ordinal);
}

return annotation.Name == JetAnnotationNames.ValueGenerationStrategy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,4 @@ public override void Generate(IRelationalPropertyOverrides overrides, CSharpRunt

base.Generate(overrides, parameters);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public class ConflictingValueGenerationStrategiesEventData(
/// <summary>
/// The property.
/// </summary>
// CA1716 objects to "Property" as a VB keyword; it is the name EF Core's own PropertyEventData uses,
// and this type is consumed through that same diagnostics surface.
#pragma warning disable CA1716
public virtual IProperty Property { get; } = property;
#pragma warning restore CA1716
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ namespace EntityFrameworkCore.Jet.Diagnostics.Internal
/// 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>
// CA1051 wants properties, but a LoggingDefinitions class is a cache of lazily-built event definitions that
// the logger extensions assign into by field; EF Core's own SqlServerLoggingDefinitions is written the same way.
#pragma warning disable CA1051
public class JetLoggingDefinitions : RelationalLoggingDefinitions
{
/// <summary>
Expand Down Expand Up @@ -162,4 +165,5 @@ public class JetLoggingDefinitions : RelationalLoggingDefinitions
/// </summary>
public EventDefinitionBase? LogConflictingValueGenerationStrategies;
}
#pragma warning restore CA1051
}
7 changes: 1 addition & 6 deletions src/EFCore.Jet.Common/EFCore.Jet.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\Shared\*.cs" />
</ItemGroup>
<Import Project="..\Shared\SharedSource.props" />

<ItemGroup>
<None Update="Properties\JetStrings.Designer.tt">
Expand All @@ -37,9 +35,6 @@

<ItemGroup>
<Using Include="System.Data.Common" />
<Using Include="System.Diagnostics" />
<Using Include="System.Linq.Expressions" />
<Using Include="System.Reflection" />
<Using Include="Microsoft.EntityFrameworkCore" />
<Using Include="Microsoft.EntityFrameworkCore.ChangeTracking" />
<Using Include="Microsoft.EntityFrameworkCore.Diagnostics" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -778,4 +778,4 @@ public static int ByteArrayLength(

#endregion Population variance
}
}
}
2 changes: 1 addition & 1 deletion src/EFCore.Jet.Common/Extensions/JetModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public static void SetJetIdentityIncrement(this IMutableModel model, int? increm
/// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param>
public static int? SetJetIdentityIncrement(
this IConventionModel model, int? increment, bool fromDataAnnotation = false)
=> (int?) model.SetOrRemoveAnnotation(
=> (int?)model.SetOrRemoveAnnotation(
JetAnnotationNames.IdentityIncrement,
increment,
fromDataAnnotation)?.Value;
Expand Down
9 changes: 6 additions & 3 deletions src/EFCore.Jet.Common/Infrastructure/JetDualTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ public static class JetDualTable
/// <summary>
/// The DUAL table or query
/// </summary>
public static string CustomName = "";
public static string CustomName { get; set; } = "";
//MSysRelationships
//MSysAccessStorage
//#Dual
//(SELECT COUNT(*) FROM MSysAccessStorage)

public static string DetectedName = "#Dual";
/// <summary>
/// The DUAL table or query the scaffolding factory last detected in the database.
/// </summary>
public static string DetectedName { get; set; } = "#Dual";

/// <summary>
/// The name to generate into SQL: the user's <see cref="CustomName"/> when one has been set,
Expand All @@ -49,4 +52,4 @@ public static string Name
? DetectedName
: CustomName;
}
}
}
8 changes: 7 additions & 1 deletion src/EFCore.Jet.Common/Internal/JetLoggerExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

// Every method here follows EF Core's own logger-extension shape: the message template comes from an
// EventDefinition rather than being a literal, and the call is already guarded by ShouldLog. That is what
// CA2254 (varying template), CA1848 (LoggerMessage delegates) and CA1873 (params array) each object to, and
// EF Core's own generated extensions are written the same way.
#pragma warning disable CA1848, CA1873, CA2254

namespace EntityFrameworkCore.Jet.Internal
{
/// <summary>
Expand Down Expand Up @@ -486,4 +492,4 @@ public static void ReflexiveConstraintIgnored(
// No DiagnosticsSource events because these are purely design-time messages
}
}
}
}
2 changes: 1 addition & 1 deletion src/EFCore.Jet.Common/Internal/JetModelValidator.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Text;
using EntityFrameworkCore.Jet.Metadata;
using EntityFrameworkCore.Jet.Metadata.Internal;
using System.Text;

namespace EntityFrameworkCore.Jet.Internal
{
Expand Down
12 changes: 8 additions & 4 deletions src/EFCore.Jet.Common/Metadata/Conventions/JetIndexConvention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ public class JetIndexConvention(
IPropertyNullabilityChangedConvention,
IPropertyAnnotationChangedConvention
{
// Unread: Jet's index filter is the fixed "IGNORE NULL", so nothing here quotes an identifier. The
// constructor parameter stays because it is the signature EF Core's convention-set builder constructs.
#pragma warning disable IDE0052
private readonly ISqlGenerationHelper _sqlGenerationHelper = sqlGenerationHelper;
#pragma warning restore IDE0052

/// <summary>
/// Dependencies for this service.
Expand Down Expand Up @@ -144,7 +148,7 @@ public virtual void ProcessPropertyAnnotationChanged(
}
}

private void SetIndexFilter(IConventionIndexBuilder indexBuilder, bool columnNameChanged = false)
private static void SetIndexFilter(IConventionIndexBuilder indexBuilder, bool columnNameChanged = false)
{
var index = indexBuilder.Metadata;
if (index.IsUnique
Expand All @@ -166,11 +170,11 @@ private void SetIndexFilter(IConventionIndexBuilder indexBuilder, bool columnNam
}
}

private string CreateIndexFilter(List<string> nullableColumns)
private static string CreateIndexFilter(List<string> nullableColumns)
{
var builder = new StringBuilder();

if (nullableColumns.Any())
if (nullableColumns.Count > 0)
{
builder.Append("IGNORE NULL");
}
Expand Down Expand Up @@ -214,4 +218,4 @@ private string CreateIndexFilter(List<string> nullableColumns)

return nullableColumns;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected override DeleteBehavior GetTargetDeleteBehavior(IConventionForeignKey
return ProcessSkipNavigations(foreignKey.GetReferencingSkipNavigations()) ?? deleteBehavior;
}

private DeleteBehavior? ProcessSkipNavigations(IEnumerable<IConventionSkipNavigation> skipNavigations)
private static DeleteBehavior? ProcessSkipNavigations(IEnumerable<IConventionSkipNavigation> skipNavigations)
{
var skipNavigation = skipNavigations
.FirstOrDefault(
Expand Down Expand Up @@ -121,4 +121,4 @@ public virtual void ProcessEntityTypeAnnotationChanged(
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ public class JetSharedTableConvention(
/// <inheritdoc />
protected override bool IndexesUniqueAcrossTables
=> false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public virtual void ProcessModelFinalizing(
static bool IsStrategyNoneNeeded(IReadOnlyProperty property, StoreObjectIdentifier storeObject)
{
if (property.ValueGenerated == ValueGenerated.OnAdd
&& property.TryGetDefaultValue(storeObject, out _) == false
&& !property.TryGetDefaultValue(storeObject, out _)
&& property.GetDefaultValueSql(storeObject) == null
&& property.GetComputedColumnSql(storeObject) == null
&& property.DeclaringType.Model.GetValueGenerationStrategy() == JetValueGenerationStrategy.IdentityColumn)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public override void ProcessPropertyAnnotationChanged(
/// <param name="property">The property.</param>
/// <param name="storeObject">The identifier of the store object.</param>
/// <returns>The store value generation strategy to set for the given property.</returns>
public new static ValueGenerated? GetValueGenerated(IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
public static new ValueGenerated? GetValueGenerated(IReadOnlyProperty property, in StoreObjectIdentifier storeObject)
=> RelationalValueGenerationConvention.GetValueGenerated(property, storeObject)
?? (property.GetValueGenerationStrategy(storeObject) != JetValueGenerationStrategy.None
? ValueGenerated.OnAdd
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Globalization;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using System.Globalization;

namespace EntityFrameworkCore.Jet.Metadata.Internal
{
Expand Down Expand Up @@ -96,7 +96,7 @@ public override IEnumerable<IAnnotation> For(IColumn column, bool designTime)
else
{
if (column is JsonColumn) yield break;
property = column.PropertyMappings.First().Property;
property = column.PropertyMappings[0].Property;
if (property.DeclaringType is IEntityType entityType)
{
// Only return auto increment for integer single column primary key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ public enum JetValueGenerationStrategy
IdentityColumn,
Sequence
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public void Dispose()
{
if (!e.Message.Contains("cannot find the input table")) throw;
}

GC.SuppressFinalize(this);
}

/// <summary>
Expand All @@ -58,5 +60,7 @@ public async ValueTask DisposeAsync()
{
if (!e.Message.Contains("cannot find the input table")) throw;
}

GC.SuppressFinalize(this);
}
}
}
Loading
Loading