I have this code:
var query = \"SELECT * FROM Cats\";
var conn = new SqlConnection(sqlConnectionString);
conn.Open();
var cmd = new SqlCommand(query);
var rea
It's possible, although not particularly neat. We'll need to create a new method that will allow us to create an empty sequence that allows for type inference off of a dummy value for starters:
public static IEnumerable<T> Empty<T>(T dummyValue)
{
return Enumerable.Empty<T>();
}
This lets us create a list of an anonymous type:
var list = Empty(new
{
CatName = "",
CatDOB = DateTime.Today,
CatStatus = 0
}).ToList();
(The item here isn't used.)
Now we can add our anonymous types to this list:
var cmd = new SqlCommand(query);
var reader = cmd.ExecuteReader();
while (reader.Read())
{
list.Add(new
{
CatName = reader.GetString(0),
CatDOB = reader.GetDateTime(1),
CatStatus = reader.GetInt32(2),
});
}
Of course, using a named type would likely be easier, so I would suggest using one unless there is a real compelling reason not to do so. That is especially true if you plan to use the list outside of the scope it's created in.
You can create helper generic method and let compiler infer type parameter:
private IEnumerable<T> Select<T>(DbDataReader reader, Func<DbDataReader, T> selector)
{
while(reader.Read())
{
yield return selector(reader);
}
}
usage:
var items = SelectFromReader(reader, r => new { CatName = r.GetString(0), CarDOB = r.GetDateTime(1), CatStatus = r.GetInt32(2) });
You can even make the method an extension method on DbDataReader
:
public static IEnumerable<T> Select<T>(this DbDataReader reader, Func<DbDataReader, T> selector)
{
while (reader.Read())
{
yield return selector(reader);
}
}
and use it like that:
var items = reader.Select(r => new { CatName = r.GetString(0), CarDOB = r.GetDateTime(1), CatStatus = r.GetInt32(2) });
Technically, it may not answer your question, but simply don't use a reader. Instead use a SqlDataAdapter
to Fill a DataSet, if you can. Take the 0th Table of that DataSet, and select a new anonymous object from the Rows collection.
using System.Data; // and project must reference System.Data.DataSetExtensions
var ds = new DataSet();
using (var conn = DbContext.Database.GetDbConnection())
using (var cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
cmd.CommandText = sqlText;
conn.Open();
(new SqlDataAdapter(cmd)).Fill(ds);
}
var rows = ds.Tables[0].AsEnumerable(); // AsEnumerable() is the extension
var anons = rows
.Select(r => new { Val = r["Val"] })
.ToList();
Here is an example of doing it with dynamic (which I think is easier to work with) but some may feel does not adhere to the letter of your question.
Call it like this:
var result = SelectIntoList("SELECT * FROM Cats",sqlconnectionString);
You could (like I did) put it into a static class in a separate file for easier maintanence.
public static IEnumerable<dynamic> SelectIntoList(string SQLselect, string connectionString, CommandType cType = CommandType.Text)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandType = cType;
cmd.CommandText = SQLselect;
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read()) // read the first one to get the columns collection
{
var cols = reader.GetSchemaTable()
.Rows
.OfType<DataRow>()
.Select(r => r["ColumnName"]);
do
{
dynamic t = new System.Dynamic.ExpandoObject();
foreach (string col in cols)
{
((IDictionary<System.String, System.Object>)t)[col] = reader[col];
}
yield return t;
} while (reader.Read());
}
}
conn.Close();
}
}
}