Skip to content

Commit e8a06dc

Browse files
committed
Merge branch 'net-standard-21' into net-core-31
2 parents 5c45e39 + 27b9222 commit e8a06dc

50 files changed

Lines changed: 2932 additions & 1309 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ _Build
2626
_Work
2727
.vs
2828
.idea
29-
User.Directory.Build.props
29+
User.Directory.Build.props
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (C) 2020 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
5+
using System;
6+
using System.Linq;
7+
using NUnit.Framework;
8+
using Xtensive.Orm.BulkOperations.ContainsTestModel;
9+
using Xtensive.Orm.Configuration;
10+
11+
namespace Xtensive.Orm.BulkOperations.ContainsTestModel
12+
{
13+
[HierarchyRoot]
14+
[KeyGenerator(KeyGeneratorKind.None)]
15+
public class TagType : Entity
16+
{
17+
[Field, Key]
18+
public long Id { get; private set; }
19+
20+
[Field]
21+
public int ProjectedValueAdjustment { get; set; }
22+
23+
public TagType(Session session, long id)
24+
:base(session, id)
25+
{
26+
}
27+
}
28+
}
29+
30+
namespace Xtensive.Orm.BulkOperations.Tests
31+
{
32+
public class ContainsTest : AutoBuildTest
33+
{
34+
private long[] tagIds;
35+
36+
protected override DomainConfiguration BuildConfiguration()
37+
{
38+
var configuration = base.BuildConfiguration();
39+
configuration.Types.Register(typeof(TagType).Assembly, typeof(TagType).Namespace);
40+
return configuration;
41+
}
42+
43+
protected override void PopulateData()
44+
{
45+
tagIds = Enumerable.Range(0, 100).Select(i => (long) i).ToArray();
46+
using (var session = Domain.OpenSession())
47+
using (var transaction = session.OpenTransaction()) {
48+
foreach (var id in tagIds.Concat(Enumerable.Repeat(1000, 1).Select(i => (long) i)))
49+
new TagType(session, id) { ProjectedValueAdjustment = -1 };
50+
transaction.Complete();
51+
}
52+
}
53+
54+
[Test]
55+
public void Test1()
56+
{
57+
using (var session = Domain.OpenSession())
58+
using (var tx = session.OpenTransaction()) {
59+
var updatedRows = session.Query.All<TagType>()
60+
.Where(t => t.Id.In(tagIds))
61+
.Set(t => t.ProjectedValueAdjustment, 2)
62+
.Update();
63+
Assert.That(updatedRows, Is.EqualTo(100));
64+
Assert.That(session.Query.All<TagType>().Count(t => t.ProjectedValueAdjustment == 2 && t.Id <= 200), Is.EqualTo(100));
65+
Assert.That(session.Query.All<TagType>().Count(t => t.ProjectedValueAdjustment == -1 && t.Id > 700), Is.EqualTo(1));
66+
}
67+
}
68+
69+
[Test]
70+
public void Test2()
71+
{
72+
using (var session = Domain.OpenSession())
73+
using (var tx = session.OpenTransaction()) {
74+
var updatedRows = session.Query.All<TagType>()
75+
.Where(t => t.Id.In(IncludeAlgorithm.ComplexCondition, tagIds))
76+
.Set(t => t.ProjectedValueAdjustment, 2)
77+
.Update();
78+
Assert.That(updatedRows, Is.EqualTo(100));
79+
Assert.That(session.Query.All<TagType>().Count(t => t.ProjectedValueAdjustment == 2 && t.Id <= 200), Is.EqualTo(100));
80+
Assert.That(session.Query.All<TagType>().Count(t => t.ProjectedValueAdjustment == -1 && t.Id > 700), Is.EqualTo(1));
81+
}
82+
}
83+
84+
[Test]
85+
public void Test3()
86+
{
87+
using (var session = Domain.OpenSession())
88+
using (var tx = session.OpenTransaction()) {
89+
Assert.Throws<NotSupportedException>(() => session.Query.All<TagType>()
90+
.Where(t => t.Id.In(IncludeAlgorithm.TemporaryTable, tagIds))
91+
.Set(t => t.ProjectedValueAdjustment, 2)
92+
.Update());
93+
}
94+
}
95+
96+
[Test]
97+
public void Test4()
98+
{
99+
using (var session = Domain.OpenSession())
100+
using (var tx = session.OpenTransaction()) {
101+
var updatedRows = session.Query.All<TagType>()
102+
.Where(t => tagIds.Contains(t.Id))
103+
.Set(t => t.ProjectedValueAdjustment, 2)
104+
.Update();
105+
Assert.That(updatedRows, Is.EqualTo(100));
106+
Assert.That(session.Query.All<TagType>().Count(t => t.ProjectedValueAdjustment == 2 && t.Id <= 200), Is.EqualTo(100));
107+
Assert.That(session.Query.All<TagType>().Count(t => t.ProjectedValueAdjustment == -1 && t.Id > 700), Is.EqualTo(1));
108+
}
109+
}
110+
}
111+
}

Extensions/Xtensive.Orm.BulkOperations.Tests/Other.cs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
using System;
1+
// Copyright (C) 2012-2020 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
// Created by: Alexander Ovchinnikov
5+
// Created: 2012.02.29
6+
7+
using System;
28
using System.Collections.Generic;
39
using System.Linq;
410
using NUnit.Framework;
@@ -242,5 +248,34 @@ public void In()
242248
trx.Complete();
243249
}
244250
}
251+
252+
[Test]
253+
public void InWithCombinationWithFieldUsageUpdate()
254+
{
255+
using (Session session = Domain.OpenSession())
256+
using (TransactionScope trx = session.OpenTransaction()) {
257+
var idsToUpdate = new[] { 99, 100, 102 };
258+
var prefix = "abc";
259+
260+
var bar1 = new Bar(session, 100) { Name = "test1", Count = 3 };
261+
var bar2 = new Bar(session, 101) { Name = "test2", Count = 4 };
262+
var bar3 = new Bar(session, 102) { Name = "test3", Count = 5 };
263+
session.SaveChanges();
264+
265+
var updatedCount = session.Query.All<Bar>()
266+
.Where(b => b.Id.In(IncludeAlgorithm.ComplexCondition, idsToUpdate))
267+
.Update(bar => new Bar(session) { Name = prefix + bar.Name });
268+
Assert.That(updatedCount, Is.EqualTo(2));
269+
270+
var all = session.Query.All<Bar>().Where(b=> b.Id == 100 || b.Id == 101 || b.Id == 102).ToList();
271+
var updatedEntities = all.Where(b => b.Id.In(idsToUpdate));
272+
Assert.That(updatedEntities.All(e => e.Name.StartsWith(prefix)), Is.True);
273+
274+
var leftEntities = all.Where(b => !b.Id.In(idsToUpdate));
275+
Assert.That(leftEntities.All(e => e.Name.StartsWith(prefix)), Is.False);
276+
277+
trx.Complete();
278+
}
279+
}
245280
}
246281
}

Extensions/Xtensive.Orm.BulkOperations/Internals/ExpressionExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Linq;
33
using System.Linq.Expressions;
4+
using Xtensive.Linq;
45
using Xtensive.Reflection;
56

67
namespace Xtensive.Orm.BulkOperations
@@ -23,7 +24,7 @@ public static bool IsContainsQuery(this Expression expression)
2324

2425
internal static object Invoke(this Expression expression)
2526
{
26-
return Expression.Lambda(typeof (Func<>).MakeGenericType(expression.Type), expression).Compile().DynamicInvoke();
27+
return FastExpression.Lambda(typeof (Func<>).MakeGenericType(expression.Type), expression).Compile().DynamicInvoke();
2728
}
2829

2930
internal static Expression Visit<T>(this Expression exp, Func<T, Expression> visitor) where T : Expression

Extensions/Xtensive.Orm.BulkOperations/Internals/QueryOperation.cs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Linq.Expressions;
@@ -14,7 +14,7 @@ namespace Xtensive.Orm.BulkOperations
1414
internal abstract class QueryOperation<T> : Operation<T>
1515
where T : class, IEntity
1616
{
17-
private static MethodInfo inMethod = GetInMethod();
17+
private readonly static MethodInfo inMethod = GetInMethod();
1818
protected IQueryable<T> query;
1919

2020
protected QueryOperation(QueryProvider queryProvider)
@@ -24,10 +24,9 @@ protected QueryOperation(QueryProvider queryProvider)
2424

2525
private static MethodInfo GetInMethod()
2626
{
27-
foreach (var method in typeof (QueryableExtensions).GetMethods().Where(a=>a.Name=="In"))
28-
{
27+
foreach (var method in typeof (QueryableExtensions).GetMethods().Where(a => string.Equals(a.Name, "In", StringComparison.Ordinal))) {
2928
var parameters = method.GetParameters();
30-
if (parameters.Length == 3 && parameters[2].ParameterType.Name == "IEnumerable`1")
29+
if (parameters.Length == 3 && string.Equals(parameters[2].ParameterType.Name, "IEnumerable`1", StringComparison.Ordinal))
3130
return method;
3231
}
3332
return null;
@@ -37,30 +36,38 @@ protected override int ExecuteInternal()
3736
{
3837
Expression e = query.Expression.Visit((MethodCallExpression ex) =>
3938
{
40-
if (ex.Method.DeclaringType == typeof (QueryableExtensions) && ex.Method.Name == "In" &&
41-
ex.Arguments.Count > 1)
42-
{
43-
if (ex.Arguments[1].Type == typeof (IncludeAlgorithm))
44-
{
45-
var v = (IncludeAlgorithm) ex.Arguments[1].Invoke();
46-
if (v == IncludeAlgorithm.TemporaryTable)
47-
{
39+
var methodInfo = ex.Method;
40+
//rewrite localCollection.Contains(entity.SomeField) -> entity.SomeField.In(localCollection)
41+
if (methodInfo.DeclaringType == typeof(Enumerable) &&
42+
string.Equals(methodInfo.Name, "Contains", StringComparison.Ordinal) &&
43+
ex.Arguments.Count == 2) {
44+
var localCollection = ex.Arguments[0];//IEnumerable<T>
45+
var valueToCheck = ex.Arguments[1];
46+
var genericInMethod = inMethod.MakeGenericMethod(new[] { valueToCheck.Type });
47+
ex = Expression.Call(genericInMethod, valueToCheck, Expression.Constant(IncludeAlgorithm.ComplexCondition), localCollection);
48+
methodInfo = ex.Method;
49+
}
50+
51+
if (methodInfo.DeclaringType == typeof(QueryableExtensions) &&
52+
string.Equals(methodInfo.Name, "In", StringComparison.Ordinal) &&
53+
ex.Arguments.Count > 1) {
54+
if (ex.Arguments[1].Type == typeof(IncludeAlgorithm)) {
55+
var algorithm = (IncludeAlgorithm) ex.Arguments[1].Invoke();
56+
if (algorithm == IncludeAlgorithm.TemporaryTable) {
4857
throw new NotSupportedException("IncludeAlgorithm.TemporaryTable is not supported");
4958
}
50-
if (v == IncludeAlgorithm.Auto)
51-
{
59+
if (algorithm == IncludeAlgorithm.Auto) {
5260
List<Expression> arguments = ex.Arguments.ToList();
5361
arguments[1] = Expression.Constant(IncludeAlgorithm.ComplexCondition);
54-
ex = Expression.Call(ex.Method, arguments);
62+
ex = Expression.Call(methodInfo, arguments);
5563
}
5664
}
57-
else
58-
{
65+
else {
5966
List<Expression> arguments = ex.Arguments.ToList();
6067
arguments.Insert(1, Expression.Constant(IncludeAlgorithm.ComplexCondition));
61-
List<Type> types = ex.Method.GetParameters().Select(a => a.ParameterType).ToList();
62-
types.Insert(1, typeof (IncludeAlgorithm));
63-
ex = Expression.Call(inMethod.MakeGenericMethod(ex.Method.GetGenericArguments()),
68+
List<Type> types = methodInfo.GetParameters().Select(a => a.ParameterType).ToList();
69+
types.Insert(1, typeof(IncludeAlgorithm));
70+
ex = Expression.Call(inMethod.MakeGenericMethod(methodInfo.GetGenericArguments()),
6471
arguments.ToArray());
6572
}
6673
}

Extensions/Xtensive.Orm.BulkOperations/Internals/SetOperation.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ private void AddConstantValue(AddValueContext addContext)
140140
{
141141
SqlTableColumn column = SqlDml.TableColumn(addContext.Statement.Table, addContext.Field.Column.Name);
142142
SqlExpression value;
143-
object constant = FastExpression.Lambda(addContext.Lambda.Body, null).Compile().DynamicInvoke();
143+
object constant = FastExpression.Lambda(addContext.Lambda.Body).Compile().DynamicInvoke();
144144
if (constant==null)
145145
value = SqlDml.Null;
146146
else {
@@ -200,7 +200,7 @@ private void AddEntityValue(AddValueContext addContext)
200200
i++;
201201
ParameterExpression p = Expression.Parameter(info.UnderlyingType);
202202
LambdaExpression lambda =
203-
Expression.Lambda(
203+
FastExpression.Lambda(
204204
typeof (Func<,>).MakeGenericType(info.UnderlyingType, field.ValueType),
205205
Expression.MakeMemberAccess(p, field.UnderlyingProperty),
206206
p);
@@ -239,7 +239,7 @@ public void AddValues()
239239
var addContext = new AddValueContext {
240240
Descriptor = descriptor,
241241
Lambda =
242-
Expression.Lambda(
242+
FastExpression.Lambda(
243243
typeof (Func<,>).MakeGenericType(typeof (T), descriptor.Expression.Type),
244244
descriptor.Expression,
245245
descriptor.Parameter),
Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
1-
using System;
2-
using Xtensive.Core;
3-
using Microsoft.AspNetCore.Builder;
4-
5-
namespace Xtensive.Orm.Web
6-
{
7-
/// <summary>
8-
/// Contains helper methods to apply <see cref="SessionManager"/> middleware to ASP.NET Core pipeline.
9-
/// </summary>
10-
public static class ApplicationBuilderExtensions
11-
{
12-
/// <summary>
13-
/// Adds <see cref="SessionManager"/> to ASP.NET Core middleware pipeline.
14-
/// </summary>
15-
/// <param name="builder"><see cref="IApplicationBuilder"/> instance.</param>
16-
/// <returns><paramref name="builder"/> with <see cref="SessionManager"/>.</returns>
17-
public static IApplicationBuilder UseSessionManager(this IApplicationBuilder builder)
18-
{
19-
return builder.UseMiddleware<SessionManager>();
20-
}
21-
22-
/// <summary>
23-
/// Adds <see cref="SessionManager"/> to ASP.NET Core middleware pipeline.
24-
/// </summary>
25-
/// <param name="builder"><see cref="IApplicationBuilder"/> instance.</param>
26-
/// <param name="sessionProvider">User-defined session provider which will be used instead of built-in provider.</param>
27-
/// <returns><paramref name="builder"/> with <see cref="SessionManager"/>.</returns>
28-
public static IApplicationBuilder UseSessionManager(this IApplicationBuilder builder, Func<Pair<Session, System.IDisposable>> sessionProvider)
29-
{
30-
SessionManager.SessionProvider = sessionProvider;
31-
return builder.UseMiddleware<SessionManager>();
32-
}
33-
}
34-
}
1+
using System;
2+
using Xtensive.Core;
3+
using Microsoft.AspNetCore.Builder;
4+
5+
namespace Xtensive.Orm.Web
6+
{
7+
/// <summary>
8+
/// Contains helper methods to apply <see cref="SessionManager"/> middleware to ASP.NET Core pipeline.
9+
/// </summary>
10+
public static class ApplicationBuilderExtensions
11+
{
12+
/// <summary>
13+
/// Adds <see cref="SessionManager"/> to ASP.NET Core middleware pipeline.
14+
/// </summary>
15+
/// <param name="builder"><see cref="IApplicationBuilder"/> instance.</param>
16+
/// <returns><paramref name="builder"/> with <see cref="SessionManager"/>.</returns>
17+
public static IApplicationBuilder UseSessionManager(this IApplicationBuilder builder)
18+
{
19+
return builder.UseMiddleware<SessionManager>();
20+
}
21+
22+
/// <summary>
23+
/// Adds <see cref="SessionManager"/> to ASP.NET Core middleware pipeline.
24+
/// </summary>
25+
/// <param name="builder"><see cref="IApplicationBuilder"/> instance.</param>
26+
/// <param name="sessionProvider">User-defined session provider which will be used instead of built-in provider.</param>
27+
/// <returns><paramref name="builder"/> with <see cref="SessionManager"/>.</returns>
28+
public static IApplicationBuilder UseSessionManager(this IApplicationBuilder builder, Func<Pair<Session, System.IDisposable>> sessionProvider)
29+
{
30+
SessionManager.SessionProvider = sessionProvider;
31+
return builder.UseMiddleware<SessionManager>();
32+
}
33+
}
34+
}

Orm/Xtensive.Orm.Tests.Core/Linq/LambdaExpressionFactoryTests.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
4-
// Created by: Denis Krjuchkov
5-
// Created: 2020.14.02
1+
// Copyright (C) 2020 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
64

75
using System;
86
using System.Linq.Expressions;

0 commit comments

Comments
 (0)