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

Commit 4565918

Browse files
authored
Merge pull request #177 from linq2db/master
Release 5.6.0
2 parents f9f0d3a + 109e613 commit 4565918

File tree

11 files changed

+225
-29
lines changed

11 files changed

+225
-29
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>5.5.0</Version>
3+
<Version>5.6.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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<PackageVersion Include="NUnit" Version="3.13.2" />
66
<PackageVersion Include="FluentAssertions" Version="5.10.3" />
77

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

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

NuGet/linq2db.EntityFrameworkCore.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<dependencies>
1717
<group targetFramework=".NETStandard2.1">
1818
<dependency id="Microsoft.EntityFrameworkCore.Relational" version="5.0.2" />
19-
<dependency id="linq2db" version="3.4.3" />
19+
<dependency id="linq2db" version="3.4.4" />
2020
</group>
2121
</dependencies>
2222
</metadata>

Source/LinqToDB.EntityFrameworkCore/EFCoreMetadataReader.cs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,24 @@ public T[] GetAttributes<T>(Type type, bool inherit = true) where T : Attribute
112112
if (tableAttribute != null)
113113
return new[] { (T)(Attribute)new TableAttribute(tableAttribute.Name) { Schema = tableAttribute.Schema } };
114114
}
115+
else if (_model != null && typeof(T) == typeof(InheritanceMappingAttribute))
116+
{
117+
if (et != null)
118+
{
119+
var derivedEntities = _model.GetEntityTypes().Where(e => e.BaseType == et && e.GetDiscriminatorValue() != null).ToList();
120+
121+
return
122+
derivedEntities.Select(e =>
123+
(T)(Attribute)new InheritanceMappingAttribute
124+
{
125+
Type = e.ClrType,
126+
Code = e.GetDiscriminatorValue()
127+
}
128+
)
129+
.ToArray();
130+
}
131+
132+
}
115133

116134
return Array.Empty<T>();
117135
}
@@ -190,11 +208,13 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
190208

191209
if (prop != null)
192210
{
211+
var discriminator = et.GetDiscriminatorProperty();
212+
193213
var isPrimaryKey = prop.IsPrimaryKey();
194214
var primaryKeyOrder = 0;
195215
if (isPrimaryKey)
196216
{
197-
var pk = prop.FindContainingPrimaryKey();
217+
var pk = prop.FindContainingPrimaryKey()!;
198218
primaryKeyOrder = pk.Properties.Select((p, i) => new { p, index = i })
199219
.FirstOrDefault(v => CompareProperty(v.p, memberInfo))?.index ?? 0;
200220
}
@@ -204,16 +224,15 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
204224
var annotations = prop.GetAnnotations();
205225
if (_annotationProvider != null && storeObjectId != null)
206226
{
207-
var column = prop.FindColumn(storeObjectId.Value) as IColumn;
208-
if (column != null)
227+
if (prop.FindColumn(storeObjectId.Value) is IColumn column)
209228
annotations = annotations.Concat(_annotationProvider.For(column));
210229
}
211230

212231
var isIdentity = annotations
213232
.Any(a =>
214233
{
215234
if (a.Name.EndsWith(":ValueGenerationStrategy"))
216-
return a.Value?.ToString().Contains("Identity") == true;
235+
return a.Value?.ToString()!.Contains("Identity") == true;
217236

218237
if (a.Name.EndsWith(":Autoincrement"))
219238
return a.Value is bool b && b;
@@ -256,6 +275,7 @@ public T[] GetAttributes<T>(Type type, MemberInfo memberInfo, bool inherit = tru
256275
IsPrimaryKey = isPrimaryKey,
257276
PrimaryKeyOrder = primaryKeyOrder,
258277
IsIdentity = isIdentity,
278+
IsDiscriminator = discriminator == prop
259279
}
260280
};
261281
}
@@ -413,7 +433,7 @@ protected bool Equals(SqlTransparentExpression other)
413433
return ReferenceEquals(this, other);
414434
}
415435

