I need a static method to convert DataTables(dynamic) to List(again dynamic Entity)
here is my code
help would be appereciated
public static ICollection<System.Data.Entity.Core.Objects.DataClasses.EntityObject> DtToEntity(DataTable DataTable,System.Data.Entity.Core.Objects.DataClasses.EntityObject EntityObject)
{
ICollection<System.Data.Entity.Core.Objects.DataClasses.EntityObject> _list = null;
System.Data.Entity.Core.Objects.DataClasses.EntityObject _tempClass;
foreach (DataRow dataRow in DataTable.Rows)
{
foreach(DataColumn dataColumn in DataTable.Columns)
{
foreach (var attribute in EntityObject.GetType().GetProperties())
{
if (attribute.Name == dataColumn.ColumnName && attribute.GetType().Equals(dataColumn.GetType()))
{
return _list;
}
}
}
}
private static List<T> ConvertDataTable<T>(DataTable dt)
{
List<T> data = new List<T>();
foreach (DataRow row in dt.Rows)
{
T item = GetItem<T>(row);
data.Add(item);
}
return data;
}
private static T GetItem<T>(DataRow dr)
{
Type temp = typeof(T);
T obj = Activator.CreateInstance<T>();
foreach (DataColumn column in dr.Table.Columns)
{
foreach (PropertyInfo pro in temp.GetProperties())
{
if (pro.Name == column.ColumnName)
pro.SetValue(obj, dr[column.ColumnName], null);
else
continue;
}
}
return obj;
}
Usage:
List< Student > studentDetails = new List<Student>();
studentDetails = ConvertDataTable<Student>(dt);
Source: http://www.c-sharpcorner.com/UploadFile/ee01e6/different-way-to-convert-datatable-to-list/
So basically you want use this structure for your mvc .net core app with dependency injection and ado.net for orm The problem that was first initiated this question was when using ado.net you have to map data table to c# object manually.But in extends of years it got grown and now you can easily implement this structure on your application which is dapper like functionality.I grant this is a small sized.But I think this is the fastest way you can actually get results from sql server.Personally you might use dapper which I also suggest to do.It is nice peace of code which I think deserve to go to wiki for future references
You start with repository which has db context factory injected into it. I used factory pattern for db context because you might want to use multiple instances of sql server on your application. Then factory pattern will be needed. I suggest create a small db for you basic information and make that factory singleton. In this manner a lot of time and effort of fetching data would be eliminated in the first place. In the first method of repo there is example functionality to showcase the design you so you use factory to fetch the result and cast it as object by covert data table function which was provided in previous answer(thank you very much #Nikhil Vartak) .So you have it!. In the further of the post I included convert data table functions to this post and which was main reason of this question. Others are parts of normal .net core or .net normality which is not concern of this post
/* repo */
public class repo
{
private readonly IDBContextFactory dBContextFactory;
public repo(IDBContextFactory _dbContextFactory)
{
_dbContextFactory=dBContextFactory;
}
public string GetLastRecord()
{
List< Student > studentDetails = new List<Student>();
studentDetails = ConvertDataTable<Student>(_dbCtextFactory.Select("mydb","select * from StudentDetail");
/*refrence from this post https://stackoverflow.com/questions/33515552/converting-datatable-to-listentity-projectdracula */;
}
}
/* interface of repo */
public interface IRepo
{
public string GetLastRecord();
}
/* controller */
public class mycontroller:BaseController
{
private readonly IRepo repo;
public mycontroller(IRepo _repo)
{
_repo=repo;
}
[httpGet]
public IActionResult<string> GetLastRecord()
{
return _repo.GetLastRecord();
}
}
/* some factory pattern for db context (multiple dbs) */
public class DBContextFactory
{
private SqlCommand BuildFactory(string dbName)
{
switch(dbName)
{
case 'mydb':
return CreateMyDB();
}
}
private SqlCommand CreateMyDB()
{
string connectionString = "your connection string";
SqlConnection connection =
new SqlConnection(connectionString));
SqlCommand command = new SqlCommand(connection);
return command.Open();
}
//Private SqlCommand GetMyOpenCommand()
public DataTable Select(string dbName,string query)
{
SqlDataAdapter dataAdapter=new SqlDataAdapter();
dataAdapter.SelectCommand=BuildFactory(dbName);
DataTable dt =new DataTable();
dataAdapter.Fill(dt);
con.Close();
return dt;
}
}
/* factory in dependncy pattern */
public inteface IDBContextFactory
{
SqlCommand BuildFactory(string dbName);
SqlCommand CreateMyDB();
DataTable Select(string dbName,string query)
}
/****** HERE IS YOUR GENERIC FILE ******/
private static List<T> ConvertDataTable<T>(DataTable dt)
{
List<T> data = new List<T>();
foreach (DataRow row in dt.Rows)
{
T item = GetItem<T>(row);
data.Add(item);
}
return data;
}
private static T GetItem<T>(DataRow dr)
{
Type temp = typeof(T);
T obj = Activator.CreateInstance<T>();
foreach (DataColumn column in dr.Table.Columns)
{
foreach (PropertyInfo pro in temp.GetProperties())
{
if (pro.Name == column.ColumnName)
pro.SetValue(obj, dr[column.ColumnName], null);
else
continue;
}
}
return obj;
}
/***** END OF GENERIC PART *****/
/* USAGE OF GENERIC */
List< Student > studentDetails = new List<Student>();
studentDetails = ConvertDataTable<Student>(dt);
Related
I want to dynamically generate a class based on the results from a query that user submits. For instance, if the user enters Select name, age from tbl, the result is a name column which is string and age which is an int. The resulting class should be:
public class Test
{
public string Name { get; set; }
public int Age { get; set; }
}
Is there an efficient way to do this via EntityFramework or features in C# or I have to use maybe reflection to create a new type and instantiate it.
PS: My purpose is to run this query on the database and show the results in a Grid to the user and run some filter/sort/etc. on it.
You could use TypeBuilder to create a new type and execute the query against database using EF's SqlQuery() as mentioned here.
OR
A cleaner method would be to use dynamic objects to bind the grid. Extend EF to return a collection of dynamic objects as suggested by ChristineBoersen here. The code was written before EF went to RTM. Here's a version that works:
public static class EFExtensions
{
public static IEnumerable<dynamic> CollectionFromSql(this DbContext dbContext, string Sql, Dictionary<string, object> Parameters)
{
using (var cmd = dbContext.Database.Connection.CreateCommand())
{
cmd.CommandText = Sql;
if (cmd.Connection.State != ConnectionState.Open)
cmd.Connection.Open();
foreach (KeyValuePair<string, object> param in Parameters)
{
DbParameter dbParameter = cmd.CreateParameter();
dbParameter.ParameterName = param.Key;
dbParameter.Value = param.Value;
cmd.Parameters.Add(dbParameter);
}
//var retObject = new List<dynamic>();
using (var dataReader = cmd.ExecuteReader())
{
while (dataReader.Read())
{
var dataRow = GetDataRow(dataReader);
yield return dataRow;
}
}
}
}
private static dynamic GetDataRow(DbDataReader dataReader)
{
var dataRow = new ExpandoObject() as IDictionary<string, object>;
for (var fieldCount = 0; fieldCount < dataReader.FieldCount; fieldCount++)
dataRow.Add(dataReader.GetName(fieldCount), dataReader[fieldCount]);
return dataRow;
}
}
You could invoke the above method as follows:
var results = context.CollectionFromSql("Select Name, Age from tbl", new Dictionary<string, object>()).ToList();
// Bind results to grid
I am trying the below way to return the dynamic results using dapper and stored procedure. Am I doing it in correct way?
using (IDbConnection dbConnection = Connection)
{
dbConnection.Open();
var result = dbConnection.Query<dynamic>("LMSSP_GetSelectedTableData",
new
{
TableName = TableName,
LangaugeID = AppTenant.SelectedLanguageID,
UserID = AppTenant.UserID
}, commandType: CommandType.StoredProcedure).ToList();
if (result != null)
{
// Added just for checking the data
foreach (var item in (IDictionary<string, object>)result.FirstOrDefault())
{
string key = item.Key;
string value = item.Value.ToString();
}
}
}
What my stored procedure do is, I will pass any table name and based on that it will return the results/records.So, obviously my number of records, columns will be varied as per the table name passed.
To achieve this I have used dynamic keyword along with dapper.
So my question is how can I pass this data to view as a model and render the controls on the view as per the properties/column data type. Can I get the data type of column OR PropertyInfo?
But, when dapper retrieves the records from database it returns as dapper row type?
Using same SP to fetch data from different table would be confusing (not good design). However to solve your problem technically, you can create model having list of control information. Example of control information
public class ControlInformation
{
public string Name { get; set; }
public dynamic Value { get; set; }
public string ControlType { get; set; }
// Applicable for drop down or multi select
public string AllValues { get; set; }
}
Model will have list of ControlInformations
public List<ControlInformation> ControlInformations { get; set; }
View will render the controls (partial view based on control type) Ex: very basic case to render different view for int and another view for rest. I have 2 partial views "IntCtrl" and "StringCtrl".
#foreach (var item in Model.ControlInformations)
{
if (#item.ControlType == "System.Int32")
{
Html.RenderPartial("IntCtrl", item);
}
else
{
Html.RenderPartial("StringCtrl", item);
}
}
Hope this help.
Here we are calling method which returns Datatable :
public DataTable GetMTDReport(bool isDepot, int userId)
{
using (IDbConnection _connection = DapperConnection)
{
var parameters = new DynamicParameters();
parameters.Add("#IsDepot", isDepot);
parameters.Add("#userId", userId);
var res = this.ExecuteSP<dynamic>(SPNames.SSP_MTDReport, parameters);
return ToDataTable(res);
}
}
In this we can call stored procedures by calling our custom method "ExecuteSP" :
public virtual IEnumerable<TEntity> ExecuteSP<TEntity>(string spName, object parameters = null)
{
using (IDbConnection _connection = DapperConnection)
{
_connection.Open();
return _connection.Query<TEntity>(spName, parameters, commandTimeout:0 , commandType: CommandType.StoredProcedure);
}
}
and here is "DapperConnection" method to connect the database:
You can give connection string with key ["MainConnection"]
public class DataConnection
{
public IDbConnection DapperConnection
{
get
{
return new SqlConnection(ConfigurationManager.ConnectionStrings["MainConnection"].ToString());
}
}
}
And at last we call "ToDataTable" method to change our response in datatable . We will receive response in DapperRow from the database because we passsed dynamic type in stored procedure.
public DataTable ToDataTable(IEnumerable<dynamic> items)
{
if (items == null) return null;
var data = items.ToArray();
if (data.Length == 0) return null;
var dt = new DataTable();
foreach (var pair in ((IDictionary<string, object>)data[0]))
{
dt.Columns.Add(pair.Key, (pair.Value ?? string.Empty).GetType());
}
foreach (var d in data)
{
dt.Rows.Add(((IDictionary<string, object>)d).Values.ToArray());
}
return dt;
}
Ok, I have 3 classes: Teacher, Student and Database for that matter. I wanna read data from database and put it in Teacher or Student. So i have to write something like this:
public Teacher dbSelect(string Table="Teacher")
{
Table = char.ToUpper(Table[0]) + Table.Substring(1);
string query = "SELECT * FROM " + Table + ";";
return dbConnect(query, true);
}
But i must have this exact Method with Student return:
public Student dbSelect(string Table="Student")
{
Table = char.ToUpper(Table[0]) + Table.Substring(1);
string query = "SELECT * FROM " + Table + ";";
return dbConnect(query, true);
}
Now I can write each one in their ViewModel, But I want to put them in Database class. So is there any way to do that?
(I know i can return them in a list and then work with that list, But just wanna know if there is a way or not!)
UPDATE:
I forgot to put dbConnect in here, so:
public List<Teacher> dbConnect(string query)
{
SQLiteConnection conn = null;
SQLiteCommand command = null;
SQLiteDataReader reader = null;
Teacher result = new Teacher(null, null, null, null, null, null, null, null);
// try
{
conn = new SQLiteConnection(db.db);
conn.Open();
command = new SQLiteCommand(query, conn);
reader = command.ExecuteReader();
}
// catch (Exception ex) { }
while (reader.Read())
{
Teacher temp = new Teacher(
reader[0].ToString(),
reader[1].ToString(),
reader[2].ToString(),
reader[3].ToString(),
reader[4].ToString(),
reader[5].ToString(),
reader[6].ToString(),
reader[7].ToString()
);
result.Items.Add(temp);
}
conn.Close();
return result.Items;
}
And again the exact thing exist for Student but returning:
public List<Student> dbConnect(string query)
{
...
}
Answer: I had a Base class and of course wanted to return a List with a specific type, So I used #Jauch answer, but with returning the List.
Here is an idea on how to do what you want, adapted from a code of mine:
public class BaseClass<T>
where T : new ()
{
protected List<object> list;
protected string query;
protected PropertyInfo[] fProperties;
protected Assembly fStoreAssembly;
public BaseClass()
{
list = new List<T>();
fStoreAssembly = Assembly.GetAssembly (typeof(T));
fProperties = typeof(T).GetProperties();
}
public void Read()
{
SQLiteConnection conn = null;
SQLiteCommand command = null;
SQLiteDataReader reader = null;
try
{
conn = new SQLiteConnection(db.db);
conn.Open();
command = new SQLiteCommand(query, conn);
reader = command.ExecuteReader();
StoreResults (reader);
conn.Close();
}
catch (Exception ex)
{
//deal with the exception here
}
}
//Store results walks through all the records returned and
//creates new instances of the store object and saves in the list,
//using reflection
protected void StoreResults (SQLiteDataReader reader)
{
if (fProperties == null)
throw new Exception ("Store type definition is missing");
while (reader.Read ())
{
object newStoreItem = fStoreAssembly.CreateInstance (typeof(T).FullName);
foreach (PropertyInfo pi in fProperties)
{
string lcName = pi.Name.ToLower ();
if (HasColumn(reader, lcName))
{
if (!reader.IsDBNull(reader.GetOrdinal(lcName)))
pi.SetValue(newStoreItem, reader[lcName], null);
}
}
list.Add (newStoreItem);
}
}
public bool HasColumn (SQLiteDataReader reader, string columnName)
{
foreach (DataRow row in reader.GetSchemaTable().Rows)
{
if (row ["ColumnName"].ToString () == columnName)
return true;
}
return false;
}
}
And here how you would create Teacher and Student
public class TeacherInfo
{
//Properties for store info from database
}
public class Teacher : BaseClass<TeacherInfo>
{
public Teacher ()
: BaseClass()
{
query = "whatever you want here"
}
}
public class StudentInfo
{
//Properties for store info from database
}
public class Student : BaseClass<StudentInfo>
{
public Student ()
: BaseClass()
{
query = "whatever you want here";
}
}
As the Read routine is public, you can call Read from any instance of Teacher or Student.
You can even create them and store as BaseClass and use it directly if you don't need to know if it is a student or a teacher (for common routines, etc)
This is not an extensive example, but just a point in the direction you could use to turn your code more generic.
You can follow the semantics of using interfaces to return the values and then cast the return type to an appropriate one, or use a base class (interfaces would be better, as you can still extend other classes as base classes while implementing the interface). The entity interface can be created as following,
public interface SchoolEntity {
// Provide the similar properties as members of this interface.
}
Then you can implement this interface in your Teacher and Student.
public class Student : SchoolEntity { }
public class Teacher : SchoolEntity { }
Finally, the parameter can be made a bit more clearer by using enumerations. They would be more clearer while reading, rather than having the same parameter types. Note that function overloading doesn't consider return type as a signature difference.
enum Entity { Teacher, Student }
And then you can check which data to return.
public SchoolEntity dbSelect(Entity type)
{
switch(type) {
case Teacher:
var query = "SELECT * FROM Teacher";
return dbConnect(query, true);
// Rest of the cases.
}
}
Note that, your SQL statement is open to SQL Injection and anyone can either drop the tables, or perform actions that can be passed to the engine.
Working in a list
Working with the list won't be a good idea. Afterall, what list would you return? Would that be, public List<Teacher> dbSelect or public List<Student> dbSelect? The answer and solution to this is to have a same type backing up these both types.
dbSelect function
Note that you are still returning only Teacher type, then why you are having a Student at all? You should definitely cast it back. As a matter of fact, if I had to develop this. I would have to the dbSelect function to take the Entity as a parameter to keep all of the database requests and processing in a single function.
public List<Teacher> dbConnect(Entity type)
{
SQLiteConnection conn = null;
SQLiteCommand command = null;
SQLiteDataReader reader = null;
Teacher result = null; // Can be set to null.
// try
{
conn = new SQLiteConnection(db.db);
conn.Open();
string query;
// This way, leave the function to build the query.
if(type == Entity.Teacher) {
query = "SELECT * FROM Teacher";
} else {
query = "SELECT * FROM Student";
}
command = new SQLiteCommand(query, conn);
reader = command.ExecuteReader();
}
// catch (Exception ex) { }
while (reader.Read())
{
if(type == Entity.Teacher) {
Teacher temp = new Teacher(
reader[0].ToString(),
reader[1].ToString(),
reader[2].ToString(),
reader[3].ToString(),
reader[4].ToString(),
reader[5].ToString(),
reader[6].ToString(),
reader[7].ToString()
);
result.Items.Add(temp);
} else {
// Add the student.
}
}
conn.Close();
return result;
}
Now in this code, you are aware result is of type Teacher. There was no list there and this made your code a bit confusing. Take my advice: Re-write the code.
Please also go through the following useful links:
Explicit Interface Implementation
https://en.wikipedia.org/wiki/SQL_injection
Signatures and overloading
I am trying to drop a collection of tables by using tables names in the list and then get the type of each string and drop it :
List<string> models = new List<string> { "WebBrowser", "Notebook", "Members"};
foreach (string mod in models)
{
Type type = Type.GetType(mod));
using (var dbConn = new SQLiteConnection(app.DBPath))
{
dbConn.RunInTransaction(() =>
{
dbConn.DropTable<type>();
//dbConn.DropTable<WebBrowser>();
dbConn.Dispose();
dbConn.Close();
});
}
}
Problem : I can't drop table using this way, DropTable need the name of class (e.g WebBrowser ) and I don't want to drop each table alone (i.e dbConn.DropTable< WebBrowser >();) since I have more than 50 tables to drop.
Error : "The type or namespace name 'type' could not be found". ( and this error is expected since there is no Class 'type' in my Namespace .
You can drop tables using a SQL command in SQLite. All you need to do is iterate over your collection and build a SQL string each time, and execute it
List<string> models = new List<string> { "WebBrowser", "Notebook", "Members"};
foreach (string mod in models)
{
using (var dbConn = new SQLiteConnection(app.DBPath))
{
SQLiteCommand command = new SQLiteCommand(dbConn);
command.CommandText = string.Format("DROP TABLE {0};", mod);
command.ExecuteNonQuery();
}
}
I'm not sure if this syntax is exactly correct for your case (I only ever use sqlite-net in Windows 8.1) but the general approach is sound
You could create your own Extensionmethod like this:
public static class SQLiteConnectionExtensions
{
public static int DropTable(this SQLiteConnection conn, string tableName)
{
var query = string.Format("drop table if exists \"{0}\"", tableName);
return conn.Execute(query);
}
}
And then use it like this:
var tables = new List<string> { "WebBrowser", "Notebook", "Members" };
using (var dbConn = new SQLiteConnection(app.DBPath))
{
dbConn.RunInTransaction(() =>
{
foreach (string table in tables)
{
dbConn.DropTable(table);
}
});
}
You could also use Reflections. Here are the two extension methods:
public static void DropTable(this SQLiteConnection Connection, Type TableType)
{
typeof(SQLiteConnection).GetMethod("DropTable", Array.Empty<Type>())?.MakeGenericMethod(TableType).Invoke(Connection, null);
}
public static void DropTable(this SQLiteConnection Connection, Type[] AllTableTypes)
{
MethodInfo? Method = typeof(SQLiteConnection).GetMethod("DropTable", Array.Empty<Type>());
if (Method != null)
{
foreach (Type? OneTableType in AllTableTypes)
{
Method.MakeGenericMethod(OneTableType).Invoke(Connection, null);
}
}
}
You can call them on a SQLiteConnection object:
TheSqlLiteConnection.DropTable(typeof(SomeClass));
TheSqlLiteConnection.DropTable(new Type[] { typeof(SomeClass), typeof(SomeOtherClass) });
In my C# WCF service I have a SqlDataReader that holds rows of data that I would like to return to the client.
How to return everything in the SqlDataReader?
Right now I have
if (sqlReader != null)
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
return sqlReader[0].ToString();
}
sqlConn.Close();
}
else
{
return null;
}
}
That only returns the first result. The return type of the class is string at the moment.
I was thinking of something like array in array, but I am not sure how?
EDIT:
Thanks for the many replies. I am interested in returning the entire SQL data that the service 'creates'. Not online the first column ([0]) - this was only for testing.
But I am not sure on how to get everything from the service back to the client.
How to return it?
For eg. in Powershell I would create a collection and add objects to that collection, if I had to pass it between clients.
I am looking for something similar in C# and WCF.
Many thanks so far :)
EDIT #2:
Got it! :)
Created a new class (e.g.):
public class ObjectNotification
{
public string AlertDescription;
public string Servername;
}
In my svc.cs file in top:
List<ObjectNotification> objlist = new List<ObjectNotification>();
And
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
ObjectNotification obj = new ObjectNotification();
obj.AlertDescription = sqlReader["AlertDescription"].ToString();
obj.Servername = sqlReader["ComputerName"].ToString();
objlist.Add(obj);
}
}
return objlist;
That gave me exactly what I wanted :)
Best regards
You need to define DataContract, If you pass list of strings or array of strings your service consumers need to know which index is for which column etc.. that approach will be hard when you adding or deleting column to the service in future. What you can do is create DataContract which having all the properties you need to send and create the operation contract accordingly. Now service consumers can update the service reference in future in case of changing field they will get compiler error. that is easy to identify.
public List<MyDataContract> GetData()
{
List<MyDataContract> list = new List<MyDataContract>();
//your code
if (sqlReader != null)
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
list.Add(new MyDataContract() {
Id = (int)sqlReader["Id"].ToString(),
Name= sqlReader = sqlReader["Name"].ToString() });
}
sqlConn.Close();
}
}
//finally return list of data
return list;
}
Sample Data Contract
[DataContract]
public class MyDataContract
{
[DataMember]
public int Id{ get; set; }
[DataMember]
public string Name{ get; set; }
}
And Operation contract
[OperationContract]
List<MyDataContract> GetData();
in my opinion we need more generic reusable code...
If you have only the .net Service consumers you can return DaTaSet or DataTable from the service method. You need to have SqlDataAdapter instead of sqlReader and Fill the DataTable Or Dataset and Return it. You can parace any number of columns no change in Service method definition. You can even send return type as string by using DataSet.GetXml()
Converting DataTable To Json
string json = JsonConvert.SerializeObject(table, Formatting.Indented);
// for instance
List<string> list = new List<string>();
if (sqlReader != null)
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
//return sqlReader[0].ToString();
list.Add(sqlReader[0].ToString());
}
sqlConn.Close();
}
else
{
return null;
}
}
return list; // ta-da
SqlReader is intended to work memory minimized and therefore will only query the result one by one. If you want to get all results you can use a while loop around your code to fetch rows as long as they are available. By calling return you will break the while loop and returning only first row. If you would call yield return an IEnumerable<string> would be returned by your method instead of string.
You can probably create an array or List and populate the List with your sqlReader.
List and Array can be serialized and transferred using WCF and are inter-operable too.
Inside the while loop
listObject.Add(sqlReader[0].ToString());
You need to actually read all the datareader rows by loading them into a datatable, the datareader is a lazyload object and can't be sent across the network since it's never fully populated at the begning:
DataTable dt=new DataTable();
dt.Load(dr);
Then, since you are using wcf, you possibly need to load that datatable into an object matching your contract interface. Take a look the snipet below that converts an arbitrary datatable into a well behaved object matching properties by using reflection.
Snippet usage
List<myType> r = (List<myType>) dt.ToList<myType>();
Snippet
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;
namespace xxxx.Sql.Extensions
{
public static class DataTableExtensions
{
/// <summary>
/// Gets a list of objects based on a generic datatable
/// </summary>
/// <typeparam name="T">List of objects</typeparam>
/// <param name="table">Existing datatable</param>
/// <returns></returns>
public static IList<T> ToList<T>(this DataTable table) where T : new()
{
IList<PropertyInfo> properties = typeof(T).GetProperties().ToList();
IList<T> result = new List<T>();
foreach (var row in table.Rows)
{
var item = CreateItemFromRow<T>((DataRow)row, properties);
result.Add(item);
}
return result;
}
private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
{
T item = new T();
foreach (var property in properties)
{
if (row.Table.Columns.Contains(property.Name))
{
var prop = row[property.Name] == System.DBNull.Value ? null : row[property.Name];
property.SetValue(item, prop, null);
}
}
return item;
}
/// <summary>
/// Creat a generic string list on the first field of a dataTable
/// </summary>
/// <param name="table"></param>
/// <returns></returns>
public static List<string> ToStringList(this DataTable table)
{
List<string> result = new List<string>();
foreach (DataRow dr in table.Rows)
result.Add(dr[0].ToString());
return result;
}
}
}
Ancient thread, but I'll add my two:
string sqltext = #"select a.columnown, a.columntwo, a.columnthreee from blahblah as a";
List<List<string>> toReturn = new List<List<string>>();
using (SqlConnection con = new SqlConnection("YourConnectionString"))
{
con.Open();
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = sqlTest;
using (SqlDataReader sqlReader = cmd.ExecuteReader())
{
if (sqlReader != null)
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
List<string> innerList = new List<string>();
for (int i = 0; i < sqlReader.FieldCount; i++)
{
innerList.Add(sqlReader[i].ToString());
}
toReturn.Add(innerList);
}
con.Close();
}
}
}
}
then you just simply return your List<List<string>>