This question already has answers here:
COM object that has been separated from its underlying RCW cannot be used. in oledb
(1 answer)
Hitting "COM object that has been separated from its underlying RCW cannot be used" error
(2 answers)
Closed 1 year ago.
My OleDB Class
public oleDB()
{
if (string.IsNullOrWhiteSpace(CONNECTION_STRING))
{
IDSTool.Security.EncryptDecryptData();
string dbname = "D:\\C# Desktop\\Database\\GoodsManagementMDB1.mdb;";
Source={0};Jet OLEDB:Database Password={1}", dbname, password);
CONNECTION_STRING = string.Format(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}; Persist Security Info=False;", dbname);
ConnectionString = CONNECTION_STRING;
}
else
{
ConnectionString = CONNECTION_STRING;
}
DbConnection = new OleDbConnection(ConnectionString);
DbCommand = new OleDbCommand();
DbCommand.Connection = DbConnection;
}
public void ExecuteReader()
{
try
{
DbDataReader = DbCommand.ExecuteReader();
}
catch (Exception ex)
{
throw ex;
}
finally
{
DbCommand.Parameters.Clear();
}
}
My AbstractDataAccess
public IDbCommand DbCommand
{
get { return dbCommand; }
set { dbCommand = value; }
}
public void Close()
{
if (DbConnection.State == ConnectionState.Open || DbConnection.State == ConnectionState.Fetching)
DbConnection.Close();
}
#region IDisposable Members
public void Dispose()
{
dbConnection.Close();
dbConnection.Dispose();
dbCommand.Dispose();
if (dbDataReader != null)
{
dbDataReader.Close();
dbDataReader.Dispose();
}
if (dbDataAdapter != null)
{
dbDataAdapter = null;
}
GC.Collect();
GC.SuppressFinalize(this);
}
My User Class
public bool CheckLogin(string userID, string userpassword)
{
bool result = false;
using (DatabaseAccess.oleDB oleDB = new DatabaseAccess.oleDB())
{
using (oleDB.DbCommand)
{
oleDB.CommandText = #"SELECT * FROM[User] where UserID=#UserID";
oleDB.AddParameter("#UserID", System.Data.OleDb.OleDbType.VarChar, userID);
oleDB.CommandType = System.Data.CommandType.Text;
try
{
oleDB.Open();
oleDB.ExecuteReader();
while (oleDB.DbDataReader.Read())
{
if (userID == oleDB.DbDataReader["UserID"].ToString() && userpassword == Tools.Security.Decrypted(oleDB.DbDataReader["Password"].ToString()))
result = true;
else
result = false;
}
oleDB.Close();
return result;
}
catch (Exception)
{
return result;
throw;
}
}
}
}
I use the oledb class as a reference in the User class to connect to the access database, oledb inherits from the AbstratDataAccess class where the AbstratDataAccess class has properties dbconnection, dbcommand etc., I have declared new DbCommand in the oledb class, but why when DbCommand.Dispose(); in Public Void Closer() method an error appears COM object that has been separated from its underlying RCW cannot be used.
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);
}
}
assuming i have a class like below, how can i implement something that would make all the called Methods inside MasterMethod (MethodA, MethodB, and MethodC) inherit the MySqlTransaction Object that was instantiated from MasterMethod?
private MySqlConnection OpenConnection() {
try {
MySqlConnection DbConn = new MySqlConnection("~connectionstring");
DbConn.Open();
return DbConn;
} catch(Exception Ex) {
throw Ex;
}
}
public void MasterMethod() {
using(MySqlConnection DbConn = OpenConnection()) {
using(MySqlTransaction DbTrans = DbConn.BeginTransaction()) {
try {
MethodA();
MethodB(Param1);
MethodC(Param1, Param2);
DbTrans.Commit();
} catch(Exception Ex) {
DbTrans.Rollback();
throw Ex;
}
}
}
}
public void MethodA() {
using(MySqlConnection DbConn = OpenConnection()) {
using(MySqlTransaction DbTrans = DbConn.BeginTransaction()) {
try {
// Lots and Lots of things to do
DbTrans.Commit();
} catch(Exception Ex) {
DbTrans.Rollback();
throw Ex;
}
}
}
}
public void MethodB(int Param1) {
using(MySqlConnection DbConn = OpenConnection()) {
using(MySqlTransaction DbTrans = DbConn.BeginTransaction()) {
try {
// Lots and Lots of things to do
DbTrans.Commit();
} catch(Exception Ex) {
DbTrans.Rollback();
throw Ex;
}
}
}
}
public void MethodC(string Param1, string Param2) {
using(MySqlConnection DbConn = OpenConnection()) {
using(MySqlTransaction DbTrans = DbConn.BeginTransaction()) {
try {
// Lots and Lots of things to do
DbTrans.Commit();
} catch(Exception Ex) {
DbTrans.Rollback();
throw Ex;
}
}
}
}
With my current architecture, queries are immediately committed right after a specific Method's block has reached its end instead of waiting for the DbTrans.Commit() on the bottom most part of MasterMethod's try block.
How can i make it (the MySqlTransaction Object) to behave in such a way that it must wait for all 3 nested/called Methods (MethodA, MethodB, MethodC) before committing (or rolling back) the changes to the Database ?
Hope the below code would help you:
You have to use 2 different connection object in order to maintain states (as per your requirement). I have posted a general DB connection code and you can use it on your own way.
public class ConnectionClass
{
public string ConnectionString = ConfigurationManager.ConnectionStrings["xyz"].ConnectionString;
public SqlConnection conTrans = new SqlConnection();
public SqlTransaction dbTrans;
public SqlConnection sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["xyz"].ConnectionString);
public SqlTransaction sqlTrans;
public bool BeginConTrans()
{
try
{
conTrans.ConnectionString = ConnectionString;
conTrans.Open();
dbTrans = conTrans.BeginTransaction();
return true;
}
catch (Exception ex)
{
return false;
}
}
public bool CommitConTrans()
{
try
{
dbTrans.Commit();
conTrans.Close();
return true;
}
catch (Exception ex)
{
return false;
}
}
public bool RollbackConTrans()
{
try
{
dbTrans.Rollback();
conTrans.Close();
return true;
}
catch (Exception ex)
{
return false;
}
}
public bool ExecuteNonQueryTrans(string proc, SqlParameter[] par)
{
SqlCommand cmd = new SqlCommand();
try
{
if (par != null)
{
for (int i = 0; i <= par.Length - 1; i++)
{
cmd.Parameters.Add(par[i]);
}
}
cmd.Connection = conTrans;
cmd.Transaction = dbTrans;
cmd.CommandText = proc;
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
return true;
}
catch (Exception ex)
{
return false;
}
}
}
EDIT -how to use it in your logic
public void MasterMethod()
{
try
{
BeginConTrans();
// your methods A,B,C
//must use ExecuteNonQueryTrans for your get/put data
}
catch (Exception ex)
{
//if any method fails handle exception and rollback the transcation
RollbackConTrans();
}
CommitConTrans(); // if success ,commit the transcation
}
This function connects to postgres database and returns Dataset.
Two things i want to understant
If i get an error how can i return it ?
Is this the best way to return Dataset ?
string strODBCDriverName = "DSN=Postgres_32";
public DataSet SelectDataSet(string sql, bool isProcedure, Dictionary<string, object> parameters = null) {
using (OdbcConnection odbcConnection = new OdbcConnection(strODBCDriverName))
{
odbcConnection.Open();
using (OdbcCommand odbcCommand = new OdbcCommand(sql, odbcConnection))
{
if (isProcedure) odbcCommand.CommandType = CommandType.StoredProcedure;
else odbcCommand.CommandType = CommandType.Text;
if (parameters != null)
foreach (KeyValuePair<string, object> parameter in parameters)
odbcCommand.Parameters.AddWithValue(parameter.Key, parameter.Value);
using (OdbcDataAdapter adapter = new OdbcDataAdapter(odbcCommand))
{
using (DataSet ds = new DataSet())
{
try
{
adapter.Fill(ds); return ds;
}
catch (Exception ex)
{
throw (ex);
}
finally
{
}
}
}
}
}
}
I like having generic Result class that can be reused:
internal class Result
{
internal bool IsFailure => !IsSuccess;
internal bool IsSuccess { get; }
internal string Error { get; }
protected Result(bool isSuccess, string error) {
IsSuccess = isSuccess;
Error = error;
}
private Result(bool isSuccess) : this(isSuccess, null) { }
internal static Result Fail(string error) => new Result(false, error);
internal static Result<T> Fail<T>(string error) =>
new Result<T>(default(T), false, error);
internal static Result Ok() => new Result(true);
internal static Result<T> Ok<T>(T value) => new Result<T>(value, true);
}
internal sealed class Result<T> : Result
{
internal T Value { get; }
internal Result(T value, bool isSuccess) : this(value, isSuccess, null) { }
internal Result(T value, bool isSuccess, string error) : base(isSuccess, error) {
Value = value;
}
This can be used not only DataSet, but any type.
In your case return would be Result<DataSet> and returns can become:
returns ds --> new Result.Ok(d)
throw ex --> new Result.Fail<DataSet>(ex.Message)
I think it would be great if you return null; If you need return some customized message as well means you can use out parameters for this. So that the return value will be null if any Exception occurs in this case out parameter will holds the exception details. if Dataset is populated well means outParameter will have a values "Success" or something like that. So the method signature will be changed as like the following
public static DataSet SelectDataSet(string sql, bool isProcedure, out string message, Dictionary<string, object> parameters = null)
{
// Rest of codes here
try
{
message = "Success";
adapter.Fill(ds);
return ds;
}
catch (Exception ex)
{
message = ex.Message;
return null;
}
}
And you can call this method like this:
string message = String.Empty;
DataSet resultDataset = SelectDataSet("query here", false, out message);
if (resultDataset != null)
{
Console.WriteLine(message);
// proceed with resultDataset
}
else
{
Console.WriteLine(message);
}
Here resultDataset will be null in case of any exception otherwise you can proceed with its value.
Create a class:
class DataSetWithError: DataSet
{
public Exception msg { get; set; }
}
Save error during query:
using (OdbcDataAdapter adapter = new OdbcDataAdapter(odbcCommand))
{
DataSetWithError ds = new DataSetWithError();
try
{
adapter.Fill(ds);
}
catch (Exception ex)
{
ds.msg = ex;
}
finally
{
adapter.Close();
}
return ds;
}
And result:
DataSetWithError dataSetWithError = SelectDataSet();
if (dataSetWithError.msg == null)
{
// Show data
}
else
{
MessageBox.Show(dataSetWithError.msg.ToString());
}
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.
}
}
}