416-
public override bool Equals(object obj)
436+
public override bool Equals(object? obj)
417437
{
418438
if (obj is null) return false;
419439
if (ReferenceEquals(this, obj)) return true;
@@ -459,7 +479,7 @@ public override int GetHashCode()
459479
Expression.Constant(DefaultValue.GetValue(p.ParameterType), p.ParameterType),
460480
_mappingSource?.FindMapping(p.ParameterType))).ToArray();
461481

462-
var newExpression = _dependencies.MethodCallTranslatorProvider.Translate(_model, objExpr, methodInfo, parametersArray, _logger);
482+
var newExpression = _dependencies.MethodCallTranslatorProvider.Translate(_model, objExpr, methodInfo, parametersArray, _logger!);
463483
if (newExpression != null)
464484
{
465485
if (!methodInfo.IsStatic)
@@ -492,7 +512,7 @@ public override int GetHashCode()
492512
{
493513
var objExpr = new SqlTransparentExpression(Expression.Constant(DefaultValue.GetValue(type), type), _mappingSource?.FindMapping(propInfo));
494514

495-
var newExpression = _dependencies.MemberTranslatorProvider.Translate(objExpr, propInfo, propInfo.GetMemberType(), _logger);
515+
var newExpression = _dependencies.MemberTranslatorProvider.Translate(objExpr, propInfo, propInfo.GetMemberType(), _logger!);
496516
if (newExpression != null)
497517
{
498518
var parametersArray = new Expression[] { objExpr };
@@ -572,7 +592,7 @@ string PrepareExpressionText(Expression? expr)
572592
var left = newExpression.GetType().GetProperty("Left")?.GetValue(newExpression) as Expression;
573593
var right = newExpression.GetType().GetProperty("Right")?.GetValue(newExpression) as Expression;
574594

575-
var operand = newExpression.GetType().GetProperty("OperatorType")?.GetValue(newExpression).ToString();
595+
var operand = newExpression.GetType().GetProperty("OperatorType")?.GetValue(newExpression)!.ToString();
576596

577597
var operandExpr = operand switch
578598
{
@@ -643,7 +663,7 @@ private static Expression UnwrapConverted(Expression expr)
643663
if (expr is SqlFunctionExpression func)
644664
{
645665
if (string.Equals(func.Name, "COALESCE", StringComparison.InvariantCultureIgnoreCase) &&
646-
func.Arguments.Count == 2 && func.Arguments[1].NodeType == ExpressionType.Extension)
666+
func.Arguments!.Count == 2 && func.Arguments[1].NodeType == ExpressionType.Extension)
647667
return UnwrapConverted(func.Arguments[0]);
648668
}
649669

Source/LinqToDB.EntityFrameworkCore/Internal/EFCoreExpressionAttribute.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ public override ISqlExpression GetExpression(
3232
{
3333
var mc = (MethodCallExpression) expression;
3434
if (!mc.Method.IsStatic)
35-
knownExpressions.Add(mc.Object);
35+
knownExpressions.Add(mc.Object!);
3636
knownExpressions.AddRange(mc.Arguments);
3737
}
3838
else
3939
{
4040
var me = (MemberExpression) expression;
41-
knownExpressions.Add(me.Expression);
41+
knownExpressions.Add(me.Expression!);
4242
}
4343

4444
var pams = new List<ISqlExpression?>(knownExpressions.Select(_ => (ISqlExpression?) null));

Source/LinqToDB.EntityFrameworkCore/Internal/LinqToDBForEFQueryProvider.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
6565
/// </summary>
6666
/// <param name="expression">Query expression.</param>
6767
/// <returns>Query result.</returns>
68-
public object Execute(Expression expression)
68+
public object? Execute(Expression expression)
6969
{
7070
return QueryProvider.Execute(expression);
7171
}
@@ -107,7 +107,7 @@ TResult IAsyncQueryProvider.ExecuteAsync<TResult>(Expression expression, Cancell
107107
{
108108
var item = typeof(TResult).GetGenericArguments()[0];
109109
var method = _executeAsyncMethodInfo.MakeGenericMethod(item);
110-
return (TResult) method.Invoke(QueryProvider, new object[] { expression, cancellationToken });
110+
return (TResult) method.Invoke(QueryProvider, new object[] { expression, cancellationToken })!;
111111
}
112112

113113
/// <summary>
@@ -158,14 +158,15 @@ IEnumerator IEnumerable.GetEnumerator()
158158
/// <returns>Query result as <see cref="IAsyncEnumerable{T}"/>.</returns>
159159
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
160160
{
161-
return QueryProvider.ExecuteAsyncEnumerable<T>(Expression, cancellationToken).Result.GetAsyncEnumerator(cancellationToken);
161+
return Task.Run(() => QueryProvider.ExecuteAsyncEnumerable<T>(Expression, cancellationToken),
162+
cancellationToken).Result.GetAsyncEnumerator(cancellationToken);
162163
}
163164

164165
/// <summary>
165166
/// Returns generated SQL for specific LINQ query.
166167
/// </summary>
167168
/// <returns>Generated SQL.</returns>
168-
public override string ToString()
169+
public override string? ToString()
169170
{
170171
return QueryProvider.ToString();
171172
}

Source/LinqToDB.EntityFrameworkCore/LinqToDBForEFExtensions.Async.EF.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public static Task<Dictionary<TKey, TSource>> ToDictionaryAsyncEF<TSource, TKey>
3939
this IQueryable<TSource> source,
4040
Func<TSource, TKey> keySelector,
4141
CancellationToken cancellationToken = default)
42+
where TKey: notnull
4243
=> EntityFrameworkQueryableExtensions.ToDictionaryAsync(source, keySelector, cancellationToken);
4344

4445
/// <inheritdoc cref="EntityFrameworkQueryableExtensions.ToDictionaryAsync{TSource, TKey, TElement}(IQueryable{TSource}, Func{TSource, TKey}, Func{TSource, TElement}, CancellationToken)"/>
@@ -47,6 +48,7 @@ public static Task<Dictionary<TKey,TElement>> ToDictionaryAsyncEF<TSource,TKey,T
4748
Func<TSource,TKey> keySelector,
4849
Func<TSource,TElement> elementSelector,
4950
CancellationToken cancellationToken = default)
51+
where TKey : notnull
5052
=> EntityFrameworkQueryableExtensions.ToDictionaryAsync(source, keySelector, elementSelector, cancellationToken);
5153

5254
/// <inheritdoc cref="EntityFrameworkQueryableExtensions.ToDictionaryAsync{TSource, TKey, TElement}(IQueryable{TSource}, Func{TSource, TKey}, Func{TSource, TElement}, IEqualityComparer{TKey}, CancellationToken)"/>
@@ -56,6 +58,7 @@ public static Task<Dictionary<TKey,TElement>> ToDictionaryAsyncEF<TSource,TKey,T
5658
Func<TSource,TElement> elementSelector,
5759
IEqualityComparer<TKey> comparer,
5860
CancellationToken cancellationToken = default)
61+
where TKey : notnull
5962
=> EntityFrameworkQueryableExtensions.ToDictionaryAsync(source, keySelector, elementSelector, comparer, cancellationToken);
6063

6164
/// <inheritdoc cref="EntityFrameworkQueryableExtensions.FirstAsync{TSource}(IQueryable{TSource}, CancellationToken)"/>

Tests/LinqToDB.EntityFrameworkCore.BaseTests/ForMappingTestsBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public virtual void TestIdentityMapping()
2020
using var connection = context.CreateLinqToDbConnection();
2121

2222
var ed = connection.MappingSchema.GetEntityDescriptor(typeof(WithIdentity));
23-
var pk = ed.Columns.Where(c => c.IsPrimaryKey).Single();
23+
var pk = ed.Columns.Single(c => c.IsPrimaryKey);
2424

2525
pk.IsIdentity.Should().BeTrue();
2626
}
@@ -32,7 +32,7 @@ public virtual void TestNoIdentityMapping()
3232
using var connection = context.CreateLinqToDbConnection();
3333

3434
var ed = connection.MappingSchema.GetEntityDescriptor(typeof(NoIdentity));
35-
var pk = ed.Columns.Where(c => c.IsPrimaryKey).Single();
35+
var pk = ed.Columns.Single(c => c.IsPrimaryKey);
3636

3737
pk.IsIdentity.Should().BeFalse();
3838
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
using Microsoft.EntityFrameworkCore;
2+
3+
namespace LinqToDB.EntityFrameworkCore.SqlServer.Tests.Models.Inheritance
4+
{
5+
public abstract class BlogBase
6+
{
7+
public int Id { get; set; }
8+
public string BlogType { get; set; } = null!;
9+
}
10+
11+
public class Blog : BlogBase
12+
{
13+
public string Url { get; set; } = null!;
14+
}
15+
16+
public class RssBlog : BlogBase
17+
{
18+
public string Url { get; set; } = null!;
19+
}
20+
21+
public abstract class ShadowBlogBase
22+
{
23+
public int Id { get; set; }
24+
public string BlogType { get; set; } = null!;
25+
}
26+
27+
public class ShadowBlog : ShadowBlogBase
28+
{
29+
public string Url { get; set; } = null!;
30+
}
31+
32+
public class ShadowRssBlog : ShadowBlogBase
33+
{
34+
public string Url { get; set; } = null!;
35+
}
36+
37+
public class InheritanceContext : DbContext
38+
{
39+
public InheritanceContext(DbContextOptions options) : base(options)
40+
{
41+
42+
}
43+
44+
protected override void OnModelCreating(ModelBuilder modelBuilder)
45+
{
46+
modelBuilder.Entity<BlogBase>()
47+
.HasDiscriminator(b => b.BlogType)
48+
.HasValue<Blog>("blog_base")
49+
.HasValue<RssBlog>("blog_rss");
50+
51+
modelBuilder.Entity<BlogBase>()
52+
.Property(e => e.BlogType)
53+
.HasColumnName("BlogType")
54+
.HasMaxLength(200);
55+
56+
modelBuilder.Entity<Blog>()
57+
.Property(b => b.Url)
58+
.HasColumnName("Url");
59+
60+
modelBuilder.Entity<RssBlog>()
61+
.Property(b => b.Url)
62+
.HasColumnName("Url");
63+
64+
modelBuilder.Entity<Blog>().ToTable("Blogs");
65+
modelBuilder.Entity<RssBlog>().ToTable("Blogs");
66+
67+
/////
68+
69+
modelBuilder.Entity<ShadowBlogBase>()
70+
.HasDiscriminator()
71+
.HasValue<ShadowBlog>("blog_base")
72+
.HasValue<ShadowRssBlog>("blog_rss");
73+
74+
modelBuilder.Entity<ShadowBlogBase>()
75+
.Property(e => e.BlogType)
76+
.HasColumnName("BlogType")
77+
.HasMaxLength(200);
78+
79+
modelBuilder.Entity<ShadowBlog>()
80+
.Property(b => b.Url)
81+
.HasColumnName("Url");
82+
83+
modelBuilder.Entity<ShadowRssBlog>()
84+
.Property(b => b.Url)
85+
.HasColumnName("Url");
86+
87+
modelBuilder.Entity<ShadowBlog>().ToTable("ShadowBlogs");
88+
modelBuilder.Entity<ShadowRssBlog>().ToTable("ShadowBlogs");
89+
}
90+
91+
public DbSet<BlogBase> Blogs { get; set; } = null!;
92+
public DbSet<ShadowBlogBase> ShadowBlogs { get; set; } = null!;
93+
}
94+
95+
}

0 commit comments

Comments
 (0)