Skip to content

Commit 8cbc5ae

Browse files
committed
Added DynamicEnumerable with Cast method
1 parent 33efbef commit 8cbc5ae

Some content is hidden

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

41 files changed

+1936
-7
lines changed

CommonAssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@
1919
// COM, set the ComVisible attribute to true on that type.
2020
[assembly: ComVisible(false)]
2121

22-
[assembly: AssemblyVersion("0.2.1.0")]
23-
[assembly: AssemblyFileVersion("0.2.1.0")]
22+
[assembly: AssemblyVersion("0.2.2.0")]
23+
[assembly: AssemblyFileVersion("0.2.2.0")]

Simple.Data.Ado/AdoAdapter.cs

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.ComponentModel.Composition;
5+
using System.Data;
6+
using System.Data.Common;
7+
using System.Data.SqlClient;
8+
using System.Linq;
9+
using System.Text;
10+
using System.Threading;
11+
using Simple.Data.Ado.Schema;
12+
13+
namespace Simple.Data.Ado
14+
{
15+
[Export("Ado", typeof(IAdapter))]
16+
internal class AdoAdapter : IAdapter, IAdapterWithRelation
17+
{
18+
private readonly IConnectionProvider _connectionProvider;
19+
private readonly DatabaseSchema _schema;
20+
21+
private readonly Lazy<ConcurrentDictionary<Tuple<string, string>, TableJoin>> _tableJoins =
22+
new Lazy<ConcurrentDictionary<Tuple<string, string>, TableJoin>>(
23+
() => new ConcurrentDictionary<Tuple<string, string>, TableJoin>(), LazyThreadSafetyMode.ExecutionAndPublication
24+
);
25+
26+
public AdoAdapter(IConnectionProvider connectionProvider)
27+
{
28+
_connectionProvider = connectionProvider;
29+
_schema = DatabaseSchema.Get(_connectionProvider);
30+
}
31+
32+
public IEnumerable<IDictionary<string, object>> Find(string tableName, SimpleExpression criteria)
33+
{
34+
if (criteria == null) return FindAll(tableName);
35+
36+
var commandBuilder = new FindHelper(_schema).GetFindByCommand(tableName, criteria);
37+
return ExecuteQuery(commandBuilder);
38+
}
39+
40+
public IDictionary<string, object> Insert(string tableName, IDictionary<string, object> data)
41+
{
42+
var table = _schema.FindTable(tableName);
43+
44+
string columnList =
45+
data.Keys.Select(s => table.FindColumn(s).QuotedName).Aggregate((agg, next) => agg + "," + next);
46+
string valueList = data.Keys.Select(s => "?").Aggregate((agg, next) => agg + "," + next);
47+
48+
string insertSql = "insert into " + table.QuotedName + " (" + columnList + ") values (" + valueList + ")";
49+
50+
var identityColumn = table.Columns.FirstOrDefault(col => col.IsIdentity);
51+
52+
if (identityColumn != null)
53+
{
54+
insertSql += "; select * from " + table.QuotedName + " where " + identityColumn.QuotedName +
55+
" = scope_identity()";
56+
return ExecuteSingletonQuery(insertSql, data.Values.ToArray());
57+
}
58+
59+
Execute(insertSql, data.Values.ToArray());
60+
return null;
61+
}
62+
63+
public int Update(string tableName, IDictionary<string, object> data, SimpleExpression criteria)
64+
{
65+
var commandBuilder = new UpdateHelper(_schema).GetUpdateCommand(tableName, data, criteria);
66+
return Execute(commandBuilder);
67+
}
68+
69+
/// <summary>
70+
/// Deletes from the specified table.
71+
/// </summary>
72+
/// <param name="tableName">Name of the table.</param>
73+
/// <param name="criteria">The expression to use as criteria for the delete operation.</param>
74+
/// <returns>The number of records which were deleted.</returns>
75+
public int Delete(string tableName, SimpleExpression criteria)
76+
{
77+
var commandBuilder = new DeleteHelper(_schema).GetDeleteCommand(tableName, criteria);
78+
return Execute(commandBuilder);
79+
}
80+
81+
/// <summary>
82+
/// Gets the names of the fields which comprise the unique identifier for the specified table.
83+
/// </summary>
84+
/// <param name="tableName">Name of the table.</param>
85+
/// <returns>A list of field names; an empty list if no key is defined.</returns>
86+
public IEnumerable<string> GetKeyFieldNames(string tableName)
87+
{
88+
return _schema.FindTable(tableName).PrimaryKey.AsEnumerable();
89+
}
90+
91+
private IEnumerable<IDictionary<string, object>> FindAll(string tableName)
92+
{
93+
return ExecuteQuery("select * from " + _schema.FindTable(tableName).ActualName);
94+
}
95+
96+
private IEnumerable<IDictionary<string, object>> ExecuteQuery(ICommandBuilder commandBuilder)
97+
{
98+
using (var connection = CreateConnection())
99+
{
100+
using (var command = commandBuilder.GetCommand(connection))
101+
{
102+
return TryExecuteQuery(connection, command);
103+
}
104+
}
105+
}
106+
107+
private IEnumerable<IDictionary<string, object>> ExecuteQuery(string sql, params object[] values)
108+
{
109+
using (var connection = CreateConnection())
110+
{
111+
using (var command = CommandHelper.Create(connection, sql, values))
112+
{
113+
return TryExecuteQuery(connection, command);
114+
}
115+
}
116+
}
117+
118+
private static IEnumerable<IDictionary<string, object>> TryExecuteQuery(DbConnection connection, IDbCommand command)
119+
{
120+
try
121+
{
122+
connection.Open();
123+
124+
return command.ExecuteReader().ToDictionaries();
125+
}
126+
catch (DbException ex)
127+
{
128+
throw new AdoAdapterException(ex.Message, command);
129+
}
130+
}
131+
132+
internal IDictionary<string, object> ExecuteSingletonQuery(string sql, params object[] values)
133+
{
134+
using (var connection = CreateConnection())
135+
{
136+
using (var command = CommandHelper.Create(connection, sql, values.ToArray()))
137+
{
138+
try
139+
{
140+
connection.Open();
141+
using (var reader = command.ExecuteReader())
142+
{
143+
if (reader.Read())
144+
{
145+
return reader.ToDictionary();
146+
}
147+
}
148+
}
149+
catch (DbException ex)
150+
{
151+
throw new AdoAdapterException(ex.Message, command);
152+
}
153+
}
154+
}
155+
156+
return null;
157+
}
158+
159+
internal int Execute(string sql, params object[] values)
160+
{
161+
using (var connection = CreateConnection())
162+
{
163+
using (var command = CommandHelper.Create(connection, sql, values.ToArray()))
164+
{
165+
return TryExecute(connection, command);
166+
}
167+
}
168+
}
169+
170+
private int Execute(ICommandBuilder commandBuilder)
171+
{
172+
using (var connection = CreateConnection())
173+
{
174+
using (var command = commandBuilder.GetCommand(connection))
175+
{
176+
return TryExecute(connection, command);
177+
}
178+
}
179+
}
180+
181+
private static int TryExecute(DbConnection connection, IDbCommand command)
182+
{
183+
try
184+
{
185+
connection.Open();
186+
return command.ExecuteNonQuery();
187+
}
188+
catch (DbException ex)
189+
{
190+
throw new AdoAdapterException(ex.Message, command);
191+
}
192+
}
193+
194+
internal DbConnection CreateConnection()
195+
{
196+
return _connectionProvider.CreateConnection();
197+
}
198+
199+
internal DatabaseSchema GetSchema()
200+
{
201+
return DatabaseSchema.Get(_connectionProvider);
202+
}
203+
204+
/// <summary>
205+
/// Determines whether a relation is valid.
206+
/// </summary>
207+
/// <param name="tableName">Name of the known table.</param>
208+
/// <param name="relatedTableName">Name of the table to test.</param>
209+
/// <returns>
210+
/// <c>true</c> if there is a valid relation; otherwise, <c>false</c>.
211+
/// </returns>
212+
public bool IsValidRelation(string tableName, string relatedTableName)
213+
{
214+
return TryJoin(tableName, relatedTableName) != null;
215+
}
216+
217+
/// <summary>
218+
/// Finds data from a "table" related to the specified "table".
219+
/// </summary>
220+
/// <param name="tableName">Name of the table.</param>
221+
/// <param name="row"></param>
222+
/// <param name="relatedTableName"></param>
223+
/// <returns>The list of records matching the criteria. If no records are found, return an empty list.</returns>
224+
/// <remarks>When implementing the <see cref="IAdapter"/> interface, if relationships are not possible, throw a <see cref="NotSupportedException"/>.</remarks>
225+
public IEnumerable<IDictionary<string, object>> FindRelated(string tableName, IDictionary<string, object> row, string relatedTableName)
226+
{
227+
var join = TryJoin(tableName, relatedTableName);
228+
if (join == null) throw new AdoAdapterException("Could not resolve relationship.");
229+
230+
return join.Master == _schema.FindTable(tableName) ? GetDetail(row, join) : GetMaster(row, join);
231+
}
232+
233+
private TableJoin TryJoin(string tableName, string relatedTableName)
234+
{
235+
return _tableJoins.Value.GetOrAdd(Tuple.Create(tableName, relatedTableName),
236+
t => TryCreateJoin(t.Item1, t.Item2));
237+
}
238+
239+
private TableJoin TryCreateJoin(string tableName, string relatedTableName)
240+
{
241+
return TryMasterJoin(tableName, relatedTableName) ?? TryDetailJoin(tableName, relatedTableName);
242+
}
243+
244+
private TableJoin TryMasterJoin(string tableName, string relatedTableName)
245+
{
246+
return _schema.FindTable(tableName).GetMaster(relatedTableName);
247+
}
248+
249+
private TableJoin TryDetailJoin(string tableName, string relatedTableName)
250+
{
251+
return _schema.FindTable(tableName).GetDetail(relatedTableName);
252+
}
253+
254+
private IEnumerable<IDictionary<string,object>> GetMaster(IDictionary<string,object> row, TableJoin masterJoin)
255+
{
256+
var criteria = new Dictionary<string, object> { { masterJoin.MasterColumn.ActualName, row[masterJoin.DetailColumn.HomogenizedName] } };
257+
yield return Find(masterJoin.Master.ActualName,
258+
ExpressionHelper.CriteriaDictionaryToExpression(masterJoin.Master.ActualName,
259+
criteria)).FirstOrDefault();
260+
}
261+
262+
private IEnumerable<IDictionary<string, object>> GetDetail(IDictionary<string, object> row, TableJoin join)
263+
{
264+
var criteria = new Dictionary<string, object> { { join.DetailColumn.ActualName, row[join.MasterColumn.HomogenizedName] } };
265+
return Find(join.Detail.ActualName,
266+
ExpressionHelper.CriteriaDictionaryToExpression(join.Detail.ActualName,
267+
criteria));
268+
}
269+
}
270+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data;
4+
using System.Linq;
5+
using System.Runtime.Serialization;
6+
using System.Text;
7+
using Simple.Data.Extensions;
8+
9+
namespace Simple.Data.Ado
10+
{
11+
public class AdoAdapterException : AdapterException
12+
{
13+
private readonly string _commandText;
14+
private readonly IDictionary<string,object> _parameters;
15+
16+
public AdoAdapterException() : base(typeof(AdoAdapter))
17+
{
18+
}
19+
20+
public AdoAdapterException(string message, IDbCommand command) : base(message, typeof(AdoAdapter))
21+
{
22+
_commandText = command.CommandText;
23+
_parameters = command.Parameters.Cast<IDbDataParameter>()
24+
.ToDictionary(p => p.ParameterName, p => p.Value);
25+
}
26+
27+
public AdoAdapterException(string commandText, IEnumerable<KeyValuePair<string,object>> parameters)
28+
:base(typeof(AdoAdapter))
29+
{
30+
_commandText = commandText;
31+
_parameters = parameters.ToDictionary();
32+
}
33+
34+
35+
public AdoAdapterException(string message) : base(message, typeof(AdoAdapter))
36+
{
37+
}
38+
39+
public AdoAdapterException(string message, string commandText, IEnumerable<KeyValuePair<string,object>> parameters)
40+
:base(message, typeof(AdoAdapter))
41+
{
42+
_commandText = commandText;
43+
_parameters = parameters.ToDictionary();
44+
}
45+
46+
public AdoAdapterException(string message, Exception inner) : base(message, inner, typeof(AdoAdapter))
47+
{
48+
}
49+
50+
public AdoAdapterException(SerializationInfo info, StreamingContext context) : base(info, context)
51+
{
52+
}
53+
54+
public IDictionary<string, object> Parameters
55+
{
56+
get { return _parameters; }
57+
}
58+
59+
public string CommandText
60+
{
61+
get { return _commandText; }
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)