Data Layer Abstract Factory - c#

I'm new on developing an Abstract Factory pattern, and would like to create an abstract factory in the data layer that will help me link this layer to any other databases for example sql and oracle. Can you help me on developing this task please. Note that the connection string of the database will be found in this layer not in the presentation..
Thanks
EDITED
public abstract class Database
{
public string connectionString;
#region Abstract Functions
public abstract IDbConnection CreateConnection();
public abstract IDbCommand CreateCommand();
public abstract IDbConnection CreateOpenConnection();
public abstract IDbCommand CreateCommand(string commandText, IDbConnection connection);
public abstract IDbCommand CreateStoredProcCommand(string procName, IDbConnection connection);
public abstract IDataParameter CreateParameter(string parameterName, object parameterValue);
#endregion
}
public class SQLDatabase : Database
{
public override IDbConnection CreateConnection()
{
return new SqlConnection(connectionString);
}
public override IDbCommand CreateCommand()
{
return new SqlCommand();
}
public override IDbConnection CreateOpenConnection()
{
SqlConnection connection = (SqlConnection)CreateConnection();
connection.Open();
return connection;
}
public override IDbCommand CreateCommand(string commandText, IDbConnection connection)
{
SqlCommand command = (SqlCommand)CreateCommand();
command.CommandText = commandText;
command.Connection = (SqlConnection)connection;
command.CommandType = CommandType.Text;
return command;
}
public override IDbCommand CreateStoredProcCommand(string procName, IDbConnection connection)
{
SqlCommand command = (SqlCommand)CreateCommand();
command.CommandText = procName;
command.Connection = (SqlConnection)connection;
command.CommandType = CommandType.StoredProcedure;
return command;
}
public override IDataParameter CreateParameter(string parameterName, object parameterValue)
{
return new SqlParameter(parameterName, parameterValue);
}
}
Those are the two classes I created..

The functionality already exists.
Add a connection string to app/webb.config:
<connectionStrings>
<add name="TheDatabase" providerName="System.Data.OleDb" connectionString="Provider=OraOLEDB.Oracle.1;Persist Security Info=False;User Id=xxx;Password=yyy;Data Source=zzzz;Extended Properties="/>
</connectionStrings>
Build the connection using a factory:
var connectionString = ConfigurationManager.ConnectionStrings["TheDatabase"];
var providerName = connectionString.ProviderName;
var factory = DbProviderFactories.GetFactory(providerName);
Get a connection:
var connection = factory.CreateConnection();
Get a command:
var command == connection.CreateCommand();
The only thing you need to do is to switch driver in the app/web.config. No other changes are required.
Update
public class Database
{
public static IDbConnection CreateOpenConnection()
{
var connectionString = ConfigurationManager.ConnectionStrings["TheDatabase"];
var providerName = connectionString.ProviderName;
var factory = DbProviderFactories.GetFactory(providerName);
var connection = factory.CreateConnection();
connection.Open();
return connection;
}
}
class FlowerManager : DataWorker
{
public static void GetFlowers()
{
using (IDbConnection connection = Database.CreateOpenConnection())
{
using (IDbCommand command = connection.CreateCommand("SELECT * FROM FLOWERS", connection))
{
using (IDataReader reader = command.ExecuteReader())
{
// ...
}
}
}
}
}

Much of the required functionality can be obtained from
System.Data.Common.DbProviderFactories
where you can get items of System.Data.Common.DbProviderFactory which are implemented by most dotnet-databaseproviders.
Update:
havig your own factory is fine. if you are lookig for examples of working database-factories see the sourcecode of
queryexpress a working database-querying gui,
queryexplus a spinof of queryexpress
mygeneration a codegenerator which connects to many different databases
NHibernate with a sophisticated driver modell for many databases

I would not have "createcommand" or "createconnection" methods.
A much better approach to take is to let each of the access methods (like "GetAccounts") handle their own connection / command instantiation.
Connection and Command objects implement IDisposable. As such it is better to have using statements in which those are created and disposed of as necessary. Teh way you have it now could lead to massive memory issues.
Further the CreateParameter method appears to not provide any real benefit over just calling "new SqlParameter" in the code that needs to create those parameters.
I would do the following:
public interface IDbAccess {
String ConnectionString;
Collection<Account> GetAccountsById(Int32 id);
Boolean StoreAccount(Account acct);
}
public class SqlDatabase : IDbAccess {
public String ConnectionString {get; set;}
public SqlDatabase(String connection) {
ConnectionString = connection;
}
public Collection<Account> GetAccountsById(Int32 id) {
using (SqlConnection connect = new SqlConnection(ConnectionString)) {
using (SqlCommand cmd = new SqlCommand(connect)) {
/// etc.
}
}
}
}
This way your datalayer is specific to the functionality you are providing. There are already great wrappers for db access like Enterprise Library. The approach you are taking adds nothing and introduces errors.
Further this approach means you can implement non-database providers like XML, web services, etc with zero code changes.

Hi People i know this is old post, but i would like share something with you.
The Enterprise Library and OleDb has some problem, when you want to insert image bigger than 32k it will throw Exception, so de solve this i have done:
Create a project Which you can call CustomProvider
Create a Classe Which you will call Database
public abstract class Database
{
public string ConnectionString { get; set; } // Preciso uma variavel para guardar o ConnectionString
public IDbConnection Connection { get; set; }
//public abstract string ProviderName { get; } // Preciso uma variavel para guardar o ConnectionString
//public abstract IDbConnection CreateConnection(string ConnectionString);
public abstract IDbConnection CreateConnection(); // Preciso um Metodo Abstract para CreateConnection Para Tratar da Connection
public abstract IDbCommand CreateCommand();
}
}
Create Seccond Class OracleDatabase.cs
Create Third class SQLDatabase.cs
public class OracleDatabase : Database
{
public override IDbConnection CreateConnection()
{
return new OracleConnection(ConnectionString);
}
public override IDbCommand CreateCommand()
{
return new OracleCommand();
}
public override IDbConnection CreateOpenConnection()
{
OracleConnection connection = (OracleConnection)CreateConnection();
connection.Open();
return connection;
}
public override IDbCommand CreateCommand(string commandText, IDbConnection connection)
{
OracleCommand command = (OracleCommand)CreateCommand();
command.CommandText = commandText;
command.Connection = (OracleConnection)connection;
command.CommandType = CommandType.Text;
return command;
}
}
public class SQLDatabase : Database
{
public override IDbConnection CreateConnection()
{
return new SqlConnection(ConnectionString);
}
public override IDbCommand CreateCommand()
{
return new SqlCommand();
}
public override IDbConnection CreateOpenConnection()
{
SqlConnection connection = (SqlConnection)CreateConnection();
connection.Open();
return connection;
}
public override IDbCommand CreateCommand(string commandText, IDbConnection connection)
{
SqlCommand command = (SqlCommand)CreateCommand();
command.CommandText = commandText;
command.Connection = (SqlConnection)connection;
command.CommandType = CommandType.Text;
return command;
}
public override IDbCommand CreateStoredProcCommand(string procName, IDbConnection connection)
{
SqlCommand command = (SqlCommand)CreateCommand();
command.CommandText = procName;
command.Connection = (SqlConnection)connection;
command.CommandType = CommandType.StoredProcedure;
return command;
}
}
and then on the program
Database db = Factory.CreateDatabase("ConnectionString");
try
{
using (IDbConnection w_connection = db.Connection)
{
w_connection.Open();
IDbTransaction transation = w_connection.BeginTransaction();
IDbCommand dbcomand = db.CreateStoredProcCommand("INSERTTEST");
db.AddInParameter(dbcomand, "#ATTCH", DbType.Binary, bytes);
db.ExecuteNonQuery(dbcomand, transation);
transation.Commit();
}
}
catch (Exception)
{
}
}
You must Override all defined method in the Master Class
Create a Factory.cs
public static Database CreateDatabase(string ConnectionString)
{
//var Conn = ConfigurationManager.ConnectionStrings[ConnectionString].ToString();
if (string.IsNullOrEmpty(ConnectionString))
throw new Exception("Connectionstring Not Found" + ConnectionString);
Database db = null;
if (ConfigurationManager.ConnectionStrings[ConnectionString].ProviderName.Contains("Oracle"))
{
db = new OracleDatabase();
db.ConnectionString = GetConnectionString(ConnectionString);
db.Connection = db.CreateConnection();
}
else
{
db = new SQLDatabase();
db.ConnectionString = GetConnectionString(ConnectionString);
db.Connection = db.CreateConnection();
}
return db;
}

Related

How to mock method which is called multiple times c#

I have a common method which is being called multiple times(around 30-35 references in the project). This method is basically fetching data from DB into data table.
Following is the testable code:
public class MyApp
{
private readonly IDataProvider _dbProvider;
public MyApp(IDataProvider dbProvider)
{
_dbProvider = dbProvider;
}
public void Process()
{
string query = "something";
Helper h = new Helper(_dbProvider);
// This method will be called in the Process method several times
var data = h.GetData(query);
}
}
public interface IDataProvider
{
IDbConnection CreateConnection(string connectionString);
DataTable FillDatatableFromAdapter(IDbCommand command);
}
public class DataProvider : IDataProvider
{
public IDbConnection CreateConnection(string connectionString)
{
return new SqlConnection(connectionString);
}
public DataTable FillDatatableFromAdapter(IDbCommand command)
{
DataSet dataSet = new DataSet();
SqlCommand sqlCommand = command as SqlCommand;
using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand))
{
sqlDataAdapter.Fill(dataSet);
}
if (dataSet.Tables.Count == 0)
return null;
return dataSet.Tables[0];
}
}
public class Helper
{
private readonly IDataProvider _dbProvider;
public Helper(IDataProvider dbProvider)
{
_dbProvider = dbProvider;
}
public DataTable GetData(string query)
{
DataTable table = new DataTable();
using (IDbConnection connection =
_databaseProvider.CreateConnection(_connectionString))
{
connection.Open();
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = query;
command.Connection = connection;
table = _dbProvider.FillDatatableFromAdapter(command);
}
}
return table;
}
}
I have mocked DB classes to not hit DB from unit tests.
Following is the test case code:
[TestMethod]
public void TestMyApp()
{
Mock<IDbCommand> mockDbCommand = new Mock<IDbCommand>();
Mock<IDbConnection> mockDbConnection = new Mock<IDbConnection>();
Mock<IDataProvider> mockDatabaseProvider = new Mock<IDataProvider();
mockDbConnection.Setup(m => m.CreateCommand()).Returns(mockDbCommand.Object);
mockDatabaseProvider.Setup(m => m.CreateConnection(It.IsAny<string>())).Returns(mockDbConnection.Object);
DataTable table = new DataTable();
mockDatabaseProvider.SetupSequence(mock => mock.FillDatatableFromAdapter(It.IsAny<IDbCommand>()))
.Returns(dataTable);
MyApp app = new MyApp(mockDatabaseProvider.Object);
app.Process();
// And then after that I am testing some data.
}
I will be calling GetData() method several times and therefore FillDatatableFromAdapter will also be called several times. As in the above test case I have mocked FillDatatableFromAdapter method and I am returning some fake data table for further testing.
I am aware of SetupSequence method in Moq which I can use to return multiple data tables from the mocked method everytime that method is called.
I want a suggestion is that approach correct because then I will have to create that many number of Data tables which will be return from the mocked method using SetupSequence? Or is there some other better approach?
Any help??
You need to define what you want to test.
A small refactoring will help you better test your code
public class MyApp
{
private readonly IDataProvider _dbProvider;
private readonly IHelper _h;
public MyApp(IDataProvider dbProvider)
{
_dbProvider = dbProvider;
_h = new Helper(_dbProvider);
}
public void Process()
{
string query = "something";
// This method will be called in the Process method several times
var data = _h.GetData(query);
}
}
public interface IDataProvider
{
IDbConnection CreateConnection(string connectionString);
DataTable FillDatatableFromAdapter(IDbCommand command);
}
public class DataProvider : IDataProvider
{
public IDbConnection CreateConnection(string connectionString)
{
return new SqlConnection(connectionString);
}
public DataTable FillDatatableFromAdapter(IDbCommand command)
{
DataSet dataSet = new DataSet();
SqlCommand sqlCommand = command as SqlCommand;
using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand))
{
sqlDataAdapter.Fill(dataSet);
}
if (dataSet.Tables.Count == 0)
return null;
return dataSet.Tables[0];
}
}
public interface IHelper
{
public DataTable GetData(string query);
}
public class Helper
{
private readonly IDataProvider _dbProvider;
public Helper(IDataProvider dbProvider)
{
_dbProvider = dbProvider;
}
public DataTable GetData(string query)
{
DataTable table = new DataTable();
using (IDbConnection connection =
_databaseProvider.CreateConnection(_connectionString))
{
connection.Open();
using (IDbCommand command = connection.CreateCommand())
{
command.CommandText = query;
command.Connection = connection;
table = _dbProvider.FillDatatableFromAdapter(command);
}
}
return table;
}
}
Now you can have 4 isolated tests
[TestMethod]
public void TestProccessFunctionCallHelperGetData()
{
Mock<IHelper> mockHelper = new Mock<IHelper>();
Mock<IDataProvider> mockDatabaseProvider = new Mock<IDataProvider();
mockHelper.Setup(m => m.getData(It.IsAny<string>())).Returns(new DataTable());
MyApp app = new MyApp(mockDatabaseProvider.Object, mockHelper.Setup);
app.Process();
Assert.AreEquals(mockHelper.numTimesCalled, 1);
}
[TestMethod]
public void TestHelperGetData()
{
var query = ""; //TODO: write dummy query
var dataTableToReturn = new DataTable(); //TODO: add some data
Mock<IDataProvider> mockDatabaseProvider = new Mock<IDataProvider();
mockDatabaseProvider.Setup(m => m.CreateConnection(It.IsAny<string>())).Returns(new SqlConnection("dummy connection string"));
mockDatabaseProvider.Setup(m => m.FillDatatableFromAdapter(It.IsAny<IDbCommand>())).Returns(dataTableToReturn );
IHelper h = new Helper(mockDatabaseProvider.Object);
var actualDataTable = h.getData(query);
Assert.AreEqual(dataTableToReturn, actualDataTable );
}
[TestMethod]
public void TestDataProviderFillDataTableFromAdapter()
{
//This test seems to me more like integration test because you need to mock a db or use a real db
}
[TestMethod]
public void TestYourData()
{
// Create a dataTable with data so you can continue with your testing
}

ExecuteReader: Connection property has not been initialized. while im using abstract class connection

Here i'm using connection state in abstract class
public abstract class Connection
{
private static string _Connection = ConfigurationManager.ConnectionStrings["CTXDB"].ConnectionString;
public static string GetConnection{ get { return _Connection; }}
}
public abstract void ProcessConnection();
This class i implemented in Another class(BusinessConnection.cs)
public class BusinessClass :Connection
{
public override void ProcessConnection()
{
using (var conn = new SqlConnection(Connection.GetConnection))
{
conn.Open();
}
}
Now i called this Class(BusinessConnection.cs) In my controller as
BusinessClass objcon = new BusinessClass();
public IHttpActionResult Index()
objcon.ProcessConnection();
SqlCommand cmd = new SqlCommand("select * from Employee");
//Here how can i inject my Connection in cmd
SqlDataReader rdr = cmd.ExecuteReader();
if (rdr.HasRows == true)
There seems to be a little design flaw. You obviously want to use the connection outside the BusinessClass/Connection classes.
So maybe you can do something like this:
public abstract class Connection
{
public abstract SqlConnection OpenConnection();
// your code
}
and in your BusinessClass:
public override SqlConnection OpenConnection()
{
var conn = new SqlConnection(Connection.GetConnection))
conn.Open();
return conn;
}
And then in your querying code:
using(SqlConnection conn = objcon.OpenConnection())
{
// create SqlCommand and pass conn!
using(SqlCommand cmd = new SqlCommand("select * from Employee", conn))
{
using (SqlDataReader rdr = cmd.ExecuteReader())
{
// and the rest of your rdr reading code
}
}
}
The using statements take care of closing/disposing the respective objects.

Encountering ObjectDisposedException when trying to read from SQLiteDataReader

I am trying to read through a stored SQLiteDataReader object. In theory, it "should" work because the object is stored in a variable before it is referenced (and doesn't hit an error until the reference line is reached), but maybe I have the wrong idea.
I'm trying to keep my application in a neatly layered architecture. So, each database table having its own C# class with its own methods for select, insert, update, and delete; only the data layer knows how to communicate with the database, etc.
I was running into connection issues earlier when I tried to make one static SQLiteConnection object that all the data layer classes could reference (so as to keep it open and minimize overhead, if any). So I'm trying to go with the using block to make sure the connection is properly disposed each time I need to access the database, and hoping that this won't cause performance issues.
So basically, here is the method in my DatabaseConnection class that handles basic query execution:
public SQLiteDataReader ExecuteQuery(string sql)
{
SQLiteDataReader rdr = null;
using(SQLiteConnection conn = new SQLiteConnection(ConnectionString))
{
conn.Open();
SQLiteCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
rdr = cmd.ExecuteReader();
}
return rdr;
}
And here is the code that calls that method. I'll use an object/record of the Associate table as an example.
public class Associate
{
public int RowId { get; private set; }
public int Id { get; set; }
public string Name { get; set; }
private string password;
public string Password
{
get
{
return password;
}
set
{
password = Hash(value); // external password hashing method
}
}
public Associate() { } // default constructor with default values
public Associate(int id)
{
this.Id = id;
Select();
}
// select, insert, update, delete methods
private void Select() { ... }
// these are non-queries and return true/false based on success
public bool Insert() { ... }
public bool Update() { ... }
public bool Delete() { ... }
/* Method that causes the error */
public static Associate[] GetAll()
{
DatabaseConnection con = new DatabaseConnection();
SQLiteDataReader rdr = con.ExecuteQuery("SELECT id FROM Associate");
List<Associate> list = new List<Associate>();
if (rdr != null)
{
while (rdr.Read()) /* this line throws the exception */
{
int next = rdr.GetInt32(0);
list.Add(new Associate(next));
}
}
return list.ToArray();
}
}
The idea here is that using the rdr object, I can access the column names directly so that if the database ever changes, I won't have to rewrite a bunch of code to adjust for the column indices (rdr["id"], rdr["name"], etc.)
So what I don't understand is why rdr in the calling method is having "object disposed" issues because it's stored in a variable before I reference it. I know the connection is disposed at the end of the called method, but since the returned result is stored, shouldn't it technically be able to "survive" outside the using block?
It is the connection that got disposed. The data reader can only read data while the connection still exists.
public SQLiteDataReader ExecuteQuery(string sql)
{
SQLiteDataReader rdr = null;
using(SQLiteConnection conn = new SQLiteConnection(ConnectionString))
{
conn.Open();
SQLiteCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
rdr = cmd.ExecuteReader();
}
// *** Connection gone at this stage ***
return rdr;
}
Your options are to either return a DataTable, e.g.
public DataTable ExecuteQuery(string sql)
{
SQLiteDataReader rdr = null;
using(SQLiteConnection conn = new SQLiteConnection(ConnectionString))
{
conn.Open();
SQLiteCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
rdr = cmd.ExecuteReader();
var dataTable = new DataTable();
dataTable.Load(rdr);
return dataTable;
}
}
otherwise, you could keep the connection alive inside the DatabaseConnection class:
class DatabaseConnection : IDisposable
{
private readonly IDbConnection _conn;
public DatabaseConnection()
{
_conn = new SQLiteConnection(ConnectionString);
}
public void Dispose()
{
_conn.Dispose();
}
public SQLDataReader ExecuteQuery(string sql)
{
...
}
}
// sample usage
using (var conn = new DatabaseConnection())
{
using (var reader = conn.ExecuteQuery("SELECT ...")
{
// do your work in here
}
}

Cannot implicitly convert type 'void' to 'string'

I've tried for a while now and I really dont get it. I recive error "Cannot implicitly convert type 'void' to 'string'"
I have tried multiple variants of string, int, nothing, void, public, static and nope I really dont get it right.
I want to get one value from my db thoug my DAL and BLL, my code looks like this.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Repeater1.DataSource = BLL.getGames();
Repeater1.DataBind();
var culture = CultureInfo.GetCultureInfo("sv-SE");
var dateTimeInfo = DateTimeFormatInfo.GetInstance(culture);
var dateTime = DateTime.Today;
int weekNumber = culture.Calendar.GetWeekOfYear(dateTime, dateTimeInfo.CalendarWeekRule, dateTimeInfo.FirstDayOfWeek);
string mroundY = dateTime.Year.ToString();
string mroundW = weekNumber.ToString();
string mrounddate = mroundY + mroundW;
string mround = BLL.getMroundGames(mrounddate); <-- Here's the error
}
protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
{
}
}
My BLL looks like this;
public class BLL
{
public static void getMroundGames(string mrounddate)
{
SqlCommand getMroundGames = new SqlCommand("SELECT mround FROM gameTB where mround = #mrounddate");
DAL.ExecuteNonQuery(getMroundGames);
}
}
Also tried this;
public class BLL
{
public static DataTable getMroundGames(string mrounddate)
{
SqlCommand getMroundGames = new SqlCommand("SELECT mround FROM gameTB where mround = #mrounddate");
getMroundGames.Parameters.Add("#mrounddate", SqlDbType.VarChar, 10).Value = mrounddate;
return DAL.GetData(getMroundGames);
}
}
And finaly my DAL looks like this;
public class DAL
{
public static SqlConnection GetConnection()
{
SqlConnection conn = new
SqlConnection(ConfigurationManager.ConnectionStrings["tiptopConnectionString"].ConnectionString);
conn.Open();
return conn;
}
public static DataTable GetData(SqlCommand command)
{
try
{
using (SqlConnection conn = GetConnection())
{
using (DataSet ds = new DataSet())
{
using (SqlDataAdapter da = new SqlDataAdapter())
{
da.SelectCommand = command;
da.SelectCommand.Connection = conn;
da.Fill(ds);
return ds.Tables[0];
}
}
}
}
catch (Exception err)
{
throw new ApplicationException(string.Format("Felmeddelande:{0}", err.Message));
}
}
public static object ExecuteScalar(SqlCommand command)
{
using (SqlConnection conn = GetConnection())
{
command.Connection = conn;
object result = command.ExecuteScalar();
return result;
}
}
public static void ExecuteNonQuery(SqlCommand command)
{
using (SqlConnection conn = GetConnection())
{
command.Connection = conn;
command.ExecuteNonQuery();
}
}
}
Where to begin?
The signature for this is wrong;
public static void getMroundGames(string mrounddate)
You need to change it to something similar to ;
public static string getMroundGames(string mrounddate)
Retrieve the string value from your DAL and return to the consumer accordingly.
var dt = Dal.GetData();
return (string)dt.Rows[0]["field"];
However, in all honesty, I would not be passing a datatable from your DAL to your BLL. I would return the string directly or introduce a DTO and populate this from your DAL through your BLL, back to the consumer.
You need to add a return type of string to getMroundGameas(string mrounddate).
It's not clear what type of object DAL is, but you should also probably use ExecuteReader method, http://msdn.microsoft.com/en-us/library/bb344397.aspx
rather then ExecuteNonQuery. This will return a Reader which can be queried for the value returned by the select statement.
Finally you should return the value.

How to mock SqlParameterCollection using Moq

I am trying to mock database operations. I have problem in mocking SqlParameterCollection. I tried to create virtual method that will return DbParameterCollection but then i am loosing all the functionality that SqlParameterCollection gives like AddWithValue etc. Is there a way i can mock SqlParameterCollection? Is there any other approach to unit test DAL? I am using Moq.
Code goes like this:
in DAL:
protected virtual IDbConnection GetConnection(string connectionString)
{
return new SqlConnection(connectionString);
}
protected virtual IDbCommand GetCommand(IDbConnection cn)
{
return cn.CreateCommand();
}
protected virtual IDbTransaction GetTransaction(IDbConnection cn)
{
return cn.BeginTransaction(IsolationLevel.Serializable);
}
Public Bool InsertInDatabase(DataTable dt)
{
using (IDbConnection cn = GetConnection(cnstr))
{
cn.Open();
using (IDbTransaction tran = GetTransaction(cn))
{
IDbCommand cmd = GetCommand(cn);
cmd.Transaction = tran;
cmd.Connection = cn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sp_InsertInDatabase";
SqlParameterCollection cmdParams = cmd.Parameters as SqlParameterCollection;
cmdParams.AddWithValue("#param1", dt);
cmd.ExecuteNonQuery();
}
}
}
In Unit test project:
protected override IDbConnection GetConnection(string connectionString)
{
return Mock.Of<IDbConnection>();
}
protected override IDbCommand GetCommand(IDbConnection cn)
{
return Mock.Of<IDbCommand>();
}
protected override IDbTransaction GetTransaction(IDbConnection cn)
{
return Mock.Of<IDbTransaction>();
}
public void TestInsertInDatabase()
{
base.InsertInDatabase(new DataTable());
}
--Solution--
Created an extension method to add parameter with value. Thank you Marc Gravell for pointing me to that direction.
public static IDbDataParameter AddParameterWithValue(this IDbCommand cmd, string paramName, object paramValue)
{
var dbParam = cmd.CreateParameter();
if (dbParam != null)
{
dbParam.ParameterName = paramName;
dbParam.Value = paramValue;
}
return dbParam;
}
Personally, I approach this problem by writing an AddParameterWithValue extension method to DbCommand (or IDbCommand). It has to be on the command so that you have access to CreateParameter, and then call .Parameters.Add.
This allows easy usage against any ADO.NET stack, including abstractions like logging decorators.
#Asdfg HI I have basically mocked the parameter collection as below
string connectionString = "connectionstring";
var sqlConnection = new SqlConnection(connectionString);
var command = sqlConnection.CreateCommand();
//****************Setup Mock************************//
Castle.DynamicProxy.Generators.AttributesToAvoidReplicating.Add(typeof(System.Data.SqlClient.SqlClientPermissionAttribute));
var mockDataReader1 = new Mock<IDataReader>();
command.Parameters.Add(new SqlParameter("#po_tint_Result", 1));
//setup read return value
Queue<bool> responseQueue = new Queue<bool>();
responseQueue.Enqueue(true);
responseQueue.Enqueue(false);
mockDataReader1.Setup(a => a.Read()).Returns(() => responseQueue.Dequeue());
var mockDb = new Mock<SqlDatabase>(connectionString);
mockDb.Setup(a => a.GetStoredProcCommand("SPNAME")).Returns(command);
mockDb.Setup(a => a.ExecuteNonQuery(command));
obj1.DbConn = mockDb.Object;
//*************************************************//
Hope this helps
Hi i found the solution.
I had to implement a Moq for the IDataParameterCollection interface and had to send it to the instance of IDbCommand.
With that my IDbCommand.Parameters object became different from null.
public static IDbConnection IDbConnectionMock(int valReturn)
{
var dataParameterCollection = new Mock<IDataParameterCollection>();
var command = new Mock<IDbCommand>();
command.Setup(x => x.Parameters).Returns(dataParameterCollection.Object);
command.Setup(x => x.ExecuteNonQuery()).Returns(valReturn);
var connection = DbConnectionMock_Success(command.Object);
return connection;
}

Categories

Resources