I wanna convert an object Array called "list" into a string Array called "test".
Attached the code.
The Problem is, the function is returning "System.Collections.Generic.Dic..." and not the strings in SQL database.
Thanks..
Code:
public string[] ListMethod(string command)
{
MySqlCommand comm = new MySqlCommand(command, conn);
MySqlDataReader commreader;
commreader = comm.ExecuteReader();
var list = new List<IDictionary<string, object>>();
while (commreader.Read())
{
var record = new Dictionary<string, object>();
for (int i = 0; i < commreader.FieldCount; i++)
{
var key = commreader.GetName(i);
var value = commreader[i];
record.Add(key, value);
}
list.Add(record);
}
string[] test = ((IEnumerable)list).Cast<object>().Select(x => x.ToString()).ToArray();
return test;
}
Lets look at your LINQ Query:
string[] test = ((IEnumerable)list).Cast<object>().Select(x => x.ToString()).ToArray();
What you are saying to the compiler here is:
Cast all objects in the list of dictionaries to object, and then execute to ToString() method of each object (which by default always prints the name of the class) and set it to an array (The cast do IEnumerable is redundant since List implements that interface anyway.
What you actually need to do is:
var test = list.Select(x => x.Values.ToString()).ToArray();
assuming all your values in the IDictionary are actually strings, this will fetch them for you.
Related
I am using Visual Studio 2012 and C#. I have a problem: I want to collect all results of a SQL query into dictionary.
This is my code:
Dictionary<int,List<string>> dic = new Dictionary<int, List<string>>();
string query = "select request_number, service_category ,service_type from enugro.enugro_service_requests_info;";
MySqlConnection connec = new MySqlConnection(strcon);
connec.Open();
MySqlCommand cmd = new MySqlCommand(query,connec);
MySqlDataReader reader = cmd.ExecuteReader();
while(reader.Read())
{
dic.Add((int)reader["request_number"], { reader["service_category"], reader["service_type"] });
}
// display result
foreach(var disp in dic)
{
MessageBox.Show(disp.Key.ToString()+"= "+disp.Value.ToString());
}
As you can see my SQL query returns 3 columns to be retrieved and to store into dictionary. Could you help me?
Since the type of the dictionary values is List<string>, then you need to create a new list for each row and add it to the dictionary like this:
dic
.Add(
(int)reader["request_number"],
new List<string>
{
reader["service_category"].ToString(),
reader["service_type"].ToString()
});
Consider creating a class to hold the information that you want from each row and use it as the type for the dictionary values. Such class would look something like this:
public class MyValue
{
public string ServiceCategory {get;set;}
public string ServiceType {get;set;}
}
Then you can have your dictionary be of type Dictionary<int, MyValue> which will allow you to do this:
dic
.Add(
(int)reader["request_number"],
new MyValue
{
ServiceCategory = reader["service_category"].ToString(),
ServiceType = reader["service_type"].ToString()
});
Why would you do that? You can create DTO (data transfer object) with properties according to column names in database, and bind query result to it. Then you can return list of DTO objects. It would be better solution, then complicating with dictionary.
I am executing a stored procedure from C# code
private void DataToGrid()
{
DataTable dt = new DataTable();
string[,] aryPara = new string[,]
{{ "#pClassId", "10" } ,
{ "#pMediumId", "11" } ,
{ "#pStreamId", "12" } ,
{ "#pSessionId","13" } ,
{ "#pSectionId", "15" } ,
{ "#pShiftId", "16" } ,
{ "#pDateId", "17" } };
dt = CallStoredProcedureUsingAdapterFillDataTabel("ssspAtdDailyattendance", aryPara);
DatagridView1.DataSource = dt;
}
public DataTable CallStoredProcedureUsingAdapterFillDataTabel(string StoredProcedureName, [Optional] string[,] aryParameters)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = "Data Source=AIS-OCTACORE\SQLserver2008r2;Initial Catalog= SchoolSoulDataTest; integrated security=SSPI";
con.open();
SqlCommand lSQLCmd = new SqlCommand();
SqlDataAdapter adp = new SqlDataAdapter();
DataTable dt = new DataTable();
lSQLCmd.CommandType = CommandType.StoredProcedure;
lSQLCmd.CommandText = StoredProcedureName;
lSQLCmd.CommandTimeout = 300;
try
{
for (int i = 0; i < aryParameters.GetLength(0); i++)
{
lSQLCmd.Parameters.Add(new SqlParameter(aryParameters[i, 0], aryParameters[i, 1]));
}
}
catch (Exception ex)
{
}
lSQLCmd.Connection = con;
adp.SelectCommand = lSQLCmd;
adp.Fill(dt);
clsConnectionClose();
return dt;
}
Where ssspAtdDailyattendance is a Dynamic Stored Procedure in which data returned by the stored procedure has variable number of columns.
Now I want to convert DataTable dt to a List<T> but as dt return variable number of columns thus type of T is not Fixed
So my question is how could I convert dt to List?
I would recommend you use Dapper for it instead of writing and maintaining the boilerplate code yourself. Dapper supports dynamic objects.
Execute a query and map it to a list of dynamic objects
public static IEnumerable<dynamic> Query (this IDbConnection cnn, string sql,
object param = null, SqlTransaction transaction = null, bool buffered = true)
This method will execute SQL and return a dynamic list.
Example usage:
var rows = connection.Query("select 1 A, 2 B union all select 3, 4");
((int)rows[0].A).IsEqualTo(1);
((int)rows[0].B).IsEqualTo(2);
((int)rows[1].A).IsEqualTo(3);
((int)rows[1].B).IsEqualTo(4);
Website: http://code.google.com/p/dapper-dot-net/
NuGet: http://www.nuget.org/packages/Dapper/
If I understood right your question, T can be more than one type.
So for example, first row could be a Person and second row a Dog? Or did you mean different types as string, int, date and so on (value types).
Regardless you will need to create your "T" entities to represent the data from the datatable and map it.
What you are looking for is potentially a mapper such as ValueInjector or Automapper.
Or even map manually:
This answer here shows how to map a DataTable to a class using ValueInjector. It can be give you a headstart.
I hope this helps.
#Douglas Jimenez has a relevant question. If only the type varies, this can be easily solved with an interface for common fields (or object if no field is common) and different types implementing the other fields. When you build your list, you then use a factory to decide which type to build for the row (or the wholde DataTable), and you build the object using the row.
However, if the type is not known at compile time, there are many solutions:
Use the DLR with the dynamic keyword.
The ExpandoObject may do what you need.
Use a hashmap (like a Dictionary<string, object>)
Emit the type with the Emit framework.
This solution is actually complicated and will lead you to advanced parts of the CLR. However, this works really well.
If you choose this path, this tutorial will help you greatly.
This may very well be overkill for your needs.
There may be other solutions as well. Good luck with the solution you choose.
According to answer posted by sll you can use something like,
IList<Class1> items = dt.AsEnumerable().Select(row =>
new Class1
{
id = row.Field<string>("id"),
name = row.Field<string>("name")
}).ToList();
But since you have requirement that it may contain different columns then you can have a common class with all the properties and place a check before getting column something like,
public class Class1
{
private int id;
public string name;
public Class1(DataRow row)
{
id = (int)GetColumnValue(row, "id");
name = (string)GetColumnValue(row, "name");
}
public object GetColumnValue(DataRow row, string column)
{
return row.Table.Columns.Contains(column) ? row[column] : null;
}
}
And then you may invoke function as,
IList<Class1> items = dt.AsEnumerable().Select(row => new Class1(row)).ToList();
I faced this issue and soled use this code from
http://musthaan.com/2016/01/18/datatable-to-dynamic-list/
public static class HelperExtensions
{
public static List<dynamic> ToDynamic(this DataTable dt)
{
var dynamicDt = new List<dynamic>();
foreach (DataRow row in dt.Rows)
{
dynamic dyn = new ExpandoObject();
dynamicDt.Add(dyn);
foreach (DataColumn column in dt.Columns)
{
var dic = (IDictionary<string, object>)dyn;
dic[column.ColumnName] = row[column];
}
}
return dynamicDt;
}
}
I have a class named DataAPIKey. I have a second class which inherits from that one.
In my code I have a List, and I would like to use that to make a list of the new class. Is there any way to do this without using a for each loop?
Using the example below I made the following code which seems to be doing what I want.
List<DataAPIKey> apiList = db.GetPendingAction("Character");
List<DataCharacter> charList = apiList.Select(k => {
DataCharacter dc = new DataCharacter(k.apiKeyId, k.keyId, k.verificationCode);
return dc;
}).ToList()
Use the LINQ Select method.
var newList = oldList.Select(oldItem => new InheritedItem(oldItem)).ToList();
In plain English this translates to "Take each item from oldList, feed each as a function parameter to a function which will take that item and perform some logic to return a different type of item, then take all the returned items and populate them into a new List."
Or if you don't have a constructor to initialize the inherited class then you can provide any code block:
var newList = oldList.Select(oldItem =>
{
var newItem = new InheritedItem();
newItem.Property = oldItem.Property;
return newItem;
}).ToList();
Or an initializer:
var newList = oldList.Select(oldItem => new InheritedItem()
{
Property = oldItem.Property,
Property2 = oldItem.Property2
}).ToList();
I think I understand returning records of an anonymous type from But in this I want to create NEW CatalogEntries, and set them from the values selected. (context is a Devart LinqConnect database context, which lets me grab a view).
My solution works, but it seems clumsy. I want to do this in one from statement.
var query = from it in context.Viewbostons
select it;
foreach (GPLContext.Viewboston item in query)
{
CatalogEntry card = new CatalogEntry();
card.idx = item.Idx;
card.product = item.Product;
card.size = (long)item.SizeBytes;
card.date = item.Date.ToString();
card.type = item.Type;
card.classification = item.Classification;
card.distributor = item.Distributor;
card.egplDate = item.EgplDate.ToString();
card.classificationVal = (int)item.ClassificationInt;
card.handling = item.Handling;
card.creator = item.Creator;
card.datum = item.Datum;
card.elevation = (int)item.ElevationFt;
card.description = item.Description;
card.dirLocation = item.DoLocation;
card.bbox = item.Bbox;
card.uniqID = item.UniqId;
values.Add(card);
}
CatalogResults response = new CatalogResults();
I just tried this:
var query2 = from item in context.Viewbostons
select new CatalogResults
{ item.Idx,
item.Product,
(long)item.SizeBytes,
item.Date.ToString(),
item.Type,
item.Classification,
item.Distributor,
item.EgplDate.ToString(),
(int)item.ClassificationInt,
item.Handling,
item.Creator,
item.Datum,
(int)item.ElevationFt,
item.Description,
item.DoLocation,
item.Bbox,
item.UniqId
};
But I get the following error:
Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a
collection initializer because it does not implement
'System.Collections.IEnumerable' C:\Users\ysg4206\Documents\Visual
Studio
2010\Projects\CatalogService\CatalogService\CatalogService.svc.cs 91 25 CatalogService
I should tell you what the definition of the CatalogResults is that I want to return:
[DataContract]
public class CatalogResults
{
CatalogEntry[] _results;
[DataMember]
public CatalogEntry[] results
{
get { return _results; }
set { _results = value; }
}
}
My mind is dull today, apologies to all. You are being helpful. The end result is going to be serialized by WCF to a JSON structure, I need the array wrapped in a object with some information about size, etc.
Since .NET 3.0 you can use object initializer like shown below:
var catalogResults = new CatalogResults
{
results = context.Viewbostons
.Select(it => new CatalogEntry
{
idx = it.Idx,
product = it.Product,
...
})
.ToArray()
};
So if this is only one place where you are using CatalogEntry property setters - make all properties read-only so CatalogEntry will be immutable.
MSDN, Object initializer:
Object initializers let you assign values to any accessible fields or properties of an
object at creation time without having to explicitly invoke a constructor.
The trick here is to create a IQueryable, and then take the FirstOrDefault() value as your response (if you want a single response) or ToArray() (if you want an array). The error you are getting (Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a collection initializer because it does not implement 'System.Collections.IEnumerable') is because you're trying to create an IEnumerable within the CatalogEntry object (by referencing the item variable).
var response = (from item in context.Viewbostons
select new CatalogEntry()
{
idx = item.Idx,
product = item.Product,
size = (long)item.SizeBytes,
...
}).ToArray();
You don't have to create anonymous types in a Linq select. You can specify your real type.
var query = context.Viewbostons.Select( it =>
new CatalogEntry
{
idx = it.idx,
... etc
});
This should work:
var query = from it in context.Viewbostons
select new CatalogEntry()
{
// ...
};
At the moment, I'm creating a new method for each mysql query with parameters I want to get performed.
An example:
public DataTable RetreiveAllLinks(int id, int categoryid)
{
const string request =
#"
SELECT *
FROM links
WHERE id=?id,categoryid=?categoryid
ORDER by id DESC
";
using (var query = new MySqlCommand(request))
{
query.Parameters.AddWithValue("?id", id);
query.Parameters.AddWithValue("?categoryid", categoryid);
return _connection.RetreiveData(query);
}
}
This is really getting on my nerves, because I always end up with 10-30 queries, when two queries can do it for me, a simple method for retrieving non-parameter query, and a method for parameters. For example
public DataTable NonParameterCommand(string r)
{
var request = r;
using (var query = new MySqlCommand(request))
{
return _connection.RetreiveData(query);
}
}
What I want to do, is some regex'ing, where i would say e.g.
var pPattern = "^[\\?][\\w]";
and then a method with request and a list as parameters, and the list should be in the same order as the request parameters. So if the request is
`"SELECT * FROM test WHERE id=?id,categoryid=?categoryid"`
then my list would look like
var _dictionary = new Dictionary<string, string>();
_dictionary.Add(_parameter, _value);
and my method
ParameterCommand(string r, Dictionary dic)
but how exactly?
If you are using a dictionary, then the key would already be the parameter name. Why parse the query to extract them?
You could do:
public DataTable CommandWithParams(string sql, Dictionary<string, object> parameters)
{
using (var query = new MySqlCommand(sql))
{
foreach (var param in parameters)
{
query.Parameters.AddWithValue(param.Key, param.Value);
}
return _connection.RetreiveData(query);
}
}
Calling it:
var parameters = new Dictionary<string, object>()
{
{ "?param1", value1 },
{ "?param2", value2 }
};
var result = CommandWithParams(query, parameters);
But maybe you'd like to use a List instead of a Dictionary?
(I wouldn't recommend it, passing the parameters values based on their position would be error-prone)