Skip to content
This repository was archived by the owner on Feb 1, 2025. It is now read-only.

Commit 07200ea

Browse files
authored
Merge pull request #285 from linq2db/version6
Release 6.11.0
2 parents 06955b0 + 1e56b40 commit 07200ea

30 files changed

+897
-77
lines changed

Build/linq2db.Default.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>6.10.0</Version>
3+
<Version>6.11.0</Version>
44

55
<Authors>Svyatoslav Danyliv, Igor Tkachev, Dmitry Lukashenko, Ilya Chudin</Authors>
66
<Product>Linq to DB</Product>

Directory.Packages.props

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<Project>
22
<ItemGroup>
3-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
4-
<PackageVersion Include="NUnit3TestAdapter" Version="4.2.1" />
3+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.0" />
4+
<PackageVersion Include="NUnit3TestAdapter" Version="4.3.1" />
55
<PackageVersion Include="NUnit" Version="3.13.3" />
6-
<PackageVersion Include="FluentAssertions" Version="6.6.0" />
6+
<PackageVersion Include="FluentAssertions" Version="6.8.0" />
77

8-
<PackageVersion Include="linq2db" Version="4.3.0" />
9-
<PackageVersion Include="linq2db.Tools" Version="4.3.0" />
8+
<PackageVersion Include="linq2db" Version="4.4.0" />
9+
<PackageVersion Include="linq2db.Tools" Version="4.4.0" />
1010

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

@@ -16,12 +16,12 @@
1616
<PackageVersion Include="Microsoft.Extensions.Logging" Version="6.0.0" />
1717
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
1818

19-
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
20-
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.4" />
21-
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.5" />
22-
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.5" />
19+
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.2" />
20+
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.7" />
21+
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.12" />
22+
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.12" />
2323

2424
<PackageVersion Include="EntityFrameworkCore.FSharp" Version="6.0.7" />
25-
<PackageVersion Include="FSharp.Core" Version="6.0.5" />
25+
<PackageVersion Include="FSharp.Core" Version="7.0.0" />
2626
</ItemGroup>
2727
</Project>

NuGet/linq2db.EntityFrameworkCore.nuspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<title>Linq to DB (linq2db) extensions for Entity Framework Core</title>
66
<authors>Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko</authors>
77
<owners>Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko</owners>
8-
<copyright>Copyright © 2020-2021 Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko</copyright>
8+
<copyright>Copyright © 2020-2022 Igor Tkachev, Ilya Chudin, Svyatoslav Danyliv, Dmitry Lukashenko</copyright>
99
<description>Allows to execute Linq to DB (linq2db) queries in Entity Framework Core DbContext.</description>
1010
<summary />
1111
<tags>linq linq2db LinqToDB ORM database entity-framework-core EntityFrameworkCore EFCore DB SQL SqlServer SqlCe SqlServerCe MySql Firebird SQLite Oracle ODP PostgreSQL DB2</tags>
@@ -16,7 +16,7 @@
1616
<dependencies>
1717
<group targetFramework="net6.0">
1818
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="6.0.5" />
19-
<dependency id="linq2db" version="4.3.0" />
19+
<dependency id="linq2db" version="4.4.0" />
2020
</group>
2121
</dependencies>
2222
</metadata>

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ LinqToDBForEFTools.Initialize();
3939

4040
After that you can just call DbContext and IQueryable extension methods, provided by `LINQ To DB`.
4141

42+
You can also register additional options (like interceptors) for LinqToDB during EF context registration, here is an example:
43+
44+
```cs
45+
var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
46+
optionsBuilder.UseSqlite();
47+
optionsBuilder.UseLinqToDb(builder =>
48+
{
49+
builder.AddInterceptor(new MyCommandInterceptor());
50+
});
51+
```
52+
4253
There are many extensions for CRUD Operations missing in vanilla EF ([watch our video](https://www.youtube.com/watch?v=m--oX73EGeQ)):
4354

4455
```cs

Source/LinqToDB.EntityFrameworkCore/EFCoreMetadataReader.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace LinqToDB.EntityFrameworkCore
3030
/// <summary>
3131
/// LINQ To DB metadata reader for EF.Core model.
3232
/// </summary>
33-
internal class EFCoreMetadataReader : IMetadataReader
33+
internal sealed class EFCoreMetadataReader : IMetadataReader
3434
{
3535
readonly IModel? _model;
3636
private readonly RelationalSqlTranslatingExpressionVisitorDependencies? _dependencies;
@@ -241,7 +241,7 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
241241
{
242242
if (a.Value is string str)
243243
{
244-
return str.ToLower().Contains("nextval");
244+
return str.ToLowerInvariant().Contains("nextval");
245245
}
246246
}
247247

@@ -258,7 +258,8 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
258258
}
259259
else
260260
{
261-
dataType = SqlDataType.GetDataType(typeMapping.ClrType).Type.DataType;
261+
var ms = _model != null ? LinqToDBForEFTools.GetMappingSchema(_model, null) : MappingSchema.Default;
262+
dataType = ms.GetDataType(typeMapping.ClrType).Type.DataType;
262263
}
263264
}
264265

@@ -407,7 +408,7 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
407408
return Array.Empty<T>();
408409
}
409410

410-
class ValueConverter : IValueConverter
411+
sealed class ValueConverter : IValueConverter
411412
{
412413
public ValueConverter(
413414
LambdaExpression convertToProviderExpression,
@@ -424,7 +425,7 @@ public ValueConverter(
424425

425426
}
426427

427-
class SqlTransparentExpression : SqlExpression
428+
sealed class SqlTransparentExpression : SqlExpression
428429
{
429430
public Expression Expression { get; }
430431

@@ -438,7 +439,7 @@ protected override void Print(ExpressionPrinter expressionPrinter)
438439
expressionPrinter.Print(Expression);
439440
}
440441

441-
protected bool Equals(SqlTransparentExpression other)
442+
private bool Equals(SqlTransparentExpression other)
442443
{
443444
return ReferenceEquals(this, other);
444445
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
4+
using Microsoft.EntityFrameworkCore.Infrastructure;
5+
using Microsoft.Extensions.DependencyInjection;
6+
7+
namespace LinqToDB.EntityFrameworkCore.Internal
8+
{
9+
using Interceptors;
10+
11+
/// <summary>
12+
/// Model containing LinqToDB related context options
13+
/// </summary>
14+
public class LinqToDBOptionsExtension : IDbContextOptionsExtension
15+
{
16+
private DbContextOptionsExtensionInfo? _info;
17+
private IList<IInterceptor>? _interceptors;
18+
19+
/// <summary>
20+
/// Context options extension info object
21+
/// </summary>
22+
public DbContextOptionsExtensionInfo Info
23+
=> _info ??= new LinqToDBExtensionInfo(this);
24+
25+
/// <summary>
26+
/// List of registered LinqToDB interceptors
27+
/// </summary>
28+
public virtual IList<IInterceptor> Interceptors
29+
=> _interceptors ??= new List<IInterceptor>();
30+
31+
/// <summary>
32+
/// .ctor
33+
/// </summary>
34+
public LinqToDBOptionsExtension()
35+
{
36+
}
37+
38+
/// <summary>
39+
/// .ctor
40+
/// </summary>
41+
/// <param name="copyFrom"></param>
42+
protected LinqToDBOptionsExtension(LinqToDBOptionsExtension copyFrom)
43+
{
44+
_interceptors = copyFrom._interceptors;
45+
}
46+
47+
/// Adds the services required to make the selected options work. This is used when
48+
/// there is no external System.IServiceProvider and EF is maintaining its own service
49+
/// provider internally. This allows database providers (and other extensions) to
50+
/// register their required services when EF is creating an service provider.
51+
/// <param name="services">The collection to add services to</param>
52+
public void ApplyServices(IServiceCollection services)
53+
{
54+
;
55+
}
56+
57+
/// <summary>
58+
/// Gives the extension a chance to validate that all options in the extension are
59+
/// valid. Most extensions do not have invalid combinations and so this will be a
60+
/// no-op. If options are invalid, then an exception should be thrown.
61+
/// </summary>
62+
/// <param name="options"></param>
63+
public void Validate(IDbContextOptions options)
64+
{
65+
;
66+
}
67+
68+
private sealed class LinqToDBExtensionInfo : DbContextOptionsExtensionInfo
69+
{
70+
private string? _logFragment;
71+
72+
public LinqToDBExtensionInfo(IDbContextOptionsExtension extension)
73+
: base(extension)
74+
{
75+
}
76+
77+
private new LinqToDBOptionsExtension Extension
78+
=> (LinqToDBOptionsExtension)base.Extension;
79+
80+
public override bool IsDatabaseProvider
81+
=> false;
82+
83+
public override string LogFragment
84+
{
85+
get
86+
{
87+
if (_logFragment == null)
88+
{
89+
string logFragment = string.Empty;
90+
91+
if (Extension.Interceptors.Any())
92+
{
93+
logFragment += $"Interceptors count: {Extension.Interceptors.Count}";
94+
}
95+
96+
_logFragment = logFragment;
97+
}
98+
99+
return _logFragment;
100+
}
101+
}
102+
103+
public override int GetServiceProviderHashCode() => 0;
104+
105+
public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
106+
=> debugInfo["Linq2Db"] = "1";
107+
108+
public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other) => true;
109+
}
110+
}
111+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using Microsoft.EntityFrameworkCore;
2+
3+
namespace LinqToDB.EntityFrameworkCore
4+
{
5+
using Internal;
6+
using Interceptors;
7+
8+
/// <summary>
9+
/// LinqToDB context options builder
10+
/// </summary>
11+
public class LinqToDBContextOptionsBuilder
12+
{
13+
private readonly LinqToDBOptionsExtension? _extension;
14+
15+
/// <summary>
16+
/// Db context options
17+
/// </summary>
18+
public DbContextOptions DbContextOptions { get; private set; }
19+
20+
/// <summary>
21+
/// .ctor
22+
/// </summary>
23+
/// <param name="optionsBuilder"></param>
24+
public LinqToDBContextOptionsBuilder(DbContextOptionsBuilder optionsBuilder)
25+
{
26+
_extension = optionsBuilder.Options.FindExtension<LinqToDBOptionsExtension>();
27+
DbContextOptions = optionsBuilder.Options;
28+
}
29+
30+
/// <summary>
31+
/// Registers LinqToDb interceptor
32+
/// </summary>
33+
/// <param name="interceptor">The interceptor instance to register</param>
34+
/// <returns></returns>
35+
public LinqToDBContextOptionsBuilder AddInterceptor(IInterceptor interceptor)
36+
{
37+
_extension?.Interceptors.Add(interceptor);
38+
return this;
39+
}
40+
}
41+
}

Source/LinqToDB.EntityFrameworkCore/LinqToDBForEFTools.ContextExtensions.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
using System.Threading;
44
using System.Threading.Tasks;
55
using Microsoft.EntityFrameworkCore;
6+
using Microsoft.EntityFrameworkCore.Infrastructure;
67

78
using JetBrains.Annotations;
89

910
namespace LinqToDB.EntityFrameworkCore
1011
{
1112
using Data;
1213
using Linq;
14+
using Internal;
15+
using Interceptors;
1316

1417
public static partial class LinqToDBForEFTools
1518
{
@@ -257,7 +260,44 @@ public static ITable<T> GetTable<T>(this DbContext context)
257260

258261
return context.CreateLinqToDbContext().GetTable<T>();
259262
}
260-
263+
264+
#endregion
265+
266+
#region Interceptors
267+
268+
/// <summary>
269+
/// Returns list of registered Linq2Db interceptors from EF Context
270+
/// </summary>
271+
/// <returns>Db context object</returns>
272+
public static IList<IInterceptor>? GetLinq2DbInterceptors(this DbContext context)
273+
274+
{
275+
if (context == null) throw new ArgumentNullException(nameof(context));
276+
277+
var contextOptions = ((IInfrastructure<IServiceProvider>)context.Database)?
278+
.Instance?.GetService(typeof(IDbContextOptions)) as IDbContextOptions;
279+
280+
return contextOptions?.GetLinq2DbInterceptors();
281+
}
282+
283+
/// <summary>
284+
/// Returns list of registered Linq2Db interceptors from EF Context options
285+
/// </summary>
286+
/// <returns>Db context options</returns>
287+
public static IList<IInterceptor> GetLinq2DbInterceptors(this IDbContextOptions contextOptions)
288+
{
289+
if (contextOptions == null) throw new ArgumentNullException(nameof(contextOptions));
290+
291+
var linq2DbExtension = contextOptions?.FindExtension<LinqToDBOptionsExtension>();
292+
List<IInterceptor> interceptors = new List<IInterceptor>();
293+
if (linq2DbExtension?.Interceptors != null)
294+
{
295+
interceptors.AddRange(linq2DbExtension.Interceptors);
296+
}
297+
298+
return interceptors;
299+
}
300+
261301
#endregion
262302
}
263303
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore.Infrastructure;
4+
5+
namespace LinqToDB.EntityFrameworkCore
6+
{
7+
using Internal;
8+
9+
public static partial class LinqToDBForEFTools
10+
{
11+
/// <summary>
12+
/// Registers custom options related to LinqToDB provider
13+
/// </summary>
14+
/// <param name="optionsBuilder"></param>
15+
/// <param name="linq2DbOptionsAction">Custom options action</param>
16+
/// <returns></returns>
17+
public static DbContextOptionsBuilder UseLinqToDb(
18+
this DbContextOptionsBuilder optionsBuilder,
19+
Action<LinqToDBContextOptionsBuilder>? linq2DbOptionsAction = null)
20+
{
21+
((IDbContextOptionsBuilderInfrastructure)optionsBuilder)
22+
.AddOrUpdateExtension(GetOrCreateExtension(optionsBuilder));
23+
24+
linq2DbOptionsAction?.Invoke(new LinqToDBContextOptionsBuilder(optionsBuilder));
25+
26+
return optionsBuilder;
27+
}
28+
29+
private static LinqToDBOptionsExtension GetOrCreateExtension(DbContextOptionsBuilder options)
30+
=> options.Options.FindExtension<LinqToDBOptionsExtension>()
31+
?? new LinqToDBOptionsExtension();
32+
}
33+
}

0 commit comments

Comments
 (0)