-
Notifications
You must be signed in to change notification settings - Fork 27
Expand file tree
/
Copy pathInsertOperation.cs
More file actions
119 lines (100 loc) · 3.7 KB
/
InsertOperation.cs
File metadata and controls
119 lines (100 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (C) 2019-2020 Xtensive LLC.
// This code is distributed under MIT license terms.
// See the License.txt file in the project root for more information.
using System.Linq.Expressions;
using Xtensive.Orm.Linq;
using Xtensive.Orm.Services;
using Xtensive.Sql;
namespace Xtensive.Orm.BulkOperations
{
internal class InsertOperation<T> : Operation<T>
where T : Entity
{
private readonly SetOperation<T> setOperation;
#region Non-public methods
protected override int ExecuteInternal()
{
if (PrimaryIndexes.Length > 1) {
throw new NotImplementedException("Inheritance is not implemented");
}
Bindings = new List<QueryParameterBinding>();
using var command = CreateCommand();
return command.ExecuteNonQuery();
}
protected async override Task<int> ExecuteInternalAsync(CancellationToken token = default)
{
if (PrimaryIndexes.Length > 1) {
throw new NotImplementedException("Inheritance is not implemented");
}
Bindings = new List<QueryParameterBinding>();
var command = CreateCommand();
await using (command.ConfigureAwait(false)) {
return await command.ExecuteNonQueryAsync(token).ConfigureAwait(false);
}
}
private QueryCommand CreateCommand()
{
var insert = SqlDml.Insert(SqlDml.TableRef(PrimaryIndexes[0].Table));
setOperation.Statement = SetStatement.Create(insert);
setOperation.AddValues();
return ToCommand(insert);
}
#endregion
public InsertOperation(QueryProvider queryProvider, Expression<Func<T>> evaluator)
: base(queryProvider)
{
var memberInitCount = 0;
var parameter = Expression.Parameter(typeof(T));
List<SetDescriptor> descriptors = null;
evaluator.Visit(
delegate(MemberInitExpression ex) {
if (memberInitCount > 0) {
return ex;
}
memberInitCount++;
descriptors = new List<SetDescriptor>();
foreach (var assignment in ex.Bindings.Cast<MemberAssignment>()) {
var fieldInfo = TypeInfo.Fields.FirstOrDefault(a => a.UnderlyingProperty == assignment.Member);
if (fieldInfo == null) {
if (assignment.Member.ReflectedType?.IsAssignableFrom(TypeInfo.UnderlyingType) == true) {
var property = TypeInfo.UnderlyingType.GetProperty(assignment.Member.Name);
fieldInfo = TypeInfo.Fields.FirstOrDefault(field => field.UnderlyingProperty == property);
}
}
descriptors.Add(
new SetDescriptor(fieldInfo, parameter, assignment.Expression));
}
return ex;
});
AddKey(descriptors);
setOperation = new SetOperation<T>(this, descriptors);
}
private void AddKey(List<SetDescriptor> descriptors)
{
var count = descriptors.Count(a => a.Field.IsPrimaryKey);
int i;
if (count == 0) {
var key = Key.Generate<T>(Session);
i = 0;
foreach (var fieldInfo in TypeInfo.Key.Fields) {
descriptors.Add(new SetDescriptor(fieldInfo, Expression.Parameter(typeof(T)), Expression.Constant(key.Value.GetValue(i))));
i++;
}
Key = key;
return;
}
if (count < TypeInfo.Key.Fields.Count) {
throw new InvalidOperationException("You must set 0 or all key fields");
}
i = 0;
var keys = new object[TypeInfo.Key.Fields.Count];
foreach (var field in TypeInfo.Key.Fields) {
var descriptor = descriptors.First(a => a.Field.Equals(field));
keys[i] = descriptor.Expression.Invoke();
i++;
}
Key = Key.Create<T>(Session.Domain, keys);
}
public Key Key { get; private set; }
}
}