Faking SqlConnection and embedded methods in the NUnit Test, using FakeItEasy - c#

I have the following class and methods, that will be connecting to a DB, but for testing, I do not need the real connection and would need to fake it. We're using FakeItEasy for this.:
public abstract class HandlerBase
{
public string errorMessage;
private MyActionsDataModel Action
{
get
{
if (_action == null)
{
_action = new MyActionsDataModel();
using (var connection = new SqlConnection(Constants.Connections.MyDatabase))
{
connection.Open();
using (var transaction = connection.BeginTransaction(IsolationLevel.Serializable))
{
_action.Id = connection.QuerySingle<int>("UpdateAction", transaction: transaction, commandType: CommandType.StoredProcedure, param: Action);
transaction.Commit();
}
}
}
return _action;
}
}
private MyActionsDataModel _action;
public void RecordFailure(AggregateException ex)
{
Console.WriteLine("A failure happened:");
Console.WriteLine(JsonConvert.SerializeObject(ex));
errorMessage = "Inner Exception\r\n" + ex.Message;
Action.ErrorOccurredOnUtc = DateTimeOffset.UtcNow;
Action.ErrorType = ex.GetType().FullName;
Action.ErrorMessage = errorMessage;
SaveAction();
}
private void SaveAction()
{
using (var connection = new SqlConnection(Constants.Connections.MyDatabase))
{
connection.Open();
using (var transaction = connection.BeginTransaction(IsolationLevel.Serializable))
{
connection.Execute("UpdateAction", transaction: transaction,
commandType: CommandType.StoredProcedure, param: Action);
transaction.Commit();
}
}
}
}
another class that I'll be calling in my tests:
public class MyHandlerType : HandlerBase
{
private readonly MyTracker _myTracker;
public MyHandlerType(MyTracker myTracker) : base()
{
_myTracker = myTracker;
}
}
What I want is to Fake the Action parameter and also SaveAction method.
Here is the Test I have for it, but not sure how to make the Fake part.
public class HandlerTests
{
[TestCase]
public void Test_RecordFailure()
{
var innerMessage = "Throw AppException for UnitTest.";
var parentMessage = "Throw AggregationException for UnitTest.";
var testHandler = new MyHandlerType(null);
var innerException = new ApplicationException(innerMessage);
var parentException = new AggregateException(parentMessage, innerException);
testHandler.RecordFailure(parentException);
var includeInnerMessage = testHandler.errorMessage.Contains(innerMessage);
var includeParentMessage = testHandler.errorMessage.Contains(parentMessage);
Assert.IsTrue(includeInnerMessage);
Assert.IsTrue(includeParentMessage);
}
}

The current class is tightly coupled to implementation concerns that make testing it in isolation difficult.
Consider refactoring the class
public abstract class HandlerBase {
private readonly Lazy<MyActionsDataModel> model;
private readonly IDbConnectionFactory connectionFactory;
protected HandlerBase(IDbConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
model = new Lazy<MyActionsDataModel>(() => {
MyActionsDataModel action = new MyActionsDataModel();
using (DbConnection connection = this.connectionFactory.Create()) {
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
action.Id = connection.QuerySingle<int>("UpdateAction",
transaction: transaction,
commandType: CommandType.StoredProcedure,
param: action);
transaction.Commit();
}
}
return action;
});
}
public string ErrorMessage;
public void RecordFailure(AggregateException ex) {
Console.WriteLine("A failure happened:");
Console.WriteLine(JsonConvert.SerializeObject(ex));
ErrorMessage = "Inner Exception\r\n" + ex.Message;
MyActionsDataModel action = model.Value;
action.ErrorOccurredOnUtc = DateTimeOffset.UtcNow;
action.ErrorType = ex.GetType().FullName;
action.ErrorMessage = ErrorMessage;
saveAction(action);
}
private void saveAction(MyActionsDataModel action) {
using (DbConnection connection = connectionFactory.Create()) {
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
connection.Execute("UpdateAction", transaction: transaction,
commandType: CommandType.StoredProcedure, param: action);
transaction.Commit();
}
}
}
}
Note the introduction of an explicit dependency
public interface IDbConnectionFactory {
DbConnection Create();
}
which can have an implementation
// Connection Factory method
public DbConnection Create() {
DbConnection connection = new SqlConnection(Constants.Connections.MyDatabase);
return connection;
}
When testing the factory can be mocked to behave as desired when the subject under test is exercised.

Here is my new code (based on the suggestion from #Nkosi) and the test part:
CODE:
public abstract class HandlerBase {
private readonly Lazy<MyActionsDataModel> model;
private readonly IDbConnectionFactory connectionFactory;
protected HandlerBase(IDbConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
model = new Lazy<MyActionsDataModel>(() => {
MyActionsDataModel action = new MyActionsDataModel();
using (DbConnection connection = this.connectionFactory.Create()) {
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
action.Id = connection.QuerySingle<int>("UpdateAction",
transaction: transaction,
commandType: CommandType.StoredProcedure,
param: action);
transaction.Commit();
}
}
return action;
});
}
public string ErrorMessage;
public void RecordFailure(AggregateException ex) {
Console.WriteLine("A failure happened:");
Console.WriteLine(JsonConvert.SerializeObject(ex));
ErrorMessage = "Inner Exception\r\n" + ex.Message;
MyActionsDataModel action = model.Value;
action.ErrorOccurredOnUtc = DateTimeOffset.UtcNow;
action.ErrorType = ex.GetType().FullName;
action.ErrorMessage = ErrorMessage;
saveAction(action);
}
private void saveAction(MyActionsDataModel action) {
using (DbConnection connection = new SqlConnection(Constants.Connections.MyDatabase)) {
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable)) {
connection.Execute("UpdateAction", transaction: transaction,
commandType: CommandType.StoredProcedure, param: action);
transaction.Commit();
}
}
}
}
public interface IDbConnectionFactory {
DbConnection Create();
}
// Connection Factory method
public DbConnection Create() {
DbConnection connection = new SqlConnection(Constants.Connections.MyDatabase);
return connection;
}
public class MyHandlerType : HandlerBase
{
private readonly IDbConnectionFactory _connectionFactory;
public MyHandlerType(IDbConnectionFactory connectionFactory) : base(connectionFactory)
{
_connectionFactory = connectionFactory;
}
}
TEST:
public class HandlerTests
{
protected MyHandlerType _subjectUnderTest;
protected HandlerBase.IDbConnectionFactory _fakeConnectionFactory;
[SetUp]
public void Setup()
{
_fakeConnectionFactory = A.Fake<HandlerBase.IDbConnectionFactory>();
A.CallTo(() => _fakeConnectionFactory.Create()).Returns<DbConnection>(new SqlConnection(Constants.Connections.MyDatabase));
_subjectUnderTest = new MyHandlerType(_fakeConnectionFactory);
}
[TestCase]
public void Test_RecordFailure()
{
var innerMessage = "Throw AppException for UnitTest.";
var parentMessage = "Throw AggregationException for UnitTest.";
var innerException = new ApplicationException(innerMessage);
var parentException = new AggregateException(parentMessage, innerException);
_subjectUnderTest.RecordFailure(parentException);
var includeInnerMessage = testHandler.errorMessage.Contains(innerMessage);
var includeParentMessage = testHandler.errorMessage.Contains(parentMessage);
Assert.IsTrue(includeInnerMessage);
Assert.IsTrue(includeParentMessage);
}
}

Related

Get source of an call function, invocation or task execution

In my app, I use an class (MySqlClass) to execute and download data from my database.
public class MySqlClass
{
public void ExecuteQuery(string query) { /* ... */ }
public DataSet GetDataSet(string query) { /* ... */ }
public void Transaction(Action queryToCommit, Action whenRollback) { /* ... */ }
}
For example :
public class MyApp
{
List<MyObjectClass> myList = MyObjectClass.GetMyObjectClass("white");
}
public class MyObjectClass
{
private static MySqlClass sqlConn = new MySqlClass();
public static List<MyObjectClass> GetMyObjectClass(string color)
{
List<MyObjectClass> obj = new List<MyObjectClass>();
using (DataSet ds = sqlConn.GetDataSet(" ... my query ... "))
{
foreach (DataRow dr in ds.Tables[0].Rows)
{
obj.Add(ConvertDataRow(dr));
}
}
return obj;
}
public static MyObjectClass ConvertDataRow(DataRow dr) { /* ... */ }
}
For some criticals utilizations, I want use transaction WITHOUT modify originals functions.
I developed for this "Transaction" function in MySqlClass :
public void Transaction(Action queryToCommit, Action whenRollback)
{
CancellationTokenSource cts = new CancellationTokenSource();
try
{
Task executeAction = new Task(new Action(() =>
{
queryToCommit.Invoke(); // user code executed here
cts.Token.ThrowIfCancellationRequested();
}),
cts.Token
);
executeAction.Start();
executeAction.Wait(cts.Token);
Commit();
}
catch (Exception)
{
Rollback();
whenRollback.Invoke();
/* ... */
}
}
In my app :
public class MyApp
{
MySqlClass sqlConn = new MySqlClass();
List<MyObjectClass> myList = MyObjectClass.GetMyObjectClass("white");
private void WithoutTransaction()
{
MyObjectClass objA = new MyObjectClass();
MyObjectClass objB = new MyObjectClass();
/* ... */
if (...)
{
objA.Insert();
}
else
{
objA.Delete();
objB.Update();
// Exception raised in objB.Update();
// Data correspond to objA in database are lost
}
}
private void WithTransaction()
{
MyObjectClass objA = new MyObjectClass();
MyObjectClass objB = new MyObjectClass();
sqlConn.Transaction(
() => {
if (...)
{
objA.Insert();
}
else
{
objA.Delete();
objB.Update(); // Exception raised in objB.Update()
}
},
CallErrorLogFunction()
);
}
}
My problem :
How i can know, when I use GetDataSet(), ExecuteQuery() or whatever, that I'm in a transaction function ?
StackTrace and StackFrame indicate invocation but not the source function of invocation.
I can't use Thread (for current thread ID) because my colleagues could make operations on the GUI.
I thought to lock instruction to check if in a transaction but I no idea to implement the code
If you have an idea ... :)
Thanks !
EDIT March 19'21 :
public class MySqlClass
{
// They are initialized before use "ExecuteQuery()"
public MyTransactionClass transac;
public SqlConnection conn;
public void ExecuteQuery(string query, Dictionary<string, object> dict = null)
{
SqlDataAdapter da;
try
{
if (conn.State = ConnectionState.Closed)
{
conn.Open();
}
da = new SqlDataAdapter(query, conn);
/* section of code for parameters queries */
if (dict != null) { /* ... */ }
if (IsTransaction())
{
da.SelectCommand.Transaction = transac.TransacSql;
}
da.SelectCommand.ExecuteNonQuery();
}
catch (Exception)
{
throw;
}
finally
{
if (da != null)
{
da.Dispose();
}
}
}
public DataSet GetDataSet(string query) { /* ... */ }
private bool IsTransaction()
{
bool r = false;
if (transac != null)
{
/*
* Check if in StackTrace, "Transaction" of "MyTransactionClass" is in the list
*/
StackTrace st = new StackTrace(true);
StackFrame sf;
for (int i = 0; i < st.FrameCount; i++)
{
sf = st.GetFrame(i);
if (sf.GetMethod().Name == MyTransactionClass.FunctionName_Transaction)
{
r = true;
break;
}
}
}
return r;
}
}
public class MyTransactionClass
{
public static readonly string FunctionName_Transaction = nameof(Transaction);
public SqlTransaction TransacSql;
public void Transaction(Action queryToCommit, Action whenRollback)
{
CancellationTokenSource cts = new CancellationTokenSource();
try
{
Task executeAction = new Task(new Action(() =>
{
queryToCommit.Invoke();
cts.Token.ThrowIfCancellationRequested();
}),
cts.Token
);
executeAction.Start();
executeAction.Wait(cts.Token);
Commit();
}
catch (Exception)
{
Rollback();
whenRollback.Invoke();
/* ... */
}
}
void Commit() { }
void Rollback() { }
}
EDIT March 31'21 :
I make a unit test, with different use cases :
with just a transaction
a transaction and a Action
a transaction with a Action in a Task
Is the last case (similar to I want), System.Transactions.Transaction.Current is null.
[TestMethod]
public void TestTransactionScope()
{
Console.WriteLine($"Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
using (TransactionScope scope = new TransactionScope())
{
Console.WriteLine($"(scope) Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
MyFunction("direct call");
}
// if I use a invocation
Action<string> fnctTransac = new Action<string>((msg) => MyFunction(msg));
using (TransactionScope scope = new TransactionScope())
{
Console.WriteLine($"(scope) Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
fnctTransac.Invoke("with invocation");
}
// if I use invocation with a Task, similar to my use
using (TransactionScope scope = new TransactionScope())
{
Console.WriteLine($"(scope) Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
Task t = new Task(() => fnctTransac.Invoke("with invocation, from a Task"));
t.Start();
Task.WaitAll(t);
}
}
public void MyFunction(string msg)
{
Console.WriteLine($"{msg} - Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
}
Logs :
Transaction ID :
(scope) Transaction ID : 1c0127fe-44d5-4954-826c-ece6ad261ee5:1
direct call - Transaction ID : 1c0127fe-44d5-4954-826c-ece6ad261ee5:1
(scope) Transaction ID : 1c0127fe-44d5-4954-826c-ece6ad261ee5:2
with invocation - Transaction ID : 1c0127fe-44d5-4954-826c-ece6ad261ee5:2
(scope) Transaction ID : 1c0127fe-44d5-4954-826c-ece6ad261ee5:3
with invocation, from a Task - Transaction ID :
EDIT April 16'21
With TransactionScope :
Source :
public class MySqlClass
{
public MyTransactionClass transac;
public SqlConnection conn;
public void ExecuteQuery(string query, Dictionary<string, object> dict = null) { /* ... */ }
public DataSet GetDataSet(string query) { /* ... */ }
private bool IsTransaction()
{
bool r = false;
string idTransaction = Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier
if (
transac == null &&
!string.IsNullOrEmpty(idTransaction)
)
{
transac = MyTransactionClass.GetTransaction(idTransaction)
}
return r;
}
}
public class MyTransactionClass
{
public const int MAX_TIME_TRANSAC_SEC = 5
public static readonly string FunctionName_Transaction = nameof(Transaction);
public SqlTransaction TransacSql;
public static void Transaction(Action queryToCommit, Action whenRollback)
{
CancellationTokenSource cts = new CancellationTokenSource();
try
{
Task executeAction = new Task(new Action(() =>
{
queryToCommit.Invoke();
cts.Token.ThrowIfCancellationRequested();
}),
cts.Token
);
using (TransactionScope scope = new TransactionScope(
TransactionScopeOption.Required,
New TimeSpan(0, 0, MAX_TIME_TRANSAC_SEC),
TransactionScopeAsyncFlowOption.Enabled
)
{
executeAction.Start();
executeAction.Wait(cts.Token);
scope.Complete();
Commit();
}
}
catch (Exception)
{
Rollback();
whenRollback.Invoke();
/* ... */
}
}
void Commit() { }
void Rollback() { }
}
Tests :
[TestMethod]
public void E_TransactionScope()
{
Console.WriteLine($"Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
Console.WriteLine($"(scope) Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
MyFunction("direct call");
}
Console.WriteLine();
// if I use a invocation
Action<string> fnctTransac = new Action<string>((msg) => MyFunction(msg));
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
Console.WriteLine($"(scope) Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
fnctTransac.Invoke("with invocation");
}
Console.WriteLine();
// if I use invocation with a Task, similar to my use
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
Console.WriteLine($"(scope) Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
Task t = new Task(() => fnctTransac.Invoke("with invocation, from a Task"));
t.Start();
Task.WaitAll(t);
}
Console.WriteLine();
// ultimate use case
Action userCode = () => MyFunction_First("last use case");
Task tk;
using (TransactionScope scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
Console.WriteLine($"(scope) Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
// TransactionID not available when userCode is defined out of using instruction and called directly
// userCode.Start();
tk = new Task(new Action(() => userCode.Invoke()));
tk.Start();
tk.Wait();
}
Console.WriteLine("-------------------------");
}
public void MyFunction(string msg)
{
Console.WriteLine($"{msg} - Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
}
public void MyFunction_First(string msg)
{
Console.WriteLine($"MyFunction_First - {msg} - Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
Task t = new Task(() => MyFunction_Second(msg));
t.Start();
Task.WaitAll(t);
}
public void MyFunction_Second(string msg)
{
Console.WriteLine($"MyFunction_Second - {msg} - Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
Thread th = new Thread(new ThreadStart(() => MyFunction_Third(msg)));
th.Start();
th.Join();
}
public void MyFunction_Third(string msg)
{
using (TransactionScope scope = new TransactionScope())
{
Console.WriteLine($"MyFunction_Third - {msg} - Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
Task t = new Task(() => MyFunction_Fourth(msg));
t.Start();
Task.WaitAll(t);
}
}
public void MyFunction_Fourth(string msg)
{
Console.WriteLine($"MyFunction_Fourth - {msg} - Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
Task t = new Task(() => MyFunction_Last(msg));
t.Start();
Task.WaitAll(t);
}
public void MyFunction_Last(string msg)
{
Console.WriteLine($"MyFunction_Last - {msg} - Transaction ID : {System.Transactions.Transaction.Current?.TransactionInformation.LocalIdentifier}");
}
Logs :
Transaction ID :
(scope) Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:1
direct call - Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:1
(scope) Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:2
with invocation - Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:2
(scope) Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:3
with invocation, from a Task - Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:3
(scope) Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:4
MyFunction_First - last use case - Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:4
MyFunction_Second - last use case - Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:4
MyFunction_Third - last use case - Transaction ID : 99e1d658-27d8-404d-b57e-d6ead2e2308e:4
MyFunction_Fourth - last use case - Transaction ID :
MyFunction_Last - last use case - Transaction ID :
Have you already considered using the TransactionScope class?
I'm not sure, but with that, you might not need to know whether you are in a transaction or not inside your ExecuteQuery and GetDataSet methods. It might just simply work. ;)
Your Transaction method could look something like this:
public void Transaction(Action queryToCommit, Action whenRollback = null)
{
if (queryToCommit == null)
{
throw new ArgumentNullException(nameof(queryToCommit));
}
CancellationTokenSource cts = new CancellationTokenSource();
Task executeAction = new Task(new Action(() =>
{
queryToCommit.Invoke(); // user code executed here
cts.Token.ThrowIfCancellationRequested();
}),
cts.Token
);
try
{
using (var scope = new System.Transactions.TransactionScope())
{
executeAction.Start();
executeAction.Wait(cts.Token);
scope.Complete();
}
}
catch (Exception)
{
whenRollback.Invoke();
/* ... */
}
}
Note that I haven't tested this. I just based it on your code and the sample in the documentation, so it probably needs some additional work.
Edit:
Based on recent comments, I added a code snippet that shows how I would personally implement your logic:
public class MySqlClass
{
private string connectionString;
public MySqlClass(string connectionString)
{
this.connectionString = connectionString;
}
public int ExecuteQuery(string query, params SqlParameter[] parameters)
{
using (SqlConnection con = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(query, con))
{
con.Open();
cmd.Parameters.AddRange(parameters);
return cmd.ExecuteNonQuery();
}
}
public DataSet GetDataSet(string query, params SqlParameter[] parameters)
{
using (SqlConnection con = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(query, con))
{
con.Open();
cmd.Parameters.AddRange(parameters);
DataSet ds = new DataSet();
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(ds);
}
return ds;
}
}
public DataTable GetDataTable(string query, params SqlParameter[] parameters)
{
DataSet ds = GetDataSet(query, parameters);
return ds.Tables[0];
}
public static void Transaction(Action queryToCommit, Action whenRollback)
{
if (queryToCommit == null)
{
throw new ArgumentNullException(nameof(queryToCommit));
}
CancellationTokenSource cts = new CancellationTokenSource();
Task executeAction = new Task(new Action(() =>
{
queryToCommit.Invoke(); // user code executed here
cts.Token.ThrowIfCancellationRequested();
}),
cts.Token
);
try
{
using (var scope = new System.Transactions.TransactionScope())
{
executeAction.Start();
executeAction.Wait(cts.Token);
scope.Complete();
}
}
catch
{
whenRollback.Invoke();
/* ... */
}
}
public static SqlParameter CreateParameter(string parameterName, SqlDbType dbType, object value)
{
SqlParameter parameter = new SqlParameter(parameterName, dbType);
parameter.Value = value;
return parameter;
}
public static SqlParameter CreateParameter(string parameterName, SqlDbType dbType, int size, object value)
{
SqlParameter parameter = new SqlParameter(parameterName, dbType, size);
parameter.Value = value;
return parameter;
}
}
/*
CREATE TABLE [MyObjects] (
[Id] INT IDENTITY NOT NULL,
[Color] VARCHAR(20) NOT NULL,
--...
CONSTRAINT [PK_MyObjects] PRIMARY KEY ([Id])
);
*/
public class MyObjectModel
{
// Sample private fields
public int? Id { get; set; }
public string Color { get; set; }
/* ... */
}
public class MyObjectRepository
{
private MySqlClass sqlConn;
public MyObjectRepository(MySqlClass sqlConn)
{
this.sqlConn = sqlConn;
}
public List<MyObjectModel> GetMyObjects(string colorFilter)
{
List<MyObjectModel> obj = new List<MyObjectModel>();
string query = (string.IsNullOrWhiteSpace(colorFilter))
? "SELECT [Id], [Color] FROM [MyObjects];"
: "SELECT [Id], [Color] FROM [MyObjects] WHERE [Color] LIKE '%' + #Color + '%';";
using (DataTable dt = sqlConn.GetDataTable(query,
MySqlClass.CreateParameter("#Color", SqlDbType.VarChar, 20, colorFilter)))
{
foreach (DataRow dr in dt.Rows)
{
obj.Add(ConvertDataRow(dr));
}
}
return obj;
}
private static MyObjectModel ConvertDataRow(DataRow dr)
{
return new MyObjectModel
{
/* set class properties here... */
Id = dr.Field<int>("Id"),
Color = dr.Field<string>("Color")
/* ... */
};
}
public void Insert(MyObjectModel model)
{
if (model.Id.HasValue)
{
return;
}
using (DataTable dt = sqlConn.GetDataTable("INSERT INTO [MyObjects] ([Color]) OUTPUT INSERTED.[Id] VALUES (#Color);",
MySqlClass.CreateParameter("#Color", SqlDbType.VarChar, 20, model.Color)))
{
model.Id = (int)dt.Rows[0]["Id"];
}
}
public int? Update(MyObjectModel model)
{
if (!model.Id.HasValue)
{
return null;
}
return sqlConn.ExecuteQuery("UPDATE [MyObjects] SET [Color] = #Color WHERE [Id] = #Id;",
MySqlClass.CreateParameter("#Id", SqlDbType.Int, model.Id),
MySqlClass.CreateParameter("#Color", SqlDbType.VarChar, 20, model.Color));
}
public int Delete(int id)
{
return sqlConn.ExecuteQuery("DELETE FROM [MyObjects] WHERE [Id] = #Id;",
MySqlClass.CreateParameter("#Id", SqlDbType.Int, id));
}
}
public class MyApp
{
private MyObjectRepository repo;
public MyApp()
{
MySqlClass sqlConn = new MySqlClass(" ... connection string here ... ");
repo = new MyObjectRepository(sqlConn);
}
List<MyObjectModel> GetMyObjects(string colorFilter = "white")
{
return repo.GetMyObjects(colorFilter);
}
private void WithoutTransaction()
{
MyObjectModel objA = new MyObjectModel();
MyObjectModel objB = new MyObjectModel();
/* ... */
if (true)
{
repo.Insert(objA);
}
else
{
repo.Delete(objA.Id.Value);
repo.Update(objB);
// Exception raised in objB.Update();
// Data correspond to objA in database are lost
}
}
private void WithTransaction()
{
MyObjectModel objA = new MyObjectModel();
MyObjectModel objB = new MyObjectModel();
MySqlClass.Transaction(
() =>
{
if (true)
{
repo.Insert(objA);
}
else
{
repo.Delete(objA.Id.Value);
repo.Update(objB); // Exception still raised now???
}
},
CallErrorLogFunction
);
}
private void CallErrorLogFunction()
{
/* ... */
}
}
From recent edits to your question, I am not sure if this would be a valid solution, however. This is the best I could come up with so far. Perhaps you can extract something useful from it anyway. (I haven't tested it, so despite me being careful, the code might contain some stupid mistakes.)

How to mocking DbRawSqlQuery<int> result?

I created a method for check that in db has a stored procedure.
public class StoredProcedure : IStoredProcedure
{
private readonly IDbContextProvider<MyDbContext> _dbContextProvider;
public StoredProcedure(IDbContextProvider<MyDbContext> dbContextProvider)
{
_dbContextProvider = dbContextProvider;
}
public bool ExistsStoredProcedure(string procedureName)
{
var query = string.Format(
"SELECT COUNT(*) FROM [sys].[objects] WHERE [type_desc] = 'SQL_STORED_PROCEDURE' AND [name] = '{0}';",
procedureName);
var request = _dbContextProvider.DbContext.Database.SqlQuery<int>(query).Single();
return request > 0 ? true : throw new UserFriendlyException(
$"Хранимая процедура {procedureName} не найдена в БД {_dbContextProvider.DbContext.Database.Connection.Database}");
}
}
Also, I want to write a unit test for him.
public class StoredProcedureTests
{
private readonly IStoredProcedure _storedProcedure;
private readonly Mock<IDbContextProvider<MyDbContext>> _mockDbProvider;
public StoredProcedureTests()
{
_mockDbProvider = new Mock<IDbContextProvider<MyDbContext>>();
_storedProcedure = new StoredProcedure(_mockDbProvider.Object);
}
[Fact]
public void CheckValueIfStoredProcedureExist()
{
const int count = 1;
var rawMock = new Mock<DbRawSqlQuery<int>>();
rawMock.Setup(i => i.Single()).Returns(count);
_mockDbProvider.Setup(i => i.DbContext.Database.SqlQuery<int>(It.IsAny<string>())).Returns(rawMock.Object);
var result = _storedProcedure.ExistsStoredProcedure(string.Empty);
Assert.True(result);
}
}
But, i get an error, when i try rawMock.Setup
try
{
rawMock.Setup(i => i.Single()).Returns(count);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw;
}
Invalid setup on an extension method: i => i.Single()
How to correctly write this stub?
UPD I try like advised Johnny
try
{
IEnumerable<int> list = new List<int> {1};
var mq = new Mock<DbRawSqlQuery<int>>();
mq.Setup(i => i.GetEnumerator()).Returns(list.GetEnumerator);
_mockDbProvider.Setup(i => i.DbContext.Database.SqlQuery<int>(It.IsAny<string>())).Returns(mq.Object);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw;
}
And i have a new error
Invalid setup on a non-virtual (overridable in VB) member: i => i.DbContext.Database.SqlQuery(It.IsAny(), new[] { })

C#: How to Wrap my Unit of Work code in my repository classes

See my repository code
public abstract class AdoRepository<T> where T : class
{
private static SqlConnection _connection;
public AdoRepository(string connectionString)
{
_connection = new SqlConnection(connectionString);
}
public virtual T PopulateRecord(SqlDataReader reader)
{
return null;
}
public virtual void GetDataCount(int count)
{
}
protected IEnumerable<T> GetRecords(SqlCommand command)
{
var list = new List<T>();
command.Connection = _connection;
_connection.Open();
try
{
var reader = command.ExecuteReader();
try
{
while (reader.Read())
{
list.Add(PopulateRecord(reader));
}
reader.NextResult();
if (reader.HasRows)
{
while (reader.Read())
{
GetDataCount(Convert.ToInt32(reader["Count"].ToString()));
}
}
}
finally
{
// Always call Close when done reading.
reader.Close();
}
}
catch(Exception ex)
{
string Msg = ex.Message;
}
finally
{
_connection.Close();
}
return list;
}
protected T GetRecord(SqlCommand command)
{
T record = null;
command.Connection = _connection;
_connection.Open();
try
{
var reader = command.ExecuteReader();
try
{
while (reader.Read())
{
record = PopulateRecord(reader);
break;
}
}
finally
{
// Always call Close when done reading.
reader.Close();
}
}
finally
{
_connection.Close();
}
return record;
}
protected IEnumerable<T> ExecuteStoredProc(SqlCommand command)
{
var list = new List<T>();
command.Connection = _connection;
command.CommandType = CommandType.StoredProcedure;
_connection.Open();
try
{
var reader = command.ExecuteReader();
try
{
while (reader.Read())
{
var record = PopulateRecord(reader);
if (record != null) list.Add(record);
}
}
finally
{
// Always call Close when done reading.
reader.Close();
}
}
finally
{
_connection.Close();
}
return list;
}
}
public class StudentRepository : AdoRepository<Student>
{
public int DataCounter { get; set; }
public StudentRepository(string connectionString)
: base(connectionString)
{
}
public IEnumerable<Student> GetAll()
{
// DBAs across the country are having strokes
// over this next command!
using (var command = new SqlCommand("SELECT ID, FirstName,LastName,IsActive,StateName,CityName FROM vwListStudents"))
{
return GetRecords(command);
}
}
public Student GetById(string id)
{
// PARAMETERIZED QUERIES!
using (var command = new SqlCommand("SELECT ID, FirstName,LastName,IsActive,StateName,CityName FROM vwListStudents WHERE Id = #id"))
{
command.Parameters.Add(new ObjectParameter("id", id));
return GetRecord(command);
}
}
public IEnumerable<Student> GetStudents(int StartIndex, int EndIndex, string sortCol, string sortOrder)
{
string strSQL = "SELECT * FROM vwListStudents WHERE ID >=" + StartIndex + " AND ID <=" + EndIndex;
strSQL += " ORDER BY " + sortCol + " " + sortOrder;
strSQL += ";SELECT COUNT(*) AS Count FROM vwListStudents";
var command = new SqlCommand(strSQL);
return GetRecords(command);
}
public override Student PopulateRecord(SqlDataReader reader)
{
return new Student
{
ID = Convert.ToInt32(reader["ID"].ToString()),
FirstName = reader["FirstName"].ToString(),
LastName = reader["LastName"].ToString(),
IsActive = Convert.ToBoolean(reader["IsActive"]),
StateName = reader["StateName"].ToString(),
CityName = reader["CityName"].ToString()
};
}
public override void GetDataCount(int count)
{
DataCounter = count;
}
}
this way unit of work code added
public class UnitOfWorkFactory
{
public static IUnitOfWork Create()
{
var connection = new SqlConnection(ConfigurationManager.ConnectionStrings("MyDb").ConnectionString);
connection.Open();
return new AdoNetUnitOfWork(connection, true);
}
}
public class AdoNetUnitOfWork : IUnitOfWork
{
public AdoNetUnitOfWork(IDbConnection connection, bool ownsConnection)
{
_connection = connection;
_ownsConnection=ownsConnection;
_transaction = connection.BeginTransaction();
}
public IDbCommand CreateCommand()
{
var command = _connection.CreateCommand();
command.Transaction = _transaction;
return command;
}
public void SaveChanges()
{
if (_transaction == null)
throw new InvalidOperationException("Transaction have already been commited. Check your transaction handling.");
_transaction.Commit();
_transaction = null;
}
public void Dispose()
{
if (_transaction != null)
{
_transaction.Rollback();
_transaction = null;
}
if (_connection != null && _ownsConnection)
{
_connection.Close();
_connection = null;
}
}
}
using (var uow = UnitOfWorkFactory.Create())
{
var repos = new UserRepository(uow);
uow.SaveChanges();
}
public class UserRepository
{
private AdoNetUnitOfWork _unitOfWork;
public UserRepository(IUnitOfWork uow)
{
if (uow == null)
throw new ArgumentNullException("uow");
_unitOfWork = uow as AdoNetUnitOfWork;
if (_unitOfWork == null)
throw new NotSupportedException("Ohh my, change that UnitOfWorkFactory, will you?");
}
public User Get(Guid id)
{
using (var cmd = _unitOfWork.CreateCommand())
{
cmd.CommandText = "SELECT * FROM Users WHERE Id = #id");
cmd.AddParameter("id", id);
// uses an extension method which I will demonstrate in a
// blog post in a couple of days
return cmd.FirstOrDefault<User>();
}
}
}
but i want to add unit of work code in my repository class. may be in AdoRepository class or StudentRepository class as a result i do not have to write the below code again and again.
using (var uow = UnitOfWorkFactory.Create())
{
var repos = new UserRepository(uow);
uow.SaveChanges();
}
so when i will be working with any repository like UserRepository then i have to repeat again and again this lines of code UnitOfWorkFactory.Create() which i do not want rather i am looking for a way to embed unit of work code in some where centralize as a result i could reduce the repeated code.
so looking for idea and suggestion. if possible give me modified version of code.
thanks
I will be straightforward about this:
A UoW that contains repositories is an anti pattern at least if DDD is involved. If it isn't, then you're dealing with a very simple app so make you life easier and use a ORM which implements what you want.
As a thumb rule, a repository may contain a UoW as an implementation detail and you should be certain that you really need a repository. A repository inside a UoW is a very specific case which is valid ONLY with CRUD apps and you'll just be reinventing a very small part of an ORM.
Using ado.net directly is wasting time (and money). Either use an ORM or a data mapper aka micro-ORM. With the latter option the UoW is the Db transaction.
You don't gain anything significant using Ado.Net,the performance gain is so small it's not even funny (I know that because I've benchmarked it). The only thing you'll get is longer devel time and human errors.
Actually, if I take a better look at your code, you're basically building a micro ORM, without knowing it. It's still not a repository though, because the abstraction doesn't have business semantics and it's too tightly coupled to an implementation detail.

Castle is unable to Instantiate my class

I have a problem. I'm implementing a selfhost web api based on Owin and Castle. My interface looks like this:
public interface IFluentStoredProcedureRunner<T> where T : class
{
FluentStoredProcedureRunner<T> WithName(string storedProcedureName);
FluentStoredProcedureRunner<T> WithParameters(List<StoredProcedureParameterDefinition> parameterList = null);
StoredProcedureResult<T> Run();
}
and the implementation looks like this:
public class FluentStoredProcedureRunner<T> : IFluentStoredProcedureRunner<T> where T : class
{
private readonly IStoredProcedureRunner<T> storedProcedureRunner;
private string storedProcedureName = string.Empty;
private List<StoredProcedureParameterDefinition> parameterList = new List<StoredProcedureParameterDefinition>();
public FluentStoredProcedureRunner(IStoredProcedureRunner<T> storedProcedureRunner)
{
this.storedProcedureRunner = storedProcedureRunner;
}
public FluentStoredProcedureRunner<T> WithName(string storedProcedureName)
{
this.storedProcedureName = storedProcedureName;
return this;
}
public FluentStoredProcedureRunner<T> WithParameters(List<StoredProcedureParameterDefinition> parameterList = null)
{
this.parameterList = parameterList;
return this;
}
public StoredProcedureResult<T> Run()
{
return this.storedProcedureRunner.Run(this.storedProcedureName, this.parameterList);
}
}
and the registrations:
public class CoreLibInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For(typeof(IMapper<>))
.ImplementedBy(typeof(MapByFieldNameMapper<>))
.LifestyleTransient());
container.Register(
Component.For(typeof(IStoredProcedureRunner<>))
.ImplementedBy(typeof(StoredProcedureRunner<>))
.LifestyleTransient());
container.Register(
Component.For(typeof(IFluentStoredProcedureRunner<>))
.ImplementedBy(typeof(FluentStoredProcedureRunner<>))
.LifestyleTransient());
container.Register(
Component.For<IAuthenticationService>()
.ImplementedBy<ActiveDirectoryAuthenticationService>()
.LifestyleTransient());
container.Register(
Component.For<IStoredProcedureNameResolverService>()
.ImplementedBy<StoredProcedureNameResolverService>()
.LifestyleTransient());
}
}
Here is the stored procedure runner:
public class StoredProcedureRunner<T> : IStoredProcedureRunner<T> where T : class, new()
{
private const string ConnectionString = "someConnectionString"
private readonly IMapper<T> mapper;
private readonly StoredProcedureResult<T> storedProcedureResult = new StoredProcedureResult<T>();
public StoredProcedureRunner(IMapper<T> mapper)
{
this.mapper = mapper;
}
public StoredProcedureResult<T> Run(
string storedProcedureName,
List<StoredProcedureParameterDefinition> parametersList = null)
{
try
{
using (var conn = new IfxConnection(ConnectionString))
{
conn.Open();
using (var cmd = new IfxCommand())
{
cmd.Connection = conn;
cmd.CommandText = storedProcedureName;
cmd.CommandType = CommandType.StoredProcedure;
if (parametersList != null)
{
foreach (var parameter in parametersList)
{
var parameterToAdd = new IfxParameter
{
ParameterName = parameter.ParameterName,
IfxType = parameter.ParameterType,
Value = parameter.ParamerValue,
Direction = parameter.ParameterDirection
};
cmd.Parameters.Add(parameterToAdd);
}
}
var ifxdr = cmd.ExecuteReader();
this.storedProcedureResult.Rows = this.mapper.Map(ifxdr).ToList();
if (parametersList != null)
{
foreach (var outputParameter in parametersList.Where(pl => pl.ParameterDirection == ParameterDirection.Output))
{
this.storedProcedureResult.OutputParameters.Add(
outputParameter.ParameterName,
cmd.Parameters[outputParameter.ParameterName].Value);
}
}
return this.storedProcedureResult;
}
}
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
}
}
This is the interface for it:
public interface IStoredProcedureRunner<T> where T : class
{
StoredProcedureResult<T> Run(
string storedProcedureName,
List<StoredProcedureParameterDefinition> parametersList = null);
}
The problem is that after all of that It is throwing the exception:
ComponentActivator: could not instantiate
StoreProcRunLib.DB.StoredProcedureRunner.FluentStoredProcedureRunner`1[[PromakGateway.WebApi.Models.InactiveAccountsTransferModel,
PromakGateway.WebApi, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null]]
I've seen here Castle Windsor - IoC registration for open generic interfaces? that there is an adapter of some kind but I don't know how it looks like. Thanks in advance.

Use of BAL in 3 tier architecture?How to call methods from DAL to BAL

I am a newbie to 3 tier architecture and below is my DAL code
public static int Insert(string firstname, string lastname, DateTime dob, string gender,string email, string password)
{
// bool flag = false;
SqlParameter pid;
SqlParameter result;
SqlConnection con = Generic.DBConnection.OpenConnection();
try
{
SqlCommand cmd1 = new SqlCommand("Insertreg", con);
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.Parameters.AddWithValue("#FirstName", firstname);
cmd1.Parameters.AddWithValue("#LastName", lastname);
cmd1.Parameters.AddWithValue("#Dob", dob);
cmd1.Parameters.AddWithValue("#Gender", gender);
cmd1.Parameters.AddWithValue("#EmailId", email);
cmd1.Parameters.AddWithValue("#Password", password);
result = cmd1.Parameters.Add("#result", System.Data.SqlDbType.Int);
result.Direction = System.Data.ParameterDirection.Output;
pid = cmd1.Parameters.Add("#id", System.Data.SqlDbType.Int);
pid.Direction = System.Data.ParameterDirection.Output;
return cmd1.ExecuteNonQuery();
con.Close();
}
catch (Exception ex)
{
throw ex;
}
}
this in BAL
public int insert(string firstname,string lastname,DateTime dob,string gender,string email,string password)
{
ProfileMasterDAL dal=new ProfileMasterDAL();
try
{
return ProfileMasterDAL.Insert(firstname, lastname, dob, gender,email, password);
}
catch (Exception ex)
{
throw ex;
}
finally
{
dal = null;
}
}
I my UI
ProfileMasterBLL pmBLL = new ProfileMasterBLL();
pmBLL.insert(firstname, lastname, dob, gender, mobile, country, state, email, password);
Is this the correct way to code in 3 tier??I mean how to call methods from DAL to BAL and into UI?If not suggest me some good way.Thanks.
Normally I do the following:
Define a Business Layer (BL, you call it BAL). This contains the definitions of you business entities. It also defines interfaces to retrieve/save/delete data for whatever patterns you use (repository, context, etc).
Define a Data Access Layer (DAL). This contains the actual implementation for the retrieve/save/delete interfaces.
Define a UI layer. This contains UI elements (forms, controls, models, controllers, etc), which can use the BL to load data.
The references are the following:
The BL doesn't know the DAL or the UI.
The DAL knows the BL. The DAL does not know the UI.
THe UI knows the BL. The UI does not know the DAL.
The big question for you probably is, how does the BL retrieve/save/delete data when it doesn't know the DAL, and therefore cannot create an instance of a class in the DAL. Well, this is where a little Dependency Injection comes in handy. All you have to wire up is the injection of the DAL-class to the BL-interface.
Hope this makes sense. I use it as my standard 3-tier implementation, and it works absolutely without problems. Specifically, I use Entity Framework with POCO for entities, and the DI I use is a custom one, but any of the ones out there will do.
UPDATE
The BL does not know the DAL.
The BL defines an interface (lets call it IRepository) which it can use to do what it needs to do.
The DAL defines a class (Repository) which implements the interface IRepository. So the actual implementation of the repository is in the DAL.
Obviously the BL cannot create an instance of the repository directly. This is where dependency injection comes in, this allows the developer to create an instance of a class where it normally cannot be done. A simple crude version of this, is to use reflection.
I hope this makes more sense.
It might help you to see some actual code. I suggest you download NetTiers, run it against your db schema and see the outputted code for the implementation details.
using System;
using System.Data;
using System.Configuration;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Data.Odbc;
using System.IO;
using System.ComponentModel;
namespace dal
{
/// <summary>
/// Summary description for Data Access Layer
/// </summary>
public class DataAccess
{
public string strConnectionString;
private DbConnection objConnection;
private DbCommand objCommand;
private DbProviderFactory objFactory = null;
private bool boolHandleErrors=false;
private string strLastError;
private bool boolLogError=false;
private string strLogFile;
public DataAccess()
{
//strConnectionString = ;
strConnectionString = objCommon.GetConnectionString;
objFactory = OleDbFactory.Instance;
objConnection = objFactory.CreateConnection();
objCommand = objFactory.CreateCommand();
objConnection.ConnectionString = strConnectionString;
objCommand.Connection = objConnection;
}
public bool HandleErrors
{
get
{
return boolHandleErrors;
}
set
{
boolHandleErrors = value;
}
}
public string LastError
{
get
{
return strLastError;
}
}
public bool LogErrors
{
get
- {
return boolLogError;
}
set
{
boolLogError = value;
}
}
public string LogFile
{
get
{
return strLogFile;
}
set
{
strLogFile = value;
}
}
public int AddParameter(string name, object value)
{
DbParameter p = objFactory.CreateParameter();
p.ParameterName = name;
p.Value = value;
return objCommand.Parameters.Add(p);
}
public int AddParameter(string name, object value, ParameterDirection direction)
{
DbParameter p = objFactory.CreateParameter();
p.ParameterName = name;
p.Value = value;
p.Direction = direction;
return objCommand.Parameters.Add(p);
}
public int AddParameter(string name, object value, DbType type)
{
DbParameter p = objFactory.CreateParameter();
p.ParameterName = name;
p.Value = value;
p.DbType = type;
return objCommand.Parameters.Add(p);
}
public int AddParameter(DbParameter parameter)
{
return objCommand.Parameters.Add(parameter);
}
public DbCommand Command
{
get
{
return objCommand;
}
}
public void BeginTransaction()
{
try
{
if (objConnection.State == System.Data.ConnectionState.Closed)
{
objConnection.Open();
}
objCommand.Transaction = objConnection.BeginTransaction();
}
catch (Exception Ex)
{
HandleExceptions(Ex);
}
}
public void CommitTransaction()
{
objCommand.Transaction.Commit();
objConnection.Close();
}
public void RollbackTransaction()
{
objCommand.Transaction.Rollback();
objConnection.Close();
}
public int ExecuteNonQuery(string query)
{
return ExecuteNonQuery(query, CommandType.Text, ConnectionState.CloseOnExit);
}
public int ExecuteNonQuery(string query, CommandType commandtype)
{
return ExecuteNonQuery(query, commandtype, ConnectionState.CloseOnExit);
}
public int ExecuteNonQuery(string query, ConnectionState connectionstate)
{
return ExecuteNonQuery(query, CommandType.Text, connectionstate);
}
public int ExecuteNonQuery(string query, CommandType commandtype, ConnectionState connectionstate)
{
objCommand.CommandText = query;
objCommand.CommandType = commandtype;
int i = -1;
try
{
if (objConnection.State == System.Data.ConnectionState.Closed)
{
objConnection.Open();
}
i = objCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
HandleExceptions(ex);
}
finally
{
objCommand.Parameters.Clear();
if (connectionstate == ConnectionState.CloseOnExit)
{
objConnection.Close();
}
}
return i;
}
public object ExecuteScalar(string query)
{
return ExecuteScalar(query, CommandType.Text, ConnectionState.CloseOnExit);
}
public object ExecuteScalar(string query, CommandType commandtype)
{
return ExecuteScalar(query, commandtype, ConnectionState.CloseOnExit);
}
public object ExecuteScalar(string query, ConnectionState connectionstate)
{
return ExecuteScalar(query, CommandType.Text, connectionstate);
}
public object ExecuteScalar(string query, CommandType commandtype, ConnectionState connectionstate)
{
objCommand.CommandText = query;
objCommand.CommandType = commandtype;
object o = null;
try
{
if (objConnection.State == System.Data.ConnectionState.Closed)
{
objConnection.Open();
}
o = objCommand.ExecuteScalar();
}
catch (Exception ex)
{
HandleExceptions(ex);
}
finally
{
objCommand.Parameters.Clear();
if (connectionstate == ConnectionState.CloseOnExit)
{
objConnection.Close();
}
}
return o;
}
public DbDataReader ExecuteReader(string query)
{
return ExecuteReader(query, CommandType.Text, ConnectionState.CloseOnExit);
}
public DbDataReader ExecuteReader(string query, CommandType commandtype)
{
return ExecuteReader(query, commandtype, ConnectionState.CloseOnExit);
}
public DbDataReader ExecuteReader(string query, ConnectionState connectionstate)
{
return ExecuteReader(query, CommandType.Text, connectionstate);
}
public DbDataReader ExecuteReader(string query, CommandType commandtype, ConnectionState connectionstate)
{
objCommand.CommandText = query;
objCommand.CommandType = commandtype;
DbDataReader reader = null;
try
{
if (objConnection.State == System.Data.ConnectionState.Closed)
{
objConnection.Open();
}
if (connectionstate == ConnectionState.CloseOnExit)
{
reader = objCommand.ExecuteReader(CommandBehavior.CloseConnection);
}
else
{
reader = objCommand.ExecuteReader();
}
}
catch (Exception ex)
{
HandleExceptions(ex);
}
finally
{
objCommand.Parameters.Clear();
}
return reader;
}
public DataSet ExecuteDataSet(string query)
{
return ExecuteDataSet(query, CommandType.Text, ConnectionState.CloseOnExit);
}
public DataSet ExecuteDataSet(string query, CommandType commandtype)
{
return ExecuteDataSet(query, commandtype, ConnectionState.CloseOnExit);
}
public DataSet ExecuteDataSet(string query, ConnectionState connectionstate)
{
return ExecuteDataSet(query, CommandType.Text, connectionstate);
}
public DataSet ExecuteDataSet(string query, CommandType commandtype, ConnectionState connectionstate)
{
DbDataAdapter adapter = objFactory.CreateDataAdapter();
objCommand.CommandText = query;
objCommand.CommandType = commandtype;
adapter.SelectCommand = objCommand;
DataSet ds = new DataSet();
try
{
adapter.Fill(ds);
}
catch (Exception ex)
{
HandleExceptions(ex);
}
finally
{
objCommand.Parameters.Clear();
if (connectionstate == ConnectionState.CloseOnExit)
{
if (objConnection.State == System.Data.ConnectionState.Open)
{
objConnection.Close();
}
}
}
return ds;
}
private void HandleExceptions(Exception ex)
{
throw ex;
}
private void WriteToLog(string msg)
{
StreamWriter writer = File.AppendText(LogFile);
writer.WriteLine(DateTime.Now.ToString() + " - " + msg);
writer.Close();
}
public void Dispose()
{
objConnection.Close();
objConnection.Dispose();
objCommand.Dispose();
}
public enum Providers
{
SqlServer, OleDb, Oracle, ODBC, ConfigDefined
}
public enum ConnectionState
{
KeepOpen, CloseOnExit
}
public interface ILoadFromDataRow
{
bool LoadFromDataRow(DataRow row);
}
}
}
You can you the following sample code for 3 tier architecture :-
CLASS - BAL.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
public class BAL
{
DAL objDAL;
public BAL()
{
}
public string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public int insert()
{
objDAL = new DAL();
int val = 0;
try
{
Hashtable objHash = new Hashtable();
objHash.Add("#Name", Convert.ToString(_Name));
val = objDAL.Insert("Your SP Name", objHash);
}
catch (Exception ex)
{
throw ex;
}
finally
{
objDAL = null;
}
return val;
}
}
CLASS - DAL.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
public class DAL : IDisposable
{
SqlConnection con;
public DAL()
{
con = new SqlConnection("Connection String");
}
public int Insert(string CMD, Hashtable objHash)
{
int val = 0;
try
{
SqlCommand cmd1 = new SqlCommand(CMD, con);
cmd1.CommandType = CommandType.StoredProcedure;
foreach (DictionaryEntry de in objHash)
{
cmd1.Parameters.AddWithValue(Convert.ToString(de.Key), Convert.ToString(de.Value));
}
con.Open();
val = cmd1.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
return val;
}
#region IDisposable Members
public void Dispose()
{
throw new NotImplementedException();
}
#endregion
}
UI:-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
BAL objBAL;
protected void Page_Load(object sender, EventArgs e)
{
Insert();
}
public void Insert()
{
int val = 0;
objBAL = new BAL();
objBAL.Name = "stackoverflow";
try
{
val = objBAL.insert();
}
catch { }
finally
{
objBAL = null;
}
if (val != 0)
{
//Insert sucessful
}
else
{
//Error in Insert.
}
}
}

Categories

Resources