Skip to content

Commit

Permalink
ef.core 7 support (#263)
Browse files Browse the repository at this point in the history
* efcore 7 support

* fix connection strings

* suppress dependency errors

* disable C# 11 features temporary

* there will be no API-breaking changes in this area within major version
  • Loading branch information
MaceWindu authored Nov 12, 2022
1 parent 2ff7369 commit d1fd30f
Show file tree
Hide file tree
Showing 83 changed files with 784 additions and 890 deletions.
44 changes: 3 additions & 41 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,46 +1,8 @@
#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.obj
*.pdb
#Ignore files build by IDE
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk
*.log
*.cs.ide
[Bb]in
[Dd]ebug*/
*.lib
*.sbr
bin/
obj/
[Rr]elease*/
_ReSharper*/
[Tt]est[Rr]esult*
linq2db.sln.docstates
Tests/**/UserDataProviders*.*
NuGet/*.nupkg
!*.dll
!*.exe
!*.pdb
linq2db.sln.ide/graph
linq2db.sln.ide/
!Redist/**
/packages
/.vs/*
*.lock.json
/api
/linq2db.github.io
#cake
/tools
/.tools
/.tools/
/.idea/
5 changes: 4 additions & 1 deletion Build/linq2db.Default.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>5.13.0</Version>
<Version>7.0.0</Version>

<Authors>Svyatoslav Danyliv, Igor Tkachev, Dmitry Lukashenko, Ilya Chudin</Authors>
<Product>Linq to DB</Product>
Expand All @@ -27,8 +27,11 @@
<GenerateAssemblyVersionAttribute>true</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>true</GenerateAssemblyFileVersionAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>

<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>

<TargetFrameworks>net6.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
Expand Down
4 changes: 2 additions & 2 deletions Build/linq2db.Tests.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<Import Project="linq2db.Default.props" />

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFrameworks>net7.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NUnit3TestAdapter">
Expand Down
26 changes: 13 additions & 13 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
<Project>
<ItemGroup>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.3.0" />
<PackageVersion Include="NUnit" Version="3.13.3" />
<PackageVersion Include="FluentAssertions" Version="6.6.0" />
<PackageVersion Include="FluentAssertions" Version="6.8.0" />

<PackageVersion Include="linq2db" Version="4.3.0" />
<PackageVersion Include="linq2db.Tools" Version="4.3.0" />

<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />

<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.17" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.17" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />

<PackageVersion Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />

<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.4" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.17" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.17" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.2" />
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />

<PackageVersion Include="EntityFrameworkCore.FSharp" Version="5.0.3" />
<PackageVersion Include="FSharp.Core" Version="6.0.5" />
<PackageVersion Include="EntityFrameworkCore.FSharp" Version="6.0.7" />
<PackageVersion Include="FSharp.Core" Version="7.0.0" />
</ItemGroup>
</Project>
6 changes: 3 additions & 3 deletions NuGet/linq2db.EntityFrameworkCore.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<title>Linq to DB (linq2db) extensions for Entity Framework Core</title>
<authors>Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko</authors>
<owners>Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko</owners>
<copyright>Copyright © 2020-2021 Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko</copyright>
<copyright>Copyright © 2020-2022 Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko</copyright>
<description>Allows to execute Linq to DB (linq2db) queries in Entity Framework Core DbContext.</description>
<summary />
<tags>linq linq2db LinqToDB ORM database entity-framework-core EntityFrameworkCore EFCore DB SQL SqlServer SqlCe SqlServerCe MySql Firebird SQLite Oracle ODP PostgreSQL DB2</tags>
Expand All @@ -14,8 +14,8 @@
<projectUrl>https://github.com/linq2db/linq2db.EntityFrameworkCore</projectUrl>
<license type="file">MIT-LICENSE.txt</license>
<dependencies>
<group targetFramework=".NETStandard2.1">
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="5.0.17" />
<group targetFramework="net6.0">
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="7.0.0" />
<dependency id="linq2db" version="4.3.0" />
</group>
</dependencies>
Expand Down
2 changes: 1 addition & 1 deletion Source/LinqToDB.EntityFrameworkCore/EFConnectionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace LinqToDB.EntityFrameworkCore
/// <summary>
/// Contains database connectivity information, extracted from EF.Core.
/// </summary>
public class EFConnectionInfo
public sealed class EFConnectionInfo
{
/// <summary>
/// Gets or sets database connection instance.
Expand Down
40 changes: 20 additions & 20 deletions Source/LinqToDB.EntityFrameworkCore/EFCoreMetadataReader.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
Expand Down Expand Up @@ -31,7 +30,7 @@ namespace LinqToDB.EntityFrameworkCore
/// <summary>
/// LINQ To DB metadata reader for EF.Core model.
/// </summary>
internal class EFCoreMetadataReader : IMetadataReader
internal sealed class EFCoreMetadataReader : IMetadataReader
{
readonly IModel? _model;
private readonly RelationalSqlTranslatingExpressionVisitorDependencies? _dependencies;
Expand All @@ -40,8 +39,7 @@ internal class EFCoreMetadataReader : IMetadataReader
private readonly ConcurrentDictionary<MemberInfo, EFCoreExpressionAttribute?> _calculatedExtensions = new();
private readonly IDiagnosticsLogger<DbLoggerCategory.Query>? _logger;

public EFCoreMetadataReader(
IModel? model, IInfrastructure<IServiceProvider>? accessor)
public EFCoreMetadataReader(IModel? model, IInfrastructure<IServiceProvider>? accessor)
{
_model = model;
if (accessor != null)
Expand All @@ -61,7 +59,7 @@ public T[] GetAttributes<T>(Type type, bool inherit = true) where T : Attribute
if (typeof(T) == typeof(TableAttribute))
{
var storeObjectId = GetStoreObjectIdentifier(et);
return new[] { (T)(Attribute)new TableAttribute(storeObjectId!.Value.Name) { Schema = storeObjectId!.Value.Schema } };
return new[] { (T)(Attribute)new TableAttribute() { Schema = storeObjectId?.Schema, Name = storeObjectId?.Name } };
}
if (typeof(T) == typeof(QueryFilterAttribute))
{
Expand Down Expand Up @@ -208,7 +206,7 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru

if (prop != null)
{
var discriminator = et.GetDiscriminatorProperty();
var discriminator = et.FindDiscriminatorProperty();

var isPrimaryKey = prop.IsPrimaryKey();
var primaryKeyOrder = 0;
Expand All @@ -225,14 +223,14 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
if (_annotationProvider != null && storeObjectId != null)
{
if (prop.FindColumn(storeObjectId.Value) is IColumn column)
annotations = annotations.Concat(_annotationProvider.For(column));
annotations = annotations.Concat(_annotationProvider.For(column, false));
}

var isIdentity = annotations
.Any(a =>
{
if (a.Name.EndsWith(":ValueGenerationStrategy"))
return a.Value?.ToString()!.Contains("Identity") == true;
return a.Value?.ToString()?.Contains("Identity") == true;

if (a.Name.EndsWith(":Autoincrement"))
return a.Value is bool b && b;
Expand All @@ -242,7 +240,7 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
{
if (a.Value is string str)
{
return str.ToLower().Contains("nextval");
return str.ToLowerInvariant().Contains("nextval");
}
}

Expand All @@ -259,7 +257,8 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
}
else
{
dataType = SqlDataType.GetDataType(typeMapping.ClrType).Type.DataType;
var ms = _model != null ? LinqToDBForEFTools.GetMappingSchema(_model, null) : MappingSchema.Default;
dataType = ms.GetDataType(typeMapping.ClrType).Type.DataType;
}
}

Expand All @@ -278,7 +277,7 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
{
(T)(Attribute)new ColumnAttribute
{
Name = prop.GetColumnName(storeObjectId!.Value),
Name = storeObjectId != null ? prop.GetColumnName(storeObjectId.Value) : null,
Length = prop.GetMaxLength() ?? 0,
CanBeNull = prop.IsNullable,
DbType = prop.GetColumnType(),
Expand Down Expand Up @@ -408,7 +407,7 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
return Array.Empty<T>();
}

class ValueConverter : IValueConverter
sealed class ValueConverter : IValueConverter
{
public ValueConverter(
LambdaExpression convertToProviderExpression,
Expand All @@ -425,7 +424,7 @@ public ValueConverter(

}

class SqlTransparentExpression : SqlExpression
sealed class SqlTransparentExpression : SqlExpression
{
public Expression Expression { get; }

Expand All @@ -439,7 +438,7 @@ protected override void Print(ExpressionPrinter expressionPrinter)
expressionPrinter.Print(Expression);
}

protected bool Equals(SqlTransparentExpression other)
private bool Equals(SqlTransparentExpression other)
{
return ReferenceEquals(this, other);
}
Expand Down Expand Up @@ -596,23 +595,24 @@ string PrepareExpressionText(Expression? expr)
return text;
}

// https://github.com/npgsql/efcore.pg/blob/main/src/EFCore.PG/Query/Expressions/Internal/PostgresBinaryExpression.cs
if (newExpression.GetType().Name == "PostgresBinaryExpression")
{
// Handling NpgSql's PostgresBinaryExpression

var left = newExpression.GetType().GetProperty("Left")?.GetValue(newExpression) as Expression;
var right = newExpression.GetType().GetProperty("Right")?.GetValue(newExpression) as Expression;
var left = (Expression)newExpression.GetType().GetProperty("Left")!.GetValue(newExpression)!;
var right = (Expression)newExpression.GetType().GetProperty("Right")!.GetValue(newExpression)!;

var operand = newExpression.GetType().GetProperty("OperatorType")?.GetValue(newExpression)!.ToString();
var operand = newExpression.GetType().GetProperty("OperatorType")!.GetValue(newExpression)!.ToString()!;

var operandExpr = operand switch
{
"Contains"
when left!.Type.Name == "NpgsqlInetTypeMapping" ||
when left.Type.Name == "NpgsqlInetTypeMapping" ||
left.Type.Name == "NpgsqlCidrTypeMapping"
=> ">>",
"ContainedBy"
when left!.Type.Name == "NpgsqlInetTypeMapping" ||
when left.Type.Name == "NpgsqlInetTypeMapping" ||
left.Type.Name == "NpgsqlCidrTypeMapping"
=> "<<",
"Contains" => "@>",
Expand Down Expand Up @@ -674,7 +674,7 @@ private static Expression UnwrapConverted(Expression expr)
if (expr is SqlFunctionExpression func)
{
if (string.Equals(func.Name, "COALESCE", StringComparison.InvariantCultureIgnoreCase) &&
func.Arguments!.Count == 2 && func.Arguments[1].NodeType == ExpressionType.Extension)
func.Arguments?.Count == 2 && func.Arguments[1].NodeType == ExpressionType.Extension)
return UnwrapConverted(func.Arguments[0]);
}

Expand Down
2 changes: 1 addition & 1 deletion Source/LinqToDB.EntityFrameworkCore/EFProviderInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace LinqToDB.EntityFrameworkCore
/// <summary>
/// Required integration information about underlying database provider, extracted from EF.Core.
/// </summary>
public class EFProviderInfo
public sealed class EFProviderInfo
{
/// <summary>
/// Gets or sets database connection instance.
Expand Down
1 change: 0 additions & 1 deletion Source/LinqToDB.EntityFrameworkCore/ILinqToDBForEFTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,5 @@ public interface ILinqToDBForEFTools
/// Entities will be attached only if AsNoTracking() is not used in query and DbContext is configured to track entities.
/// </summary>
bool EnableChangeTracker { get; set; }

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ TResult IAsyncQueryProvider.ExecuteAsync<TResult>(Expression expression, Cancell
{
var item = typeof(TResult).GetGenericArguments()[0];
var method = _executeAsyncMethodInfo.MakeGenericMethod(item);
return (TResult) method.Invoke(QueryProvider, new object[] { expression, cancellationToken })!;
return (TResult)method.Invoke(QueryProvider, new object[] { expression, cancellationToken })!;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace LinqToDB.EntityFrameworkCore
/// <summary>
/// LINQ To DB async extensions adapter to call EF.Core functionality instead of default implementation.
/// </summary>
public class LinqToDBExtensionsAdapter : IExtensionsAdapter
public sealed class LinqToDBExtensionsAdapter : IExtensionsAdapter
{
/// <inheritdoc cref="EntityFrameworkQueryableExtensions.AsAsyncEnumerable{TSource}(IQueryable{TSource})"/>
public IAsyncEnumerable<TSource> AsAsyncEnumerable<TSource>(IQueryable<TSource> source)
Expand Down Expand Up @@ -90,18 +90,14 @@ public Task<TSource> FirstAsync<TSource>(
public Task<TSource?> FirstOrDefaultAsync<TSource>(
IQueryable<TSource> source,
CancellationToken token)
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
=> EntityFrameworkQueryableExtensions.FirstOrDefaultAsync(source, token);
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.

/// <inheritdoc cref="EntityFrameworkQueryableExtensions.FirstOrDefaultAsync{TSource}(IQueryable{TSource}, Expression{Func{TSource, bool}}, CancellationToken)"/>
public Task<TSource?> FirstOrDefaultAsync<TSource>(
IQueryable<TSource> source,
Expression<Func<TSource,bool>> predicate,
CancellationToken token)
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
=> EntityFrameworkQueryableExtensions.FirstOrDefaultAsync(source, predicate, token);
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.

/// <inheritdoc cref="EntityFrameworkQueryableExtensions.SingleAsync{TSource}(IQueryable{TSource}, CancellationToken)"/>
public Task<TSource> SingleAsync<TSource>(
Expand All @@ -120,18 +116,14 @@ public Task<TSource> SingleAsync<TSource>(
public Task<TSource?> SingleOrDefaultAsync<TSource>(
IQueryable<TSource> source,
CancellationToken token)
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
=> EntityFrameworkQueryableExtensions.SingleOrDefaultAsync(source, token);
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.

/// <inheritdoc cref="EntityFrameworkQueryableExtensions.SingleOrDefaultAsync{TSource}(IQueryable{TSource}, Expression{Func{TSource, bool}}, CancellationToken)"/>
public Task<TSource?> SingleOrDefaultAsync<TSource>(
IQueryable<TSource> source,
Expression<Func<TSource,bool>> predicate,
CancellationToken token)
#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type.
=> EntityFrameworkQueryableExtensions.SingleOrDefaultAsync(source, predicate, token);
#pragma warning restore CS8619 // Nullability of reference types in value doesn't match target type.

/// <inheritdoc cref="EntityFrameworkQueryableExtensions.ContainsAsync{TSource}(IQueryable{TSource}, TSource, CancellationToken)"/>
public Task<bool> ContainsAsync<TSource>(
Expand Down
Loading

0 comments on commit d1fd30f

Please sign in to comment.