forked from nhibernate/nhibernate-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSqlInsertBuilder.cs
225 lines (191 loc) · 6.24 KB
/
SqlInsertBuilder.cs
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
using System;
using System.Linq;
using NHibernate.Engine;
using NHibernate.SqlTypes;
using NHibernate.Type;
using NHibernate.Util;
namespace NHibernate.SqlCommand
{
/// <summary>
/// A class that builds an <c>INSERT</c> sql statement.
/// </summary>
public class SqlInsertBuilder : ISqlStringBuilder
{
private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(SqlInsertBuilder));
private readonly ISessionFactoryImplementor factory;
private string tableName;
private string comment;
// columns-> (ColumnName, Value) or (ColumnName, SqlType) for parametrized column
private readonly LinkedHashMap<string, object> columns = new LinkedHashMap<string, object>();
public SqlInsertBuilder(ISessionFactoryImplementor factory)
{
this.factory = factory;
}
protected internal Dialect.Dialect Dialect
{
get { return factory.Dialect; }
}
public virtual SqlInsertBuilder SetComment(string comment)
{
this.comment = comment;
return this;
}
public SqlInsertBuilder SetTableName(string tableName)
{
this.tableName = tableName;
return this;
}
/// <summary>
/// Adds the Property's columns to the INSERT sql
/// </summary>
/// <param name="columnName">The column name for the Property</param>
/// <param name="propertyType">The IType of the property.</param>
/// <returns>The SqlInsertBuilder.</returns>
/// <remarks>The column will be associated with a parameter.</remarks>
public virtual SqlInsertBuilder AddColumn(string columnName, IType propertyType)
{
SqlType[] sqlTypes = propertyType.SqlTypes(factory);
if (sqlTypes.Length > 1)
throw new AssertionFailure("Adding one column for a composed IType.");
AddColumnWithValueOrType(columnName, sqlTypes[0]);
return this;
}
/// <summary>
/// Add a column with a specific value to the INSERT sql
/// </summary>
/// <param name="columnName">The name of the Column to add.</param>
/// <param name="val">The value to set for the column.</param>
/// <param name="literalType">The NHibernateType to use to convert the value to a sql string.</param>
/// <returns>The SqlInsertBuilder.</returns>
public SqlInsertBuilder AddColumn(string columnName, object val, ILiteralType literalType)
{
return AddColumn(columnName, literalType.ObjectToSQLString(val, Dialect));
}
/// <summary>
/// Add a column with a specific value to the INSERT sql
/// </summary>
/// <param name="columnName">The name of the Column to add.</param>
/// <param name="val">A valid sql string to set as the value of the column.</param>
/// <returns>The SqlInsertBuilder.</returns>
public SqlInsertBuilder AddColumn(string columnName, string val)
{
AddColumnWithValueOrType(columnName, val);
return this;
}
public SqlInsertBuilder AddColumns(string[] columnNames, bool[] insertable, IType propertyType)
{
SqlType[] sqlTypes = propertyType.SqlTypes(factory);
for (int i = 0; i < columnNames.Length; i++)
{
if (insertable == null || insertable[i])
{
if (i >= sqlTypes.Length)
throw new AssertionFailure("Different columns and it's IType.");
AddColumnWithValueOrType(columnNames[i], sqlTypes[i]);
}
}
return this;
}
private void AddColumnWithValueOrType(string columnName, object valueOrType)
{
if (columns.ContainsKey(columnName))
throw new ArgumentException(
$"The column '{columnName}' has already been added in this SQL builder",
nameof(columnName));
columns.Add(columnName, valueOrType);
}
public virtual SqlInsertBuilder AddIdentityColumn(string columnName)
{
string value = Dialect.IdentityInsertString;
if (value != null)
{
AddColumn(columnName, value);
}
return this;
}
#region ISqlStringBuilder Members
public virtual SqlString ToSqlString()
{
// 5 = "INSERT INTO", tableName, " (" , ") VALUES (", and ")"
int initialCapacity = 5;
// 2 = the first column is just the columnName and columnValue
initialCapacity += 2;
// eachColumn after the first one is 4 because of the ", ", columnName
// and the ", " columnValue
if (columns.Count > 0)
{
initialCapacity += ((columns.Count - 1) * 4);
}
if (!string.IsNullOrEmpty(comment))
initialCapacity++;
SqlStringBuilder sqlBuilder = new SqlStringBuilder(initialCapacity + 2);
if (!string.IsNullOrEmpty(comment))
{
sqlBuilder.Add("/* " + comment + " */ ");
}
sqlBuilder.Add("INSERT INTO ")
.Add(tableName);
if (columns.Count == 0)
{
sqlBuilder.Add(" ").Add(factory.Dialect.NoColumnsInsertString);
}
else
{
sqlBuilder.Add(" (");
// do we need a comma before we add the column to the INSERT list
// when we get started the first column doesn't need one.
bool commaNeeded = false;
foreach (string columnName in columns.Keys)
{
// build up the column list
if (commaNeeded)
sqlBuilder.Add(StringHelper.CommaSpace);
commaNeeded = true;
sqlBuilder.Add(columnName);
}
sqlBuilder.Add(") VALUES (");
commaNeeded = false;
foreach (object obj in columns.Values)
{
if (commaNeeded)
sqlBuilder.Add(StringHelper.CommaSpace);
commaNeeded = true;
SqlType param = obj as SqlType;
if (param != null)
sqlBuilder.Add(Parameter.Placeholder);
else
sqlBuilder.Add((string) obj);
}
sqlBuilder.Add(")");
}
if (log.IsDebugEnabled())
{
if (initialCapacity < sqlBuilder.Count)
{
log.Debug("The initial capacity was set too low at: {0} for the InsertSqlBuilder that needed a capacity of: {1} for the table {2}",
initialCapacity,
sqlBuilder.Count,
tableName);
}
else if (initialCapacity > 16 && ((float) initialCapacity / sqlBuilder.Count) > 1.2)
{
log.Debug("The initial capacity was set too high at: {0} for the InsertSqlBuilder that needed a capacity of: {1} for the table {2}",
initialCapacity,
sqlBuilder.Count,
tableName);
}
}
return sqlBuilder.ToSqlString();
}
#endregion
public SqlCommandInfo ToSqlCommandInfo()
{
SqlString text = ToSqlString();
return new SqlCommandInfo(text, GetParametersTypeArray());
}
public SqlType[] GetParametersTypeArray()
{
return columns.Values.OfType<SqlType>().ToArray();
}
}
}