This question is about using XUnit with ADO.NET for a To Do List app using Nancy. I'm hoping for some insight on why an Assert.Equal test is failing, even though the outputs appear to be identical.
I have a Task class with two properties: id and description.
The database for this app has a corresponding tasks table. User input is used for the description, and the id is an auto-incrementing identity column.
The Task class has a static List property All(). Each task is added to All(), and you can retrieve the list of all tasks by calling Task.All().
Here's the Task class:
namespace ToDoList
{
public class Task
{
private int id;
private string description;
public Task(string Description, int Id = 0)
{
id = Id;
description = Description;
}
public int GetId()
{
return id;
}
public string GetDescription()
{
return description;
}
public void SetDescription(string newDescription)
{
description = newDescription;
}
public static List<Task> All()
{
List<Task> AllTasks = new List<Task>{};
SqlConnection conn = DB.Connection();
SqlDataReader rdr = null;
conn.Open();
SqlCommand cmd = new SqlCommand("SELECT * FROM tasks", conn);
rdr = cmd.ExecuteReader();
while(rdr.Read())
{
int taskId = rdr.GetInt32(0);
string taskDescription = rdr.GetString(1);
Task newTask = new Task(taskDescription, taskId);
AllTasks.Add(newTask);
}
conn.Close();
return AllTasks;
}
public void Save()
{
SqlConnection conn = DB.Connection();
SqlDataReader rdr;
conn.Open();
SqlCommand cmd = new SqlCommand("INSERT INTO tasks (description) OUTPUT INSERTED.id VALUES (#TaskDescription)", conn);
SqlParameter testParameter = new SqlParameter();
testParameter.ParameterName = "#TaskDescription";
testParameter.Value = this.GetDescription();
cmd.Parameters.Add(testParameter);
rdr = cmd.ExecuteReader();
while(rdr.Read())
{
this.id = rdr.GetInt32(0);
}
conn.Close();
}
public static void DeleteAll()
{
SqlConnection conn = DB.Connection();
conn.Open();
SqlCommand cmd = new SqlCommand("DELETE FROM tasks;", conn);
cmd.ExecuteNonQuery();
}
}
I define DB.Connection as the connection string in Startup.cs:
...
public class DB
{
public static SqlConnection Connection()
{
SqlConnection conn = new SqlConnection("Data Source=(localdb)\\mssqllocaldb;Initial Catalog=todo_test;Integrated Security=SSPI;");
return conn;
}
}
...
Now here's the test I use to see if it works:
namespace ToDoList
{
public class ToDoTest : IDisposable
{
[Fact]
public void Test_All()
{
//Arrange
var description = "Wash the dog";
var description2 = "Water the plants";
Task testTask = new Task(description);
testTask.Save();
Task testTask2 = new Task(description2);
testTask2.Save();
//Act
List<Task> result = Task.All();
List<Task> testList = new List<Task>{testTask, testTask2};
//Assert
Assert.Equal(result, testList);
}
public void Dispose()
{
Task.DeleteAll();
}
}
}
The output in the console only says that the test failed:
ToDoList.ToDoTest.Test_All [FAIL]
Assert.Equal() Failure
Expected: List<Task> [Task { }, Task { }]
Actual: List<Task> [Task { }, Task { }]
I did some console logs, and the ids and descriptions for the tasks in each list are identical.
In addition, when I test with:
List<Task> result = new List<Task>{testTask, testTask2};
List<Task> testList = new List<Task>{testTask, testTask2};
The test passes.
I'm not really sure how to approach this to see why the test is failing. Any ideas would be great!
You need to overwrite the Task.Equals() method for that Assert.Equal() to succeed, otherwise the default reference equals semantics will be applied.
Related
Trying to return value from GetStage_details() methods and bind it to ViewBag.Stage_details but getting error at var result.
Error msg is :
can't implicitly convert type oracle.ManagedDtaAccessclient.oracledatareader to System.Collection.generic.List<Models.Stage_Details."
Any idea how to resolve it show that correct value return from table and bind to ViewBag.Stage_details will be appreciated.
public class Stage_details
{
public int Stage_Cd { get; set; }
public string Stage_Desc { get; set; }
}
public ActionResult Index_shift()
{
ViewBag.Stage_details = new SelectList(GetStage_details(), "Stage_Cd", "Stage_Desc");
}
private List<Stage_details> GetStage_details()
{
List<Stage_details> Stage_detail = new List<Stage_details>();
OracleConnection conn = new
OracleConnection(ConfigurationManager.ConnectionStrings["Mycon"].ToString());
conn.Open();
string cmdText= "select a.stage_cd,a.stage_desc from Stage_Mst a";
OracleCommand command = new OracleCommand(cmdText,conn);
command.CommandType = CommandType.Text;
var result = command.ExecuteReader();
return result;
}
According to Microsoft documentation, You could read each element from reader and build Stage_detail object inside loop, like the following code :
private List<Stage_details> GetStage_details()
{
List<Stage_details> Stage_detail = new List<Stage_details>();
OracleConnection conn = new
OracleConnection(ConfigurationManager.ConnectionStrings["Mycon"].ToString());
conn.Open();
string cmdText = "select a.stage_cd,a.stage_desc from Stage_Mst a";
OracleCommand command = new OracleCommand(cmdText, conn)
{
CommandType = CommandType.Text
};
using (OracleDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Stage_detail.Add(new Stage_details { Stage_Cd = (int)reader["stage_cd"], Stage_Desc = reader["stage_desc"].ToString() });
}
}
return Stage_detail;
}
I hope you find this helpful.
I have created a database with 1 table "emp" and have some data in it. Now every time i start the app, i want a list to fetch the data from db and save it in list because i want to perform some calculations like tax and Gross-Salary on data at runtime for display only(don't want to save it in db ). I have tried many times but i am unable to understand how this can be done. This is my code:
Main Class:
static void Main(string[] args)
{
empDB empDB1 = new empDB();
List<emplyee> empLST1 = new List<emplyee>();
if (empLST1 == null)
{
empDB1.loadLST(out empLST1);
}
}
empDB Class:
class empDB
{
private string ConnectionString = #"server=localhost;DATABASE=hris;uid=root;Password=123456;";
internal void loadLST(out List<emplyee> loadedLST)
{
string query = "select name, grade from emp";
try
{
MySqlConnection con = new MySqlConnection(ConnectionString);
con.Open();
MySqlDataReader rdr = null;
MySqlCommand cmd = new MySqlCommand(query, con);
rdr = cmd.ExecuteReader();
while(rdr.Read())
{
List<employee> returnedLst = new List<employee>();
returnedLst.Add(rdr["name"].ToString(), rdr["grade"].ToString());
}
loadedLst = returnedLst;
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
I have no idea even if my approach is right or not. I have googled it a few times but i just started working in .net a few days ago so i don't understand how to do it.
Okay i tried this and it also dosn't work:
internal void GetDatabaseList()
{
List<employee> databases = new List<employee>();
MySqlConnection con = new MySqlConnection(ConnectionString);
{
con.Open();
DataTable tbl = con.GetSchema("Databases");
con.Close();
foreach (DataRow row in tbl.Rows)
{
databases.Add(row["hris"].ToString());
}
}
}
static void Main(string[] args)
{
empDB empDB1 = new empDB();
List<emplyee> empLST1 = new List<emplyee>();
**if (empLST1 == null)
{
empDB1.loadLST(out empLST1);
}**
}
this will always be false because you defined empLST1 as a new List, meaning its not null
try this
public class Employee
{
public string Name { get; set; }
public string Grade { get; set; }
}
static void Main(string[] args)
{
empDB empDB1 = new empDB();
List<Employee> empLST1 = new List<Employee>();
empDB1.loadLST(ref empLST1);
}
public class empDB
{
public void loadLst(ref List<Employee> loadedLST)
{
string query = "select name, grade from emp";
try
{
MySqlConnection con = new MySqlConnection(ConnectionString);
con.Open();
MySqlDataReader rdr = null;
MySqlCommand cmd = new MySqlCommand(query, con);
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Employee emp = new Employee();
emp.Name = rdr["name"].ToString();
emp.Grade = rdr["grade"].ToString();
loadedLST.Add(emp);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Assuming, that that employee class looks like this:
class employee
{
public string Name { get; set; }
public string Grade { get; set; }
}
I'd rewrite loadLST like this:
internal List<employee> loadLST()
{
string query = "select name, grade from emp";
// we should dispose IDisposable implementations:
// connection, command and data reader
using (var con = new MySqlConnection(ConnectionString))
{
con.Open();
using (var cmd = new MySqlCommand(query, con))
using (var rdr = cmd.ExecuteReader())
{
// it is hard to maintain manual mapping
// between query results and objects;
// let's use helper like Automapper to make this easier
Mapper.CreateMap<IDataReader, employee>();
Mapper.AssertConfigurationIsValid();
return Mapper.Map<List<employee>>(rdr);
}
}
}
Improvements:
IDisposable implementations must be disposed explicitly (see this and this)
to avoid manual mapping code, which maps the result from data reader and object (employee instance in your case), the code uses Automapper package
exception handling and out parameter are thrown away. There's no need for exception handling and out parameter here, unless you're writing method like TryToDoSomething (and even in that case your method must return bool to indicate the state of operation, and catch only specific exceptions instead of Exception).
Also note, that your code doesn't match naming guidelines (e.g., employee should be Employee).
We know that "Action, Func and Predicate are pre-defined Generic delegates. So as delegate they can point to functions with specified signature."
I have following data-access scenario in which Func<T,R> helps in avoiding a foreach loop in the calling method. The approach 2 doesn’t have looping. Here Func<T,R> helped to avoid loop.
What are the other scenarios for generic delegates in which it can save lots of lines of code?
REFERENCES
Dynamically Composing Expression Predicates
Advanced C#
C#/.NET Little Wonders: The Predicate, Comparison, and Converter Generic Delegates
Func vs. Action vs. Predicate
What is Func, how and when is it used
How can I pass in a func with a generic type parameter?
CODE
Approach 1
public class MyCommonDAL
{
public static IEnumerable<IDataRecord> ExecuteQueryWithTextCommandType(string commandText, List<SqlParameter> commandParameters)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = commandText;
command.CommandTimeout = 0;
command.Parameters.AddRange(commandParameters.ToArray());
connection.Open();
using (var rdr = command.ExecuteReader())
{
while (rdr.Read())
{
yield return rdr;
}
rdr.Close();
}
}
}
}
}
public class MyLogDAL
{
public List<LogSeverityType> GetLogSeveritiesFirstApproach(LogSeverityType logSeverityType)
{
List<SqlParameter> commandParameters = new List<SqlParameter>()
{
new SqlParameter {ParameterName = "#CreatedDateTime",
Value = logSeverityType.CreatedDateTime,
SqlDbType = SqlDbType.DateTime}
};
string commandText = #"SELECT * FROM dbo.LogSeverityType WHERE CreatedDateTime > #CreatedDateTime";
var results = MyCommonDAL.ExecuteQueryWithTextCommandType(commandText, commandParameters);
List<LogSeverityType> logSeverities = new List<LogSeverityType>();
//LOOP
foreach (IDataRecord rec in results)
{
LogSeverityType objLogSeverityType = LogSeverityType.LogSeverityTypeFactory(rec);
logSeverities.Add(objLogSeverityType);
}
return logSeverities;
}
}
Approach 2
public class MyCommonDAL
{
public static IEnumerable<T> ExecuteQueryGenericApproach<T>(string commandText, List<SqlParameter> commandParameters, Func<IDataRecord, T> factoryMethod)
{
//Action, Func and Predicate are pre-defined Generic delegates.
//So as delegate they can point to functions with specified signature.
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.CommandType = CommandType.Text;
command.CommandText = commandText;
command.CommandTimeout = 0;
command.Parameters.AddRange(commandParameters.ToArray());
connection.Open();
using (var rdr = command.ExecuteReader())
{
while (rdr.Read())
{
yield return factoryMethod(rdr);
}
rdr.Close();
}
}
}
}
}
public class MyLogDAL
{
public List<LogSeverityType> GetLogSeveritiesSecondApproach(LogSeverityType logSeverityType)
{
List<SqlParameter> commandParameters = new List<SqlParameter>()
{
new SqlParameter {ParameterName = "#CreatedDateTime",
Value = logSeverityType.CreatedDateTime,
SqlDbType = SqlDbType.DateTime}
};
string commandText = #"SELECT * FROM dbo.LogSeverityType WHERE CreatedDateTime > #CreatedDateTime";
//var results = MyCommonDAL.ExecuteQueryWithTextCommandType(commandText, commandParameters);
IEnumerable<LogSeverityType> logSeverities = MyCommonDAL.ExecuteQueryGenericApproach<LogSeverityType>(commandText, commandParameters, LogSeverityType.LogSeverityTypeFactory);
//foreach (IDataRecord rec in results)
//{
// LogSeverityType objLogSeverityType = LogSeverityType.LogSeverityTypeFactory(rec);
// logSeverities.Add(objLogSeverityType);
//}
return logSeverities.ToList();
}
}
Other Code Required
public class LogSeverityType
{
public int LogSeverityTypeID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime CreatedDateTime { get; set; }
public static LogSeverityType LogSeverityTypeFactory(IDataRecord record)
{
return new LogSeverityType
{
LogSeverityTypeID = (int)record[0],
Name = (string) record[1],
Description = (string)record[2],
CreatedDateTime = (DateTime) record[3]
};
}
}
static void Main(string[] args)
{
MyLogDAL logDAL = new MyLogDAL();
LogSeverityType logSeverityType = new LogSeverityType();
logSeverityType.CreatedDateTime = Convert.ToDateTime("1/1/2000");
List<LogSeverityType> logSeverities = logDAL.GetLogSeveritiesSecondApproach(logSeverityType);
}
I use generic delegates when parsing / finding nodes in XML / HTML documents, and assigning the values to properties. I wrote a blog post about it, which shows refactoring the code to pass in a generic delegate, and how much code was removed.
I tried using Run Code Analysis option in VisualStudio 2012, as a result of it I got a warning as
CA1001 Types that own disposable fields should be disposable
Implement IDisposable on 'DBConnectivity'
because it creates members of the following IDisposable types: 'SqlConnection', 'SqlCommand'.
I referred some question in SO, but I couldn't catch the point regarding IDisposable
and following is the class, responsible for this warning.
class DBConnectivity
{
public SqlConnection connection = null;
public SqlCommand command = null;
public SqlDataReader dataReader = null;
public string connectionString = null;
public List<MasterTableAttributes> masterTableList;
public DBConnectivity()
{
connectionString = ConfigurationManager.ConnectionStrings["Master"].ConnectionString;
connection = new SqlConnection(connectionString.ToString());
//-----Master table results
connection.Open();
string masterSelectQuery = "SELECT * FROM MASTER_TABLE";
command = new SqlCommand(masterSelectQuery, connection);
dataReader = command.ExecuteReader();
masterTableList = new List<MasterTableAttributes>();
while (dataReader.Read())
{
MasterTableAttributes masterTableAttribute = new MasterTableAttributes()
{
fileId = Convert.ToInt32(dataReader["Id"]),
fileName = Convert.ToString(dataReader["FileName"]),
frequency = Convert.ToString(dataReader["Frequency"]),
scheduledTime = Convert.ToString(dataReader["Scheduled_Time"])
};
masterTableList.Add(masterTableAttribute);
}
dataReader.Close();
connection.Close();
}
}
I am really confused in implementing the IDisposable. Any help appreciated?
I fully agree with the compiler - you need to dispose your fields here, or (as already noted) - not make them fields in the first place:
class DBConnectivity : IDisposable // caveat! read below first
{
public void Dispose() {
if(connection != null) { connection.Dispose(); connection = null; }
if(command != null) { command.Dispose(); command = null; }
if(dataReader != null) { dataReader.Dispose(); dataReader = null; }
}
Note that you would then use this type via using(...)
However! It looks like a static method would be more appropriate:
static class DBConnectivity
{
public static List<MasterTableAttributes> GetMasterTableList()
{
var connectionString = ConfigurationManager.ConnectionStrings["Master"].ConnectionString;
using(var connection = new SqlConnection(connectionString))
{
connection.Open();
const string masterSelectQuery = "SELECT * FROM MASTER_TABLE";
using(var command = new SqlCommand(masterSelectQuery, connection))
using(var dataReader = command.ExecuteReader())
{
var masterTableList = new List<MasterTableAttributes>();
while (dataReader.Read())
{
MasterTableAttributes masterTableAttribute = new MasterTableAttributes()
{
fileId = Convert.ToInt32(dataReader["Id"]),
fileName = Convert.ToString(dataReader["FileName"]),
frequency = Convert.ToString(dataReader["Frequency"]),
scheduledTime = Convert.ToString(dataReader["Scheduled_Time"])
};
masterTableList.Add(masterTableAttribute);
}
return masterTableList;
}
}
}
}
or perhaps simpler with a tool like "dapper":
static class DBConnectivity
{
public static List<MasterTableAttributes> GetMasterTableList()
{
var connectionString = ConfigurationManager.ConnectionStrings["Master"].ConnectionString;
using(var connection = new SqlConnection(connectionString))
{
connection.Open();
const string sql = "SELECT Id as [FileId], FileName, Frequency, Scheduled_Time as [ScheduledTime] FROM MASTER_TABLE";
return connection.Query<MasterTableAttributes>(sql).ToList();
}
}
}
If that is you complete class you should move all the SQL variables inside the constructor. Or perhaps change the constructor to a static function that return the masterTableList
I am wondering what's a better way to abstract some of this code, into a simple DAL. At this time, I'm just patching the code and don't have time or need yet to use EF, Linq2Sql or any ORM right now.
public string GetMySpecId(string dataId)
{
using (SqlConnection conn = new SqlConnection(this.MyConnectionString))
{
conn.Open();
// Declare the parameter in the query string
using (SqlCommand command = new SqlCommand(#"select ""specId"" from ""MyTable"" where ""dataId"" = :dataId", conn))
{
// Now add the parameter to the parameter collection of the command specifying its type.
command.Parameters.Add(new SqlParameter("dataId", SqlDbType.Text));
command.Prepare();
// Now, add a value to it and later execute the command as usual.
command.Parameters[0].Value = dataId;
using (SqlDataReader dr = command.ExecuteReader())
{
while (dr.Read())
{
specId = dr[0].ToString();
}
}
}
}
return specId;
}
What's a good clean way to pull the connection, commands, and such out of the GetMySpecId() as I will have tons of these functions and don't want to write the using.... over and over again.
Well, you could write your own custom data-access helper that encapsulates all that stuff and returns a DataTable:
public string GetMySpecId(string dataId)
{
DataTable result = _dbHelper.ExecuteQuery(
#"select ""specId"" from ""MyTable"" where ""dataId"" = :dataId",
new SqlParameter("dataId", dataId);
return result.Rows[0][0].ToString();
}
Or if you are stuck on the idea of using a DataReader, you could pass a delegate to the helper, which gets invoked inside of the using statements:
public string GetMySpecId(string dataId)
{
return _dbHelper.ExecuteQuery(
dr =>
{
if(dr.Read())
{
return dr[0].ToString();
}
// do whatever makes sense here.
},
#"select ""specId"" from ""MyTable"" where ""dataId"" = :dataId",
new SqlParameter("dataId", dataId));
}
You could also use a lightweight tool like Dapper to simplify some of the syntax and take care of mapping to your data types. (You'd still need to deal with opening a connection and such.)
Update
Here's an example of how you could write the ExecuteQuery method used in the second example:
public T ExecuteQuery<T>(
Func<IDataReader, T> getResult,
string query,
params IDataParameter[] parameters)
{
using (SqlConnection conn = new SqlConnection(this.MyConnectionString))
{
conn.Open();
// Declare the parameter in the query string
using (SqlCommand command = new SqlCommand(query, conn))
{
foreach(var parameter in parameters)
{
command.Parameters.Add(parameter);
}
command.Prepare();
using (SqlDataReader dr = command.ExecuteReader())
{
return getResult(dr);
}
}
}
}
You could use the yield return statement in order to keep the connection, command and reader objects inside using statements.
public class ScalarReader<T>
{
const string MyConnectionString = "...";
private string _returnColumn, _table, _whereCond;
private object[] _condParams;
public ScalarReader(string returnColumn, string table, string whereCond,
params object[] condParams)
{
_returnColumn = returnColumn;
_table = table;
_whereCond = whereCond;
_condParams = condParams;
}
public IEnumerator<T> GetEnumerator()
{
using (SqlConnection conn = new SqlConnection(MyConnectionString)) {
conn.Open();
string select = String.Format(#"SELECT ""{0}"" FROM ""{1}"" WHERE {2}",
_returnColumn, _table, _whereCond);
using (SqlCommand command = new SqlCommand(select, conn)) {
for (int p = 0; p < _condParams.Length; p++) {
command.Parameters.AddWithValue("#" + (p+1), _condParams[p]);
}
using (SqlDataReader dr = command.ExecuteReader()) {
while (dr.Read()) {
if (dr.IsDBNull(0)) {
yield return default(T);
} else {
yield return (T)dr[0];
}
}
}
}
}
}
}
You would call it like this
var reader = new ScalarReader<string>("specId", "MyTable", "dataId=#1", "x");
foreach (string id in reader) {
Console.WriteLine(id);
}
Note that I am using a convention for the parameter names. They are named #1, #2, #3 ....
var reader =
new ScalarReader<DateTime>("date", "MyTable", "num=#1 AND name=#2", 77, "joe");
You would need to return an IDataReader from the middle of your using statement and as soon as you do that, you will lose the connection and the data. You can't really do what you are after.
You could do something like this, sorry for no actual code, but it will give you the idea. Of course it will have to be careful converting object[] back into something useful, but you're sort of doing that already with specId = dr[0].ToString();
class MyDb
{
public MyDb()
{
}
public void Initialize()
{
// open the connection
}
public void Finalize()
{
// close the connection
}
public List<object[]> Query(string command, List<SqlParameter> params)
{
// prepare command
// execute reader
// read all values into List of object[], and return it
}
}
You can create a base abstract class that will have some base function with all the usings and base code like so:
public abstract class BaseClass
{
public abstract void myFunc(SqlConnection conn);
public void BaseFunc()
{
using (SqlConnection conn = new SqlConnection(this.MyConnectionString))
{
conn.Open();
myFunc(conn);
..any other base implementation...
}
}
}
each derived class will inheret the BaseClass and implement the abstract MyFunc with the specific query and all the specific stuff for each derived class. You will call from outside the BaseFunc function of the base abstract class.