Select improvements and alias parsing.

Insert and updates evolved.
Written more tests that intended to break parser.
Added basic exception handling, telling user what went wrong.

TODO:
 * INSERT INTO ... SELECT ...
 * Extend and normalize documentation.
This commit is contained in:
grzegorz.russek
2013-06-05 11:53:49 +00:00
parent de58df8c60
commit 3aa20eb50b
13 changed files with 423 additions and 44 deletions

View File

@@ -27,6 +27,7 @@
*/ */
using System.Linq; using System.Linq;
using DynamORM.Builders;
using DynamORM.Builders.Implementation; using DynamORM.Builders.Implementation;
using NUnit.Framework; using NUnit.Framework;
@@ -55,13 +56,15 @@ namespace DynamORM.Tests.Modify
DestroyTestDatabase(); DestroyTestDatabase();
} }
#region Insert
/// <summary> /// <summary>
/// Tests the basic insert. /// Tests the basic insert.
/// </summary> /// </summary>
[Test] [Test]
public void TestBasicInsert() public void TestInsertBasic()
{ {
var cmd = new DynamicInsertQueryBuilder(Database, "Users"); IDynamicInsertQueryBuilder cmd = new DynamicInsertQueryBuilder(Database, "Users");
cmd.Insert(x => x.Users.Code = "001", x => x.Users.Name = "Admin", x => x.Users.IsAdmin = 1); cmd.Insert(x => x.Users.Code = "001", x => x.Users.Name = "Admin", x => x.Users.IsAdmin = 1);
@@ -75,7 +78,7 @@ namespace DynamORM.Tests.Modify
[Test] [Test]
public void TestInsertSubQuery() public void TestInsertSubQuery()
{ {
var cmd = new DynamicInsertQueryBuilder(Database, "Users"); IDynamicInsertQueryBuilder cmd = new DynamicInsertQueryBuilder(Database, "Users");
cmd.Insert(x => x.Code = "001", x => x.Name = "Admin", x => x.IsAdmin = x(cmd cmd.Insert(x => x.Code = "001", x => x.Name = "Admin", x => x.IsAdmin = x(cmd
.SubQuery(a => a.AccessRights.As(a.a)) .SubQuery(a => a.AccessRights.As(a.a))
@@ -90,9 +93,9 @@ namespace DynamORM.Tests.Modify
/// Tests the basic insert using object. /// Tests the basic insert using object.
/// </summary> /// </summary>
[Test] [Test]
public void TestBasicInsertObject() public void TestInsertBasicObject()
{ {
var cmd = new DynamicInsertQueryBuilder(Database, "Users"); IDynamicInsertQueryBuilder cmd = new DynamicInsertQueryBuilder(Database, "Users");
cmd.Insert(x => new { Code = "001", Name = "Admin", IsAdmin = 1 }); cmd.Insert(x => new { Code = "001", Name = "Admin", IsAdmin = 1 });
@@ -106,7 +109,7 @@ namespace DynamORM.Tests.Modify
[Test] [Test]
public void TestInsertSubQueryObject() public void TestInsertSubQueryObject()
{ {
var cmd = new DynamicInsertQueryBuilder(Database, "Users"); IDynamicInsertQueryBuilder cmd = new DynamicInsertQueryBuilder(Database, "Users");
cmd.Insert(x => new cmd.Insert(x => new
{ {
@@ -121,5 +124,81 @@ namespace DynamORM.Tests.Modify
Assert.AreEqual(string.Format(@"INSERT INTO ""Users"" (""Code"", ""Name"", ""IsAdmin"") VALUES ({0}, (SELECT a.""IsAdmin"" FROM ""AccessRights"" AS a WHERE (a.""User_Id"" = [${1}])))", Assert.AreEqual(string.Format(@"INSERT INTO ""Users"" (""Code"", ""Name"", ""IsAdmin"") VALUES ({0}, (SELECT a.""IsAdmin"" FROM ""AccessRights"" AS a WHERE (a.""User_Id"" = [${1}])))",
string.Join(", ", cmd.Parameters.Keys.Take(2).Select(p => string.Format("[${0}]", p))), cmd.Parameters.Keys.Last()), cmd.CommandText()); string.Join(", ", cmd.Parameters.Keys.Take(2).Select(p => string.Format("[${0}]", p))), cmd.Parameters.Keys.Last()), cmd.CommandText());
} }
#endregion Insert
#region Update
/// <summary>
/// Tests the basic update.
/// </summary>
[Test]
public void TestUpdateBasic()
{
IDynamicUpdateQueryBuilder cmd = new DynamicUpdateQueryBuilder(Database, "Users");
cmd.Values(x => x.Users.Code = "001", x => x.Users.Name = "Admin", x => x.Users.IsAdmin = 1)
.Where(x => x.Users.Id_User == 1);
Assert.AreEqual(string.Format(@"UPDATE ""Users"" SET ""Code"" = [${0}], ""Name"" = [${1}], ""IsAdmin"" = [${2}] WHERE (""Users"".""Id_User"" = [${3}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2], cmd.Parameters.Keys.ToArray()[3]), cmd.CommandText());
}
/// <summary>
/// Tests the insert with sub query.
/// </summary>
[Test]
public void TestUpdateSubQuery()
{
IDynamicUpdateQueryBuilder cmd = new DynamicUpdateQueryBuilder(Database, "Users");
cmd.Values(x => x.Users.Code = "001", x => x.Users.Name = "Admin", x => x.Users.IsAdmin = x(cmd
.SubQuery(a => a.AccessRights.As(a.a))
.Select(a => a.IsAdmin)
.Where(a => a.User_Id == a.Users.Id_User)))
.Where(x => x.Users.Id_User == 1);
Assert.AreEqual(string.Format(@"UPDATE ""Users"" SET ""Code"" = [${0}], ""Name"" = [${1}], ""IsAdmin"" = (SELECT a.""IsAdmin"" FROM ""AccessRights"" AS a WHERE (a.""User_Id"" = ""Users"".""Id_User"")) WHERE (""Users"".""Id_User"" = [${2}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
/// <summary>
/// Tests the basic insert using object.
/// </summary>
[Test]
public void TestUpdateBasicObject()
{
IDynamicUpdateQueryBuilder cmd = new DynamicUpdateQueryBuilder(Database, "Users");
cmd.Values(x => new { Code = "001", Name = "Admin", IsAdmin = 1 })
.Where(x => new { Id_User = 1 });
Assert.AreEqual(string.Format(@"UPDATE ""Users"" SET ""Code"" = [${0}], ""Name"" = [${1}], ""IsAdmin"" = [${2}] WHERE (""Id_User"" = [${3}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2], cmd.Parameters.Keys.ToArray()[3]), cmd.CommandText());
}
/// <summary>
/// Tests the basic insert using object.
/// </summary>
[Test]
public void TestUpdateSubQueryObject()
{
IDynamicUpdateQueryBuilder cmd = new DynamicUpdateQueryBuilder(Database, "Users");
cmd.Values(x => new
{
Code = "001",
Name = "Admin",
IsAdmin = x(cmd
.SubQuery(a => a.AccessRights.As(a.a))
.Select(a => a.IsAdmin)
.Where(a => a.User_Id == a.Users.Id_User))
}).Where(x => new { Id_User = 1 });
Assert.AreEqual(string.Format(@"UPDATE ""Users"" SET ""Code"" = [${0}], ""Name"" = [${1}], ""IsAdmin"" = (SELECT a.""IsAdmin"" FROM ""AccessRights"" AS a WHERE (a.""User_Id"" = ""Users"".""Id_User"")) WHERE (""Id_User"" = [${2}])",
cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1], cmd.Parameters.Keys.ToArray()[2]), cmd.CommandText());
}
#endregion Update
} }
} }

View File

@@ -436,29 +436,23 @@ namespace DynamORM.Tests.Select
Assert.AreEqual(exp.last, o.last); Assert.AreEqual(exp.last, o.last);
} }
/// <summary>Test dynamic duplicate column name ocurrance.</summary> /// <summary>Test dynamic duplicate column name occurrence.</summary>
[Test] [Test]
public void TestDuplicateColumnNameException() public void TestDuplicateColumnNameException()
{ {
Assert.Throws<ArgumentException>(() => GetTestBuilder() Assert.Throws<ArgumentException>(() => GetTestBuilder()
.Where(x => x.id == 19) .Where(x => x.id == 19)
.Select(x => new { id = x.id, first = x.first, last = x.last }) .Select(x => new
{
id = x.id,
first = x.first,
last = x.last,
})
.Select(x => x.last.As(x.first)) // Make last be first .Select(x => x.last.As(x.first)) // Make last be first
.Execute() .Execute()
.First()); .First());
} }
[Test]
public void TestEmptyColumnName()
{
var v = GetTestBuilder()
.Select(x => x.first, x => x.Count(x.first))
.GroupBy(x => x.first)
.OrderBy(x => x.Desc(2))
.Execute()
.ToList();
}
#endregion Select #endregion Select
#region Where #region Where

View File

@@ -326,6 +326,21 @@ namespace DynamORM.Tests.Select
Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr INNER JOIN \"dbo\".\"UserClients\" AS uc ON (usr.\"Id_User\" = uc.\"User_Id\")"), cmd.CommandText()); Assert.AreEqual(string.Format("SELECT * FROM \"dbo\".\"Users\" AS usr INNER JOIN \"dbo\".\"UserClients\" AS uc ON (usr.\"Id_User\" = uc.\"User_Id\")"), cmd.CommandText());
} }
/// <summary>
/// Tests inner join method with aliases mix.
/// </summary>
[Test]
public void TestInnerJoin2()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.usr))
.Join(usr => usr.Inner().dbo.UserClients.AS(usr.uc).On(usr.Id_User == usr.uc.User_Id && usr.uc.Users != null))
.Select(usr => usr.All(), uc => uc.Users);
Assert.AreEqual(string.Format("SELECT usr.*, uc.\"Users\" FROM \"dbo\".\"Users\" AS usr INNER JOIN \"dbo\".\"UserClients\" AS uc ON ((usr.\"Id_User\" = uc.\"User_Id\") AND (uc.\"Users\" IS NOT NULL))"), cmd.CommandText());
}
/// <summary> /// <summary>
/// Tests left outer join method. /// Tests left outer join method.
/// </summary> /// </summary>
@@ -496,6 +511,20 @@ namespace DynamORM.Tests.Select
Assert.AreEqual("SELECT u.\"UserName\" AS \"Name\" FROM \"dbo\".\"Users\" AS u", cmd.CommandText()); Assert.AreEqual("SELECT u.\"UserName\" AS \"Name\" FROM \"dbo\".\"Users\" AS u", cmd.CommandText());
} }
/// <summary>
/// Tests select field with alias.
/// </summary>
[Test]
public void TestSelectFieldAlias4()
{
IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database);
cmd.From(u => u.dbo.Users.As(u.u))
.Select(u => u.UserName.As(u.u.Name));
Assert.AreEqual("SELECT u.\"UserName\" AS \"Name\" FROM \"dbo\".\"Users\" AS u", cmd.CommandText());
}
/// <summary> /// <summary>
/// Tests select aggregate field with alias (Sum). /// Tests select aggregate field with alias (Sum).
/// </summary> /// </summary>

View File

@@ -1,4 +1,32 @@
using System; /*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace DynamORM.Builders namespace DynamORM.Builders

View File

@@ -1,8 +1,30 @@
// ----------------------------------------------------------------------- /*
// <copyright file="ITableInfo.cs" company="Microsoft"> * DynamORM - Dynamic Object-Relational Mapping library.
// TODO: Update copyright text. * Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
// </copyright> * All rights reserved.
// ----------------------------------------------------------------------- *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
using System.Collections.Generic; using System.Collections.Generic;

View File

@@ -66,6 +66,7 @@
<Compile Include="DynamicDatabase.cs" /> <Compile Include="DynamicDatabase.cs" />
<Compile Include="DynamicDatabaseOptions.cs" /> <Compile Include="DynamicDatabaseOptions.cs" />
<Compile Include="DynamicExtensions.cs" /> <Compile Include="DynamicExtensions.cs" />
<Compile Include="DynamicQueryException.cs" />
<Compile Include="DynamicSchemaColumn.cs" /> <Compile Include="DynamicSchemaColumn.cs" />
<Compile Include="DynamicTable.cs" /> <Compile Include="DynamicTable.cs" />
<Compile Include="DynamicTransaction.cs" /> <Compile Include="DynamicTransaction.cs" />

View File

@@ -28,11 +28,12 @@
using System; using System;
using System.Data; using System.Data;
using DynamORM.Helpers;
namespace DynamORM namespace DynamORM
{ {
/// <summary>Helper class to easy manage command.</summary> /// <summary>Helper class to easy manage command.</summary>
public class DynamicCommand : IDbCommand public class DynamicCommand : IDbCommand, IExtendedDisposable
{ {
private IDbCommand _command; private IDbCommand _command;
private int? _commandTimeout = null; private int? _commandTimeout = null;
@@ -45,6 +46,7 @@ namespace DynamORM
/// <param name="db">The database manager.</param> /// <param name="db">The database manager.</param>
internal DynamicCommand(DynamicConnection con, DynamicDatabase db) internal DynamicCommand(DynamicConnection con, DynamicDatabase db)
{ {
IsDisposed = false;
_con = con; _con = con;
_db = db; _db = db;
@@ -65,6 +67,7 @@ namespace DynamORM
/// <remarks>Used internally to create command without context.</remarks> /// <remarks>Used internally to create command without context.</remarks>
internal DynamicCommand(DynamicDatabase db) internal DynamicCommand(DynamicDatabase db)
{ {
IsDisposed = false;
_db = db; _db = db;
_command = db.Provider.CreateCommand(); _command = db.Provider.CreateCommand();
} }
@@ -152,7 +155,14 @@ namespace DynamORM
/// <returns>The number of rows affected.</returns> /// <returns>The number of rows affected.</returns>
public int ExecuteNonQuery() public int ExecuteNonQuery()
{ {
return PrepareForExecution().ExecuteNonQuery(); try
{
return PrepareForExecution().ExecuteNonQuery();
}
catch (Exception ex)
{
throw new DynamicQueryException(ex, this);
}
} }
/// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/> /// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/>
@@ -164,7 +174,14 @@ namespace DynamORM
/// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns> /// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns>
public IDataReader ExecuteReader(CommandBehavior behavior) public IDataReader ExecuteReader(CommandBehavior behavior)
{ {
return PrepareForExecution().ExecuteReader(behavior); try
{
return PrepareForExecution().ExecuteReader(behavior);
}
catch (Exception ex)
{
throw new DynamicQueryException(ex, this);
}
} }
/// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/> /// <summary>Executes the <see cref="P:System.Data.IDbCommand.CommandText"/>
@@ -173,7 +190,14 @@ namespace DynamORM
/// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns> /// <returns>An <see cref="T:System.Data.IDataReader"/> object.</returns>
public IDataReader ExecuteReader() public IDataReader ExecuteReader()
{ {
return PrepareForExecution().ExecuteReader(); try
{
return PrepareForExecution().ExecuteReader();
}
catch (Exception ex)
{
throw new DynamicQueryException(ex, this);
}
} }
/// <summary>Executes the query, and returns the first column of the /// <summary>Executes the query, and returns the first column of the
@@ -182,7 +206,14 @@ namespace DynamORM
/// <returns>The first column of the first row in the result set.</returns> /// <returns>The first column of the first row in the result set.</returns>
public object ExecuteScalar() public object ExecuteScalar()
{ {
return PrepareForExecution().ExecuteScalar(); try
{
return PrepareForExecution().ExecuteScalar();
}
catch (Exception ex)
{
throw new DynamicQueryException(ex, this);
}
} }
/// <summary>Gets the <see cref="T:System.Data.IDataParameterCollection"/>.</summary> /// <summary>Gets the <see cref="T:System.Data.IDataParameterCollection"/>.</summary>
@@ -194,7 +225,14 @@ namespace DynamORM
/// <summary>Creates a prepared (or compiled) version of the command on the data source.</summary> /// <summary>Creates a prepared (or compiled) version of the command on the data source.</summary>
public void Prepare() public void Prepare()
{ {
_command.Prepare(); try
{
_command.Prepare();
}
catch (Exception ex)
{
throw new DynamicQueryException("Error preparing command.", ex, this);
}
} }
/// <summary>Gets or sets the transaction within which the Command /// <summary>Gets or sets the transaction within which the Command
@@ -214,7 +252,7 @@ namespace DynamORM
#endregion IDbCommand Members #endregion IDbCommand Members
#region IDisposable Members #region IExtendedDisposable Members
/// <summary>Performs application-defined tasks associated with /// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary> /// freeing, releasing, or resetting unmanaged resources.</summary>
@@ -231,9 +269,14 @@ namespace DynamORM
} }
_command.Dispose(); _command.Dispose();
IsDisposed = true;
} }
} }
#endregion IDisposable Members /// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
#endregion IExtendedDisposable Members
} }
} }

View File

@@ -28,13 +28,14 @@
using System; using System;
using System.Data; using System.Data;
using DynamORM.Helpers;
namespace DynamORM namespace DynamORM
{ {
/// <summary>Connection wrapper.</summary> /// <summary>Connection wrapper.</summary>
/// <remarks>This class is only connection holder, connection is managed by /// <remarks>This class is only connection holder, connection is managed by
/// <see cref="DynamicDatabase"/> instance.</remarks> /// <see cref="DynamicDatabase"/> instance.</remarks>
public class DynamicConnection : IDbConnection, IDisposable public class DynamicConnection : IDbConnection, IExtendedDisposable
{ {
private DynamicDatabase _db; private DynamicDatabase _db;
private bool _singleTransaction; private bool _singleTransaction;
@@ -48,6 +49,7 @@ namespace DynamORM
/// <param name="singleTransaction">Are we using single transaction mode? I so... act correctly.</param> /// <param name="singleTransaction">Are we using single transaction mode? I so... act correctly.</param>
internal DynamicConnection(DynamicDatabase db, IDbConnection con, bool singleTransaction) internal DynamicConnection(DynamicDatabase db, IDbConnection con, bool singleTransaction)
{ {
IsDisposed = false;
_db = db; _db = db;
Connection = con; Connection = con;
_singleTransaction = singleTransaction; _singleTransaction = singleTransaction;
@@ -147,11 +149,19 @@ namespace DynamORM
#endregion IDbConnection Members #endregion IDbConnection Members
#region IExtendedDisposable Members
/// <summary>Performs application-defined tasks associated with freeing, /// <summary>Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.</summary> /// releasing, or resetting unmanaged resources.</summary>
public void Dispose() public void Dispose()
{ {
_db.Close(Connection); _db.Close(Connection);
IsDisposed = true;
} }
/// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
#endregion IExtendedDisposable Members
} }
} }

View File

@@ -40,7 +40,7 @@ using DynamORM.Mapper;
namespace DynamORM namespace DynamORM
{ {
/// <summary>Dynamic database is a class responsible for managing database.</summary> /// <summary>Dynamic database is a class responsible for managing database.</summary>
public class DynamicDatabase : IDisposable public class DynamicDatabase : IExtendedDisposable
{ {
#region Internal fields and properties #region Internal fields and properties
@@ -127,6 +127,7 @@ namespace DynamORM
/// <param name="options">Connection options.</param> /// <param name="options">Connection options.</param>
public DynamicDatabase(DbProviderFactory provider, string connectionString, DynamicDatabaseOptions options) public DynamicDatabase(DbProviderFactory provider, string connectionString, DynamicDatabaseOptions options)
{ {
IsDisposed = false;
_provider = provider; _provider = provider;
InitCommon(connectionString, options); InitCommon(connectionString, options);
@@ -137,6 +138,7 @@ namespace DynamORM
/// <param name="options">Connection options. <see cref="DynamicDatabaseOptions.SingleConnection"/> required.</param> /// <param name="options">Connection options. <see cref="DynamicDatabaseOptions.SingleConnection"/> required.</param>
public DynamicDatabase(IDbConnection connection, DynamicDatabaseOptions options) public DynamicDatabase(IDbConnection connection, DynamicDatabaseOptions options)
{ {
IsDisposed = false;
InitCommon(connection.ConnectionString, options); InitCommon(connection.ConnectionString, options);
TransactionPool.Add(connection, new Stack<IDbTransaction>()); TransactionPool.Add(connection, new Stack<IDbTransaction>());
@@ -643,7 +645,7 @@ namespace DynamORM
#endregion Transaction #endregion Transaction
#region IDisposable Members #region IExtendedDisposable Members
/// <summary>Performs application-defined tasks associated with freeing, /// <summary>Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.</summary> /// releasing, or resetting unmanaged resources.</summary>
@@ -684,9 +686,13 @@ namespace DynamORM
// Clear pools // Clear pools
TransactionPool.Clear(); TransactionPool.Clear();
CommandsPool.Clear(); CommandsPool.Clear();
IsDisposed = true;
} }
} }
#endregion IDisposable Members /// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
#endregion IExtendedDisposable Members
} }
} }

View File

@@ -798,9 +798,9 @@ namespace DynamORM
#region Dynamic extensions #region Dynamic extensions
/// <summary>Turns an <see cref="IDataReader"/> to a Dynamic list of things.</summary> /// <summary>Turns an <see cref="IDataReader"/> to a Dynamic list of things.</summary>
/// <param name="r">Reader from which read data..</param> /// <param name="r">Reader from which read data.</param>
/// <returns>List of things.</returns> /// <returns>List of things.</returns>
public static List<dynamic> ToDynamicList(this IDataReader r) public static List<dynamic> ToList(this IDataReader r)
{ {
var result = new List<dynamic>(); var result = new List<dynamic>();
@@ -810,6 +810,23 @@ namespace DynamORM
return result; return result;
} }
/// <summary>Turns an <see cref="IDynamicSelectQueryBuilder"/> to a Dynamic list of things.</summary>
/// <param name="b">Ready to execute builder.</param>
/// <returns>List of things.</returns>
public static List<dynamic> ToList(this IDynamicSelectQueryBuilder b)
{
return b.Execute().ToList();
}
/// <summary>Turns an <see cref="IDynamicSelectQueryBuilder"/> to a Dynamic list of things with specified type.</summary>
/// <typeparam name="T">Type of object to map on.</typeparam>
/// <param name="b">Ready to execute builder.</param>
/// <returns>List of things.</returns>
public static List<T> ToList<T>(this IDynamicSelectQueryBuilder b) where T : class
{
return b.Execute<T>().ToList();
}
/// <summary>Turns the dictionary into an ExpandoObject.</summary> /// <summary>Turns the dictionary into an ExpandoObject.</summary>
/// <param name="d">Dictionary to convert.</param> /// <param name="d">Dictionary to convert.</param>
/// <returns>Converted dictionary.</returns> /// <returns>Converted dictionary.</returns>

View File

@@ -0,0 +1,128 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Data;
using System.Runtime.Serialization;
using System.Text;
namespace DynamORM
{
/// <summary>Dynamic query exception.</summary>
public class DynamicQueryException : Exception, ISerializable
{
/// <summary>Gets the dumped command which failed.</summary>
public string Command { get; private set; }
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="command">The command which failed.</param>
public DynamicQueryException(IDbCommand command = null)
: base("Error executing command.")
{
if (command != null)
{
var sb = new StringBuilder();
command.Dump(sb);
Command = sb.ToString();
}
}
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="message">The message.</param>
/// <param name="command">The command which failed.</param>
public DynamicQueryException(string message, IDbCommand command = null)
: base(message)
{
SetCommand(command);
}
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="innerException">The inner exception.</param>
/// <param name="command">The command which failed.</param>
public DynamicQueryException(Exception innerException, IDbCommand command = null)
: base("Error executing command.", innerException)
{
SetCommand(command);
}
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="message">The message.</param>
/// <param name="innerException">The inner exception.</param>
/// <param name="command">The command which failed.</param>
public DynamicQueryException(string message, Exception innerException, IDbCommand command = null)
: base(message, innerException)
{
SetCommand(command);
}
/// <summary>Initializes a new instance of the
/// <see cref="DynamicQueryException"/> class.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" />
/// that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" />
/// that contains contextual information about the source or destination.</param>
public DynamicQueryException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
Command = info.GetString("Command");
}
/// <summary>When overridden in a derived class, sets the
/// <see cref="T:System.Runtime.Serialization.SerializationInfo" />
/// with information about the exception.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" />
/// that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" />
/// that contains contextual information about the source or destination.</param>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Read="*AllFiles*" PathDiscovery="*AllFiles*" />
/// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="SerializationFormatter" />
/// </PermissionSet>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
if (!string.IsNullOrEmpty(Command))
info.AddValue("Command", Command);
}
private void SetCommand(IDbCommand command)
{
if (command != null && (!(command is DynamicCommand) || ((command is DynamicCommand) && !(command as DynamicCommand).IsDisposed)))
{
var sb = new StringBuilder();
command.Dump(sb);
Command = sb.ToString();
}
}
}
}

View File

@@ -194,7 +194,7 @@ namespace DynamORM
/// });</code> /// });</code>
/// <code>x.Delete(where: new { id = 14, code = 14 });</code> /// <code>x.Delete(where: new { id = 14, code = 14 });</code>
/// </example> /// </example>
public class DynamicTable : DynamicObject, IDisposable, ICloneable public class DynamicTable : DynamicObject, IExtendedDisposable, ICloneable
{ {
private static HashSet<string> _allowedCommands = new HashSet<string> private static HashSet<string> _allowedCommands = new HashSet<string>
{ {
@@ -243,6 +243,7 @@ namespace DynamORM
/// <param name="keys">Override keys in schema.</param> /// <param name="keys">Override keys in schema.</param>
public DynamicTable(DynamicDatabase database, string table = "", string owner = "", string[] keys = null) public DynamicTable(DynamicDatabase database, string table = "", string owner = "", string[] keys = null)
{ {
IsDisposed = false;
Database = database; Database = database;
TableName = Database.StripName(table); TableName = Database.StripName(table);
OwnerName = Database.StripName(owner); OwnerName = Database.StripName(owner);
@@ -260,15 +261,20 @@ namespace DynamORM
if (type == null) if (type == null)
throw new ArgumentNullException("type", "Type can't be null."); throw new ArgumentNullException("type", "Type can't be null.");
Database = database; IsDisposed = false;
Database = database;
TableType = type; TableType = type;
var mapper = DynamicMapperCache.GetMapper(type); var mapper = DynamicMapperCache.GetMapper(type);
if (mapper != null) if (mapper != null)
{
TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ? TableName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ?
type.Name : mapper.Table.Name; type.Name : mapper.Table.Name;
OwnerName = mapper.Table == null || string.IsNullOrEmpty(mapper.Table.Name) ?
type.Name : mapper.Table.Name;
}
BuildAndCacheSchema(keys); BuildAndCacheSchema(keys);
} }
@@ -995,7 +1001,7 @@ namespace DynamORM
#endregion Universal Dynamic Invoker #endregion Universal Dynamic Invoker
#region IDisposable Members #region IExtendedDisposable Members
/// <summary>Performs application-defined tasks associated with /// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary> /// freeing, releasing, or resetting unmanaged resources.</summary>
@@ -1007,9 +1013,14 @@ namespace DynamORM
Database.RemoveFromCache(this); Database.RemoveFromCache(this);
Database = null; Database = null;
} }
IsDisposed = true;
} }
#endregion IDisposable Members /// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
#endregion IExtendedDisposable Members
#region ICloneable Members #region ICloneable Members

View File

@@ -28,11 +28,12 @@
using System; using System;
using System.Data; using System.Data;
using DynamORM.Helpers;
namespace DynamORM namespace DynamORM
{ {
/// <summary>Helper class to easy manage transaction.</summary> /// <summary>Helper class to easy manage transaction.</summary>
public class DynamicTransaction : IDbTransaction, IDisposable public class DynamicTransaction : IDbTransaction, IExtendedDisposable
{ {
private DynamicDatabase _db; private DynamicDatabase _db;
private DynamicConnection _con; private DynamicConnection _con;
@@ -48,6 +49,7 @@ namespace DynamORM
/// <param name="disposed">This action is invoked when transaction is disposed.</param> /// <param name="disposed">This action is invoked when transaction is disposed.</param>
internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed) internal DynamicTransaction(DynamicDatabase db, DynamicConnection con, bool singleTransaction, IsolationLevel? il, Action disposed)
{ {
IsDisposed = false;
_db = db; _db = db;
_con = con; _con = con;
_singleTransaction = singleTransaction; _singleTransaction = singleTransaction;
@@ -125,6 +127,8 @@ namespace DynamORM
/// <summary>Gets <see cref="System.Data.IsolationLevel"/> for this transaction.</summary> /// <summary>Gets <see cref="System.Data.IsolationLevel"/> for this transaction.</summary>
public IsolationLevel IsolationLevel { get; private set; } public IsolationLevel IsolationLevel { get; private set; }
#region IExtendedDisposable Members
/// <summary>Performs application-defined tasks associated with /// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary> /// freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose() public void Dispose()
@@ -133,6 +137,13 @@ namespace DynamORM
if (_disposed != null) if (_disposed != null)
_disposed(); _disposed();
IsDisposed = true;
} }
/// <summary>Gets a value indicating whether this instance is disposed.</summary>
public bool IsDisposed { get; private set; }
#endregion IExtendedDisposable Members
} }
} }