i have code like this
public class People
{
public string name { get; set; }
}
public class Animal
{
public string age { get; set; }
}
class Test
{
public void DataPeopleList()
{
string sql = "SELECT * FROM People";
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader rdr = cmd.ExecuteReader();
List<People> list = new List<People>();
while (rdr.Read()) {
People p = new People();
p.name = rdr["name"].ToString();
list.Add(p);
}
rdr.Close();
}
public void DataAnimalList()
{
string sql = "SELECT * FROM Animal";
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader rdr = cmd.ExecuteReader();
List<People> list = new List<People>();
while (rdr.Read())
{
People p = new People();
p.name = rdr["age"].ToString();
list.Add(p);
}
rdr.Close();
}
}
i think is not good for me. can i write give class as parameter so when i want load data i just give query and class as parameter..example the code which i want like :
public void LoadData(string query, Type ClassName)
{
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader rdr = cmd.ExecuteReader();
List<ClassName> list = new List<ClassName>();
while (rdr.Read())
{
ClassName p = new ClassName();
//p.name = rdr["age"].ToString(); i dont have idea in this part
list.Add(p);
}
rdr.Close();
}
so I`m enough to call method like
public void DataAnimalList()
{
string sql = "SELECT * FROM Animal";
LoadData(sql,class Animal);
}
Can you give me an answer or hint..
Thanks in Advance
There are ways that you can accomplish something like this with reflection, but I strongly recommend you switch to using an ORM framework like ADO.NET Entity Framework, Linq to SQL or NHibernate instead.
You might want to read:
Why should you use an ORM?
What is so great about ORM?
Are there good reasons not to use an ORM?
You could use generics. I think it can be done like this:
public List<T> LoadData<T> (String query) {
SqlCommand cmd = new SqlCommand(query, conn);
SqlDataReader rdr = cmd.ExecuteReader();
List<T> list = new List<T>();
while (rdr.Read())
{
T p = new T(rdr[0]);
list.Add(p);
}
rdr.Close();
return list;
}
Where you have to create a constructor for each class that accepts the data as a parameter. You could event modify the code a bit and use a DataAdapter to fill a DataTable, and then you could create a constructor that accepts DataRow as argument so you can instantiate classes with different number of elements.
But if you get a any more complicated with this, I would suggest using some ORM framework like Linq to SQL, Entity Framework, Nhibernate...
I feel, what you are thinking may not be that elegant solution. Because
1) You can use reflection but which can result in poor performance. So, better not to go for it until, it is badly needed.
2) Also, tomorrow, if the columns to deal with in the result set changes then anyway you need to go and tweak the code otherwise your code may fail.
So, better could be you can go for some ORM Framework as suggested by Ani.
If I got your question right then what you're looking for is Polymorphism. Try this:
void DataList(IType var)
{
if(IType is Animal)
{
//Do something for Animal
}
if(IType is People)
{
//Do something for People
}
}
Both Animal and People class would implement IType interface, which can be an empty interface.
A better design would be to change your code structure and move the DataList method to IType and implement this accordingly in your People and Animal class. More than one way to skin the cat, you see :)
You could have something like this where a delegate is used to populate the object from the data reader:
public List<T> LoadData<T>(string sql, Action<IDataReader, T> fill) where T : new()
{
using( SqlCommand cmd = new SqlCommand(sql, conn) )
using( SqlDataReader reader = cmd.ExecuteReader() )
{
List<T> items = new List<T>();
while( reader.Read() )
{
T item = new T();
fill(reader, item);
items.Add(item);
}
return items;
}
}
Then use it like this:
public List<Person> LoadPeople()
{
return LoadData<Person>("SELECT * FROM Person", (r, p) =>
{
p.Name = r["Name"].ToString();
});
}
But really you should be using an ORM.
Related
Just as title says i have this error already defines a member called with the same parameter types c#
I have looked into multiple same questions but they all tells why does it happens and how to deal with it (change name of method to some other) BUT i do not want to change method name to something other because it is same method but with different parameter so i just want to bypass it.
Here are 2 methods i have:
public static List<int> Lista(int vrDok)
{
List<int> list = new List<int>();
using (FbConnection con = new FbConnection(M.Baza.connectionKomercijalno2018))
{
con.Open();
using (FbCommand cmd = new FbCommand("SELECT BRDOK FROM DOKUMENT WHERE VRDOK = #VrDok ORDER BY DATUM ASC", con))
{
cmd.Parameters.AddWithValue("#VrDok", vrDok);
FbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
list.Add(Convert.ToInt32(dr[0]));
}
}
}
return list;
}
public static List<int> Lista(int magacinId)
{
List<int> list = new List<int>();
using (FbConnection con = new FbConnection(M.Baza.connectionKomercijalno2018))
{
con.Open();
using (FbCommand cmd = new FbCommand("SELECT BRDOK FROM DOKUMENT WHERE MAGACINID = #MID ORDER BY DATUM ASC", con))
{
cmd.Parameters.AddWithValue("#MID", magacinId);
FbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
list.Add(Convert.ToInt32(dr[0]));
}
}
}
return list;
}
So as you can see they are totally identical but with different parameter and it drops me error.
How can i bypass it?
Any of Davide suggestions will work. Another options is to do just have one method that takes the ID and the Parameter Name like so:
public static List<int> Lista(int id,string paramName)
{
List<int> list = new List<int>();
using (FbConnection con = new FbConnection(M.Baza.connectionKomercijalno2018))
{
con.Open();
using (FbCommand cmd = new FbCommand("SELECT BRDOK FROM DOKUMENT WHERE MAGACINID = #MID ORDER BY DATUM ASC", con))
{
cmd.Parameters.AddWithValue(paramName, id);
FbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
list.Add(Convert.ToInt32(dr[0]));
}
}
}
return list;
}
Since everything in both methods are the same and just which parameter name changes.
It gives error because the method signature is the same
- Lista(int)
- Lista(int)
The parameters name doesn't matter.
You can resolve in different ways:
- Change the name of one method (ex. ListaByVrDok, ListaByMagician) <= recommended
- Move one method in another class
- Add a parameter to one method
- Change int in double in one method
The name I chose for my migration has already been used.
add-migration "added-list-to-model-a"
All I needed to do was to change the name of my migration.
add-migration "re-added-list-to-model-a"
I have a table that has 14 rows in it that i want to return as well as declare each cell as a variable. Here is what I have tried:
using (SqlConnection conn1 = new SqlConnection(ConfigurationManager.ConnectionStrings["2012SSMS"].ConnectionString))
{
SqlCommand cmd1 = new SqlCommand(#"SELECT [Question], [Answer]
from [MyTable]", conn1);
conn1.Open();
using (SqlDataReader reader1 = cmd1.ExecuteReader())
{
while (reader1.HasRows)
{
reader1.GetName(0);
reader1.GetName(1);
while(reader1.Read())
{
string Question(1) = reader1.GetString(0); //errors here
string Answer(1) = reader1.GetString(1); //and here
}
reader1.NextResult();
}
}
}
my hope is to return the declared variables as Question1 - Question14 and Answer1 - Answer14. How do I go about doing this?
Well, if you want to use 14 different names, you could define 14 string variables for the questions and 14 string variable for the answers. But this is frankly ridicolous when you have at your disposal Lists and other collection classes.
For example
Define a class for your question/answer
public class QuestionAnswer
{
public string Question {get;set;}
public string Answer {get;set;}
}
then modify your code to create a List<QuestionAnswer>
List<QuestionAnswer> listOfQuestionsAndAnswers = new List<QuestionAnswer>();
using (SqlConnection conn1 = new SqlConnection(ConfigurationManager.ConnectionStrings["2012SSMS"].ConnectionString))
{
SqlCommand cmd1 = new SqlCommand(#"SELECT [Question], [Answer]
from [MyTable]", conn1);
conn1.Open();
using (SqlDataReader reader1 = cmd1.ExecuteReader())
{
while(reader1.Read())
{
QuestionAnswer qa = new QuestionAnswer();
qa.Question = reader1.GetString(0);
qa.Answer = reader1.GetString(1);
listOfQuestionsAndAnswers.Add(qa);
}
}
}
Now you could use any question in the List using the following syntax
string aQuestion = listOfQuestionsAndAnswers[0].Question;
string anAnswer = listOfQuestionsAndAnswers[0].Answer;
And, finally, I really suggest you to spend a bit of your time to learn how to use Dapper as shown in the answer of Mr. Gravell.
I have have to give a dapper answer here... to show how much unnecessary code you are writing
public class QuestionAnswer {
public string Question {get;set;}
public string Answer {get;set;}
}
...
var pairs = conn1.Query<QuestionAnswer>("select Question, Answer from MyTable")
.ToList();
Now: pairs[0].Question is the first question, and pairs[3].Answer is the 4th answer.
What you want to do here is return a collection of objects, where each of those objects has a Question and Answer property.
In each iteration of the loop you can create a new instance of the custom type that you have defined to hold onto these two values, and then you can add it to your data structure of choice.
You want to use a dynamic to do some thing of this nature. I have not tested the code, but conceptually this should work.
public class DynamicDataRecord : DynamicObject
{
private IDataRecord _dataRecordFromReader;
public DynamicDataRecord(IDataRecord dataRecordFromReader)
{
_dataRecordFromReader = dataRecordFromReader;
}
public override bool TryGetMember(GetMemberBinder binder, out dynamic result)
{
result = _dataRecordFromReader[binder.Name];
return result != null;
}
}
And then in the place you iterate through the reader you can do something like the below
List<DynamicDataRecord> records = new List<DynamicDataRecord>();
using (SqlDataReader reader1 = cmd1.ExecuteReader())
{
foreach(var record in reader)
{
records.Add( new DynamicDataRecord(record));
}
}
And then you should be able to do something like this.
records[0].Question
record[0].Answer
I have this code:
var query = "SELECT * FROM Cats";
var conn = new SqlConnection(sqlConnectionString);
conn.Open();
var cmd = new SqlCommand(query);
var reader = cmd.ExecuteReader();
while (reader.Read())
{
var CatName = reader.GetString(0);
var CatDOB = reader.GetDateTime(1);
var CatStatus = reader.GetInt32(2);
}
I'd like to pull the rows out into an anonymous type collection, which I'd normally do using LINQ to iterate, but I an not sure if it's possible due to the way you have to call .Read() each time to get the next row.
Is there a way to do this?
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) });
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();
}
}
}
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.
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();
I am using generic list to store the data that comes by querying the databse.I uses List of classes actually for multiple rows.
But my problem is my classes have almost more than 20 properties and most of the time i uses only its 2 or 3 properties.
So I want to know that what is the best way to keep the data coming from database.
Below is my code
List<ImageGalleryCollection> tempList = new List<ImageGalleryCollection1>();
SqlConnection connection = Dal.GetConnection();
SqlParameter[] paramList = new SqlParameter[1];
paramList[0] = new SqlParameter("#cityId", cityId);
SqlDataReader data = Dal.ExecuteReaderSP(SPNames.GetRegCity, paramList, connection);
while(data.Read())
{
ImageGalleryCollection igc = new ImageGalleryCollection1();
igc.cityPhotoGalleryId = Convert.ToInt32(data["cityPhotoGalleryId"]);
igc.ImagePath = data["imagePath"].ToString();
tempList.Add(igc);
}
data.Close();
connection.Close();
return tempList;
In ImageGalleryCollection I have more that 20 properties and above i only uses two properties.I think it is very inefficient
Can you how your base class implementation? You can create another class with the most using attributes and use an object of that class inside your class.
IEnumerable<ImageGalleryCollection> GetImageGalleryCollection()
{
SqlConnection connection = Dal.GetConnection();
SqlParameter[] paramList = new SqlParameter[1];
paramList[0] = new SqlParameter("#cityId", cityId);
SqlDataReader data = Dal.ExecuteReaderSP(SPNames.GetRegCity, paramList,connection);
while(data.Read())
{
ImageGalleryCollection igc = new ImageGalleryCollection1();
igc.cityPhotoGalleryId = Convert.ToInt32(data["cityPhotoGalleryId"]);
igc.ImagePath = data["imagePath"].ToString();
yield return igc;
}
data.Close();
connection.Close();
}
I would like to suggest you to write a extension method for SqlDataReader and make use of the method in linq to fetch required columns from the returned rows of reader.
Extension method:
public static class DataReaderExtension
{
public static IEnumerable<Object[]> DataRecord(this System.Data.IDataReader source)
{
if (source == null)
throw new ArgumentNullException("source");
while (source.Read())
{
Object[] row = new Object[source.FieldCount];
source.GetValues(row);
yield return row;
}
}
}
using it in linq:
using (SqlConnection cn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("Select * from tblUser"))
{
cmd.CommandType = CommandType.Text;
cmd.Connection = cn;
cn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
var result = (from row in dr.DataRecord()
select new
{
UserId = row[0],
UserName = row[1]
}).ToList();
}
}
}
This result list has only the required properties you select and helps to reduce the consumption of memory for unwanted properties.
I have the following code:
SqlDataReader reader = getAddressQuery.sqlReader;
while (reader.Read())
{
foreach (Object ob in reader)
{
someText.InnerText = someText.InnerText + " " + ob.ToString();
}
}
The code in the foreach loop does not execute. However, I can do this:
SqlDataReader reader = getAddressQuery.sqlReader;
while (reader.Read())
{
someText.InnerText = reader[0].ToString();
}
Which works.
Obviously I could achieve the same result using a regular for loop rather than a foreach loop, but I think the foreach syntax is clearer, so I use it when possible.
What has gone wrong here? Are foreach loops in c# not as flexible as in more high level languages?
Something like the following. Note that IDataReader derives from IDataRecord which exposes the members used to process the current row:
IEnumerable<IDataRecord> GetFromReader(IDataReader reader)
{
while(reader.Read()) yield return reader;
}
foreach(IDataRecord record in GetFromReader(reader))
{
... process it ...
}
Or even something like the following, to get an enumeration or list of strongly-typed entity objects from a reader:
IEnumerable<T> GetFromReader<T>(IDataReader reader, Func<IDataRecord, T> processRecord)
{
while(reader.Read()) yield return processRecord(reader);
}
MyType GetMyTypeFromRecord(IDataRecord record)
{
MyType myType = new MyType();
myType.SomeProperty = record[0];
...
return myType;
}
IList<MyType> myResult = GetFromReader(reader, GetMyTypeFromRecord).ToList();
UPDATE in response to Caleb Bell's comment.
I agree Enumerate is a better name.
In fact in my personal "common" library, I've now replaced the above by an extension method on IDataReader:
public static IEnumerable<IDataRecord> Enumerate(this IDataReader reader)
{
while (reader.Read())
{
yield return reader;
}
}
And the caller can get strongly-typed objects using:
reader.Enumerate.Select(r => GetMyTypeFromRecord(r))
The foreach exposes an IDataRecord, which puts you in a very similar boat to the while loop:
using (SqlConnection conn = new SqlConnection(""))
using (SqlCommand comm = new SqlCommand("select * from somewhere", conn))
{
conn.Open();
using (var r = comm.ExecuteReader())
{
foreach (DbDataRecord s in r)
{
string val = s.GetString(0);
}
}
}
If you want to see something more useful, you'll need to have some of your own code that extracts the values from the record into something more custom, as the other answer has suggested.
Either way you are going to need custom code, whether you have it inline or not or use a while loop or not depends on how often it's going to be written I suppose, any more than once and you should probably stick it in a helper method somewhere.
And to answer the somewhat question: the problem is not the foreach, it is your attempted usage of what it returns for you, as your comparable use of the while loop is not actually comparable.
you may do also that...
string sql = "select * from Users";
using (SqlConnection conn = GetConnection()){
conn.Open();
using (SqlDataReader rdr = new SqlCommand(sql, conn).ExecuteReader()){
foreach (DbDataRecord c in rdr.Cast<DbDataRecord>()){
Console.Write("{0} {1} ({2}) - ", (string)c["Name"], (string)c["Surname"], (string)c["Mail"]);
Console.WriteLine((string)c["LoginID"]);
}
}
}