I have a method in my app that populates DataTable with the data using the following code:
DataTable dt = this.attachmentsDataSet.Tables["Attachments"];
foreach (Outlook.Attachment attachment in this.mailItem.Attachments)
{
DataRow dr = dt.NewRow();
dr["Index"] = attachment.Index;
dr["DisplayName"] = String.Format(
CultureInfo.InvariantCulture,
"{0} ({1})",
attachment.FileName,
FormatSize(attachment.Size));
dr["Name"] = attachment.FileName;
dr["Size"] = attachment.Size;
dt.Rows.Add(dr);
}
I was wondering if I could achieve the same functionality using LINQ in order to shorten this code a bit. Any ideas?
Yes, Easy
public void FillFromList(List<T> col)
{
Type elementType = typeof(T);
// Nested query of generic element list of property
// values (using a join to the DataTable columns)
var rows = from row in col
select new
{
Fields = from column in m_dataTable.Columns.Cast<DataColumn>()
join prop in elementType.GetProperties()
on column.Caption equals prop.Name
select prop.GetValue(row, null)
};
// Add each row to the DataTable
int recordCount = 0;
foreach ( var entry in rows )
{
m_dataTable.Rows.Add(entry.Fields.ToArray());
}
This assumes that the properties on T are the same as the DataTable columns.
Well this code isnt shorter or Linq but I did an externsion method that takes a IList and turns it into a DataTable for you.
public static DataTable ToDataTable<T>(this IList<T> theList)
{
DataTable theTable = CreateTable<T>();
Type theEntityType = typeof(T);
// Use reflection to get the properties of the generic type (T)
PropertyDescriptorCollection theProperties = TypeDescriptor.GetProperties(theEntityType);
// Loop through each generic item in the list
foreach (T theItem in theList)
{
DataRow theRow = theTable.NewRow();
// Loop through all the properties
foreach (PropertyDescriptor theProperty in theProperties)
{
// Retrieve the value and check to see if it is null
object thePropertyValue = theProperty.GetValue(theItem);
if (null == thePropertyValue)
{
// The value is null, so we need special treatment, because a DataTable does not like null, but is okay with DBNull.Value
theRow[theProperty.Name] = DBNull.Value;
}
else
{
// No problem, just slap the value in
theRow[theProperty.Name] = theProperty.GetValue(theItem);
}
}
theTable.Rows.Add(theRow);
}
return theTable;
}
You first identify whether you can query this.mailItem.Attachments and
if it is possible, you can convert query result to a datatable from extension method create by Steve Sloka...
Related
I have a datatable from a stored procedure. I want to add a column named "Assessment" which will be populated from a sql query. Finally I want to populate a store with this datatable. In visual studio I see that the datatable column that contains the "SiteId" is named 7. But I receive this error:
Load failed:Column '7' does not belong to table .
and the code:
DAL.DBDataContext dc = new DAL.DBDataContext();
try
{
SqlConnection sqlConnection1 = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString);
SqlCommand cmd = new SqlCommand();
SqlDataReader sqlreader;
cmd.CommandText = "StorProc";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#CTid", ctid));
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
sqlreader = cmd.ExecuteReader();
var dt = new DataTable();
dt.Load(sqlreader);
//Add assessment column
dt.Columns.Add("Assessment", typeof(System.String));
var data = new List<object>();
foreach (DataRow r in dt.Rows)
{
if (r[7] != null)
{
var res = (from d in dc.Doctors
join ct in dc.CTUsers on d.id equals ct.DoctorId
where ct.CTid == ctid && ct.SiteId == Int32.Parse(r["7"].ToString())
select d).FirstOrDefault();
r["Assessment"] = res.Assessment;
}
data.Add(r);
}
this.storeSites.DataSource = dt;
this.storeSites.DataBind();
sqlConnection1.Close();
}
catch (Exception a)
{
X.Msg.Alert("Warning", "Load failed:" + a.Message).Show();
}
Please try this:
foreach (DataRow r in dt.Rows)
{
foreach(DataColumn column in dt.Columns)
{
if (r[column] != null && r[column].ColumnName == "some column name")
{
var res = (from d in dc.Doctors
join ct in dc.CTUsers on d.id equals ct.DoctorId
where ct.CTid == ctid && ct.SiteId == Int32.Parse(r[column].ToString())
select d).FirstOrDefault();
r["Assessment"] = res.Assessment;
}
}
data.Add(r);
}
Int32.Parse(r["7"].ToString() is not correct. You are requesting a column named 7.
I think the above code is more clear.
Edit
You can also access the row-column value like this:
r.ItemArray[i].ToString()
Like so:
for (int i = 0; i < dt.Rows.Count; i++)
{
var r = dt.Rows[i];
var value = r.ItemArray[7].ToString();
if (!String.IsNullOrEmpty(value))
{
var res = (from d in dc.Doctors
join ct in dc.CTUsers on d.id equals ct.DoctorId
where ct.CTid == ctid && ct.SiteId == Int32.Parse(value)
select d).FirstOrDefault();
r["Assessment"] = res.Assessment;
}
data.Add(r);
}
The DataRow class has an overloaded indexer to access the columns.
public object this[int columnIndex] { get; set; }
... accesses the column by its int index (this is what we can see on your image). You use it by passing it an int:
object o = r[7]; // NOT r["7"] !
The other overload
public object this[string columnName] { get; set; }
... requires a column name passed as string:
object o = r["Assessment"];
If the column was really named "7", then you would have to access it like this:
object o = r["7"]; // But this is wrong in your case!
Note that the type of the argument passed to the index makes the difference. So r[7] and r["Assessment"] both work in your case. Using the name is preferred, as the index might change if the schema or the query changes. r["7"] does not work, as there is no column named like this.
See:
Member Overloading on MSDN.
Overloading, C# in Depth by Jon Skeet.
I have two columns in a datatable:
ID, Calls.
How do I find what the value of Calls is where ID = 5?
5 could be anynumber, its just for example. Each row has a unique ID.
Make a string criteria to search for, like this:
string searchExpression = "ID = 5"
Then use the .Select() method of the DataTable object, like this:
DataRow[] foundRows = YourDataTable.Select(searchExpression);
Now you can loop through the results, like this:
int numberOfCalls;
bool result;
foreach(DataRow dr in foundRows)
{
// Get value of Calls here
result = Int32.TryParse(dr["Calls"], out numberOfCalls);
// Optionally, you can check the result of the attempted try parse here
// and do something if you wish
if(result)
{
// Try parse to 32-bit integer worked
}
else
{
// Try parse to 32-bit integer failed
}
}
You can use LINQ to DataSet/DataTable
var rows = dt.AsEnumerable()
.Where(r=> r.Field<int>("ID") == 5);
Since each row has a unique ID, you should use Single/SingleOrDefault which would throw exception if you get multiple records back.
DataRow dr = dt.AsEnumerable()
.SingleOrDefault(r=> r.Field<int>("ID") == 5);
(Substitute int for the type of your ID field)
I could use the following code.
Thanks everyone.
int intID = 5;
DataTable Dt = MyFuctions.GetData();
Dt.PrimaryKey = new DataColumn[] { Dt.Columns["ID"] };
DataRow Drw = Dt.Rows.Find(intID);
if (Drw != null) Dt.Rows.Remove(Drw);
You can try with method select
DataRow[] rows = table.Select("ID = 7");
DataRow dataRow = dataTable.AsEnumerable().FirstOrDefault(r => Convert.ToInt32(r["ID"]) == 5);
if (dataRow != null)
{
// code
}
If it is a typed DataSet:
MyDatasetType.MyDataTableRow dataRow = dataSet.MyDataTable.FirstOrDefault(r => r.ID == 5);
if (dataRow != null)
{
// code
}
try this code
DataRow foundRow = FinalDt.Rows.Find(Value);
but set at lease one primary key
Hello just create a simple function that looks as shown below.. That returns all rows where the call parameter entered is valid or true.
public DataTable SearchRecords(string Col1, DataTable RecordDT_, int KeyWORD)
{
TempTable = RecordDT_;
DataView DV = new DataView(TempTable);
DV.RowFilter = string.Format(string.Format("Convert({0},'System.String')",Col1) + " LIKE '{0}'", KeyWORD);
return DV.ToTable();
}
and simply call it as shown below;
DataTable RowsFound=SearchRecords("IdColumn", OriginalTable,5);
where 5 is the ID.
Thanks..
Try avoiding unnecessary loops and go for this if needed.
string SearchByColumn = "ColumnName=" + value;
DataRow[] hasRows = currentDataTable.Select(SearchByColumn);
if (hasRows.Length == 0)
{
//your logic goes here
}
else
{
//your logic goes here
}
If you want to search by specific ID then there should be a primary key in a table.
I have two columns in a datatable:
ID, Calls.
How do I find what the value of Calls is where ID = 5?
5 could be anynumber, its just for example. Each row has a unique ID.
Make a string criteria to search for, like this:
string searchExpression = "ID = 5"
Then use the .Select() method of the DataTable object, like this:
DataRow[] foundRows = YourDataTable.Select(searchExpression);
Now you can loop through the results, like this:
int numberOfCalls;
bool result;
foreach(DataRow dr in foundRows)
{
// Get value of Calls here
result = Int32.TryParse(dr["Calls"], out numberOfCalls);
// Optionally, you can check the result of the attempted try parse here
// and do something if you wish
if(result)
{
// Try parse to 32-bit integer worked
}
else
{
// Try parse to 32-bit integer failed
}
}
You can use LINQ to DataSet/DataTable
var rows = dt.AsEnumerable()
.Where(r=> r.Field<int>("ID") == 5);
Since each row has a unique ID, you should use Single/SingleOrDefault which would throw exception if you get multiple records back.
DataRow dr = dt.AsEnumerable()
.SingleOrDefault(r=> r.Field<int>("ID") == 5);
(Substitute int for the type of your ID field)
I could use the following code.
Thanks everyone.
int intID = 5;
DataTable Dt = MyFuctions.GetData();
Dt.PrimaryKey = new DataColumn[] { Dt.Columns["ID"] };
DataRow Drw = Dt.Rows.Find(intID);
if (Drw != null) Dt.Rows.Remove(Drw);
You can try with method select
DataRow[] rows = table.Select("ID = 7");
DataRow dataRow = dataTable.AsEnumerable().FirstOrDefault(r => Convert.ToInt32(r["ID"]) == 5);
if (dataRow != null)
{
// code
}
If it is a typed DataSet:
MyDatasetType.MyDataTableRow dataRow = dataSet.MyDataTable.FirstOrDefault(r => r.ID == 5);
if (dataRow != null)
{
// code
}
try this code
DataRow foundRow = FinalDt.Rows.Find(Value);
but set at lease one primary key
Hello just create a simple function that looks as shown below.. That returns all rows where the call parameter entered is valid or true.
public DataTable SearchRecords(string Col1, DataTable RecordDT_, int KeyWORD)
{
TempTable = RecordDT_;
DataView DV = new DataView(TempTable);
DV.RowFilter = string.Format(string.Format("Convert({0},'System.String')",Col1) + " LIKE '{0}'", KeyWORD);
return DV.ToTable();
}
and simply call it as shown below;
DataTable RowsFound=SearchRecords("IdColumn", OriginalTable,5);
where 5 is the ID.
Thanks..
Try avoiding unnecessary loops and go for this if needed.
string SearchByColumn = "ColumnName=" + value;
DataRow[] hasRows = currentDataTable.Select(SearchByColumn);
if (hasRows.Length == 0)
{
//your logic goes here
}
else
{
//your logic goes here
}
If you want to search by specific ID then there should be a primary key in a table.
By trying to avoid to many foreach()->if() routines, i tried a lambda-concept to search through a bunch of DataTables. I had no errors until i debugged my code to see it does not work, because its not allowed to ask my datarow-column for its index... is there any way to make this work instead of using IndexOf()?
static Entity.Produkt ProduktConstructor(DataRow dr)
{
Entity.Produkt p = new Entity.Produkt();
DataTable dt = Entity.KbMirror.mirror.Tables["Produkt"];
p.id = Guid.Parse(dr[0].ToString());
p.name = dr[1].ToString();
byte[] ba = dt.Rows[dt.IndexOf(dt.Select().Where(r => r[0].ToString() == p.id.ToString()))]["ProduktLogo"];
p.logo = Converter.ImageConverter.BA2Image(ba);
foreach (DataRow pvdr in Entity.KbMirror.mirror.Tables["Produkt_Version"].Rows)
if (Guid.Parse(pvdr[1].ToString()) == p.id)
p.version.Add(VersionConstructor(Guid.Parse(pvdr[2].ToString() ), Guid.Parse(pvdr[0].ToString() ) ) );
return p;
}
static Entity.Version VersionConstructor(Guid vid, Guid pvid)
{
Entity.Version version = new Entity.Version();
DataTable dt = Entity.KbMirror.mirror.Tables["Version"];
version.id = vid;
version.name = dt.Rows[dt.IndexOf(dt.Select().Where(r =>r[0].ToString() == vid.ToString()))][1].ToString();
foreach (DataRow cvdr in Entity.KbMirror.mirror.Tables["Customer_ProduktVersion"].Rows)
if (Guid.Parse(cvdr[2].ToString()) == pvid)
version.customerCollection.Add(CustomerConstructor(Guid.Parse(cvdr[1].ToString())));
return version;
}
EDIT:
error occures when I use "IndexOf()" like this:
byte[] ba = dt.Rows[dt.IndexOf(dt.Select().Where(r => r[0].ToString() == p.id.ToString()))]["ProduktLogo"];
Have you tried passing the entire table as opposed to just the row? Once you pass the entire table, then you can reference just that row of the table.
Also: http://msdn.microsoft.com/en-us/library/bb552415%28v=vs.110%29.aspx
// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);
DataTable products = ds.Tables["Product"];
IEnumerable<DataRow> query =
from product in products.AsEnumerable()
select product;
Console.WriteLine("Product Names:");
foreach (DataRow p in query)
{
Console.WriteLine(p.Field<string>("Name"));
}
i have this code
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
conn.Open();
DataTable Databases = conn.GetSchema("Databases");
DataTable Tables = conn.GetSchema("Tables");
DataTable Columns = conn.GetSchema("Columns");
conn.close();
}
i need to return datattype by reading string value in column "DATA_TYPE"
foreach (DataRow row in Columns.Rows)
if (row["TABLE_NAME"].ToString() == tableName)
{
if (fName == row["COLUMN_NAME"].ToString())
{
//return Datatype
var x = row["DATA_TYPE"];
}
}
////if(row["DATA_TYPE"] == "int") how i can set var x by DataType (Int)
or how to get datatype by name that is found in row["DATA_TYPE"]??!!
a solution would be to create a dictionary mapping sql types to .net types:
Dictionary<string, Type> sqlToNetTypes;
and populate it with all possible types you can find in column "DATA_TYPE" and their .NET equivalent:
sqlToNetTypes.Add("int", typeof(int));
sqlToNetTypes.Add("varchar", typeof(sting));
sqlToNetTypes.Add("datetime", typeof(DateTime));
sqlToNetTypes.Add("bit", typeof(bool));
sqlToNetTypes.Add("numeric", typeof(float));//or double or decimal as you like...
...
then in a helper method:
Type GetNETType(string sqlType)
{
if(sqlToNetTypes.ContainsKey(sqlType))
{
return sqlToNetTypes[sqlType];
}else
{
return typeof(object); //generic type
}
}
and use it like this:
foreach (DataRow row in Columns.Rows)
if (row["TABLE_NAME"].ToString() == tableName)
{
if (fName == row["COLUMN_NAME"].ToString())
{
//return Datatype
var x = GetNETType(row["DATA_TYPE"]);
}
}