I have an extension method to turn an IEnumerable into a data table and it is throwing this exception. System.Data.DuplicateNameException: A column named 'Item' already belongs to this DataTable. What's confusing is that there is not a column named 'Item' in this table, or at least there shouldn't be because the SqlTable it was created from does not have an 'Item' column.
public static DataTable ToDataTable<T>(this IEnumerable<T> items)
{
var dataTable = new DataTable(typeof(T).Name);
var props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in props)
{
dataTable.Columns.Add(prop.Name, prop.PropertyType);
}
foreach (var item in items)
{
var values = new object[props.Length];
for (var i = 0; i < props.Length; i++)
{
values[i] = props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
This extention method has been working except until now when I use it with a method that takes in a sql table and makes it a datatable, then turns the data table into and IEnumerable to update one column and then uses the extenstion method on the Ienumerable to turn it back into a datatable.
var strSqlQuery = "Select * FROM " + strTableName;
var dataTable = Database.CreateDataTableFromDatabaseTable(strSqlQuery);
var ocRows = dataTable.AsEnumerable(); // turn the data table into an enumerable we can sqlbulkcopy dump later
foreach (var dataRow in ocRows)
{
if (dataRow[4].ToString().Contains("COMPLETED")) continue;
// Generate and Save Needed Hashes for this Node
// This is the algorithm to generate the hash
var md5Hash = MD5.Create();
var profileId = Database.GetProfileIdByEndPage(dataRow[3].ToString(), false);
var endPageId = Database.GetEndPageId(navigationProfileId);
var strValuesForObjectHash = string.IsNullOrEmpty(dataRow[6].ToString()) // if the "id" is null or empty use xpath
? endPageId + "," + dataRow[7] // use the xpath for the object hash, not the "id"
: endPageId + "," + dataRow[6]; // if the id has a value use the id for the object hash
var currentObjectHash = strValuesForObjectHash.GetMd5Hash(md5Hash);
dataRow[1] = currentObjectHash;
}
I tried in the extension method to check if the column had already been added but then got
System.Reflection.TargetParameterCountException: Parameter count mismatch.
foreach (var prop in props)
{
if (dataTable.Columns.Contains(prop.Name))
dataTable.Columns.Add(prop.Name, prop.PropertyType);
}
How can I use the DataTable as enumerable to update the one column for each row and make it into a DataTable again?
Related
I'm new to C#, I never worked with a DataTable before.
I want a DataGridView with specific names.
DataTable table = new DataTable();
List<string> bla = new List<string>();
XDocument config = XDocument.Load(configFile);
Dictionary<string, string> dict = config.Descendants("Columns").FirstOrDefault().Elements()
.GroupBy(x => (string)x.Attribute("XPath"), y => (string)y.Attribute("Name"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
//I dont know if I need this:
foreach (string key in dict.Keys)
{
table.Columns.Add(key, typeof(string));
}
foreach (XElement position in positions.Where(e => e.HasAttributes))
{
foreach (XAttribute attribute in position.Attributes().Where(a => dict.ContainsKey($"#{a.Name.LocalName}")))
{
string name = attribute.Name.LocalName;
string value = (string)attribute;
string xName = dict["#" + name];
bla.Add(xName);
}
The columns should have the name from xName.
How can I do this?
I've tried this:
foreach (var item in bla)
{
DataRow row = table.NewRow();
row.SetField<string>(item); //this didn't work.
//foreach (string key in dict.Keys)
//{
// row.SetField<string>(key, item[key]);
//}
}
Just want the names from xName as my heading for the output.
Example für xName: Position, Status, Order, Number, ...
As my heading.
And under that the values.
if i understand you correctly, you've got your list of column names ok, but dont know how to create a datatable with the correct column names.
Below is an example of how to add a column and row to a datatable with a specific column header name.
As discussed in the comments, I've demonstrated a process to get the data you need into a structure that allows you to populate your table.
//Class to hold data
public class MyRecordContent
{
public MyRecordContent()
{
//initialise list
RecordsColumns = new List<string>();
}
//Holds a list of strings for each column of the record.
//It starts at position 0 to however many columns you have
public List<string> RecordsColumns { get; set; }
}
//This creates an empty table with the columns
var myTable = new DataTable("Table1");
foreach (var item in bla)
{
if (!myTable.Columns.Contains(item))
{
myTable.Columns.Add(new DataColumn(item, typeof(string)));
}
}
//Here you build up a list of all records and their field content from your xml.
foreach (var xmlNode in yourXMLRecordCollection)
{
var thisRecord = new MyRecordContent();
foreach (var xmlCol in xmlNode.Elements)//Each column value
{
thisRecord.RecordsColumns.Add(xmlCol.GetValue());
}
myListOfRecords.Add(thisRecord);
}
foreach (MyRecordContent record in myListOfRecords)
{
var row = myTable.NewRow();
//Here we set each row column values in the datatable.
//Map each rows column value to be the value in the list at same position.
for (var colPosition = 0; colPosition <= myTable.Columns.Count - 1;) //Number of columns added.
{
row[colPosition] = record.RecordsColumns[colPosition];
}
myTable.Rows.Add(row);
}
In the above, itterate through your list of column names and add each column to the table. You may want to add a switch statement to the loop to change the datatype of the column based upon name if required. Then create of new row off that table and set each fields value accordingly.
Finally, add the new row to the datatable.
Hope that helps.
Then
I am trying to convert a List to a datatable with an extension method. Implementation is:
Extension method
public static class list2Dt
{
public static DataTable ToDataTable<T>(List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dataTable.Columns.Add(prop.Name);
}
foreach (T item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] = Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a breakpoint here and check datatable
return dataTable;
}
}
Controller
var noDups = firstTable.AsEnumerable()
.GroupBy(d => new
{
name = d.Field<string>("name"),
date = d.Field<string>("date")
})
.Where(d => d.Count() > 1)
.Select(d => d.First())
.ToList();
DataTable secondTable = new DataTable();
secondTable.Columns.Add("name", typeof(string));
secondTable.Columns.Add("date", typeof(string));
secondTable.Columns.Add("clockIn", typeof(string));
secondTable.Columns.Add("clockOut", typeof(string));
secondTable = list2Dt.ToDataTable(noDups);
I am getting this following error:
An exception of type 'System.Data.DuplicateNameException' occurred in System.Data.dll but was not handled in user code
Additional information: A column named 'Item' already belongs to this DataTable.
Above error is raised on line:
dataTable.Columns.Add(prop.Name);
Can someone find where problem lies.
Your ToDataTable method is expecting a list of objects - most likely a list of simple DTOs or similar.
You are passing it a list of DataRow instances, of which that class has multiple overloads of property Item which means when you're trying to build up the new DataTable it will try to add multiple columns with the name Item which is invalid in a DataTable.
On way around this is to project noDups to a new object, rather than retain the DataRow:
public class MyClass
{
public string Name{get;set;}
public string Date{get;set;}
}
var noDups = firstTable.AsEnumerable()
.GroupBy(d => new
{
name = d.Field<string>("name"),
date = d.Field<string>("date")
})
.Where(d => d.Count() > 1)
.Select(d => {
var first = d.First();
return new MyClass()
{
Name = (string)first["name"],
Date = (string)first["date"]
}
})
.ToList();
I am trying to remove rows that are not needed from a DataTable. Basically, there may be several rows where the itemID is identical. I want to find the rows where the column "failEmail" = "fail", and using the itemID of those rows, remove all rows from the emails DataTable that have the same itemID.
Here is what I have tried:
System.Diagnostics.Debug.Print(emails.Rows.Count.ToString() + " emails!");
// create a list of the email IDs for records that will be deleted
List<DataRow> rows2Delete = new List<DataRow>();
foreach (DataRow dr in emails.Rows)
{
if (dr["failEmail"].ToString().ToLower() == "fail")
{
rows2Delete.Add(dr);
}
}
foreach (DataRow row in rows2Delete)
{
DataRow[] drRowsToCheck =emails.Select("itemID ='" + row["itemID"].ToString() +"'");
foreach (DataRow drCheck in drRowsToCheck)
{
emails.Rows.RemovedDrCheck);
emails.AcceptChanges();
}
}
Here is the error message I am getting on the second pass:
This row has been removed from a table and does not have any data.
BeginEdit() will allow creation of new data in this row
How can I do what I need to without throwing errors like that? Is there a better way like using a LiNQ query?
The problem is that when the same itemID has multiple entries with 'fail', you are trying to remove them multiple times.
// 1. Find the Unique itemIDs to remove
var idsToRemove = emails.Select("failEmail = 'fail'").Select (x => x["itemID"]).Distinct();
// 2. Find all the rows that match the itemIDs found
var rowsToRemove = emails.Select(string.Format("itemID in ({0})", string.Join(", ", idsToRemove)));
// 3. Remove the found rows.
foreach(var rowToRemove in rowsToRemove)
{
emails.Rows.Remove(rowToRemove);
}
emails.AcceptChanges();
this is what I ended up doing, based on an answer I got from MSDN c# Forums:
create an extension on DataTable to enable LINQ euering of the Datatable:
public static class DataTableExtensions
{
public static IEnumerable<DataRow> RowsAsEnumerable ( this DataTable source )
{
return (source != null) ? source.Rows.OfType<DataRow>() : Enumerable.Empty<DataRow>();
}
}
then modified my code as below:
//Get IDs to delete
var deleteIds = from r in emails.RowsAsEnumerable()
where String.Compare(r["failEmail"].ToString(), "fail", true) == 0
select r["itemID"];
//Get all rows to delete
var rows2Delete = (from r in emails.RowsAsEnumerable()
where deleteIds.Contains(r["itemID"])
select r).ToList();
//Now delete them
foreach (var row in rows2Delete)
emails.Rows.Remove(row);
emails.AcceptChanges();
and now it works, just wish I could do it the normal way successfully.
foreach (DataRow rowFail in emails.Select("failEmail = 'fail'"))
{
DataRow[] rowsItem = emails.Select(String.Format("itemID = '{0}'", rowFail["itemID"]));
for (int i = rowsItem.Length - 1; i >= 0; i--)
{
rowsItem[i].Delete();
}
}
emails.AcceptChanges();
DataTable.Select returns an array of all DataRow objects that match the filter criteria.
I need to store the data returned from this LINQ to Entities query (below) into a DataTable so that I can use it as data source to a DataGridView, how can I do that?
In this case I'm using LINQ to Entities to query against an Entity Framework conceptual model, so db is a class that inherits from System.Data.Entity.DbContext.
using (TccContext db = new TccContext())
{
var query = from vendedor in db.Vendedores.AsEnumerable()
where vendedor.codigo == Convert.ToInt32(textBoxPesquisa.Text)
select vendedor;
// I'd like to do something like DataTable dt = query;
}
I've tried to do this (below), but it throws an exception during execution [1].
using (TccContext db = new TccContext())
{
IEnumerable<DataRow> query = (IEnumerable<DataRow>)(from vendedor in db.Vendedores.AsEnumerable()
where vendedor.codigo == Convert.ToInt32(textBoxPesquisa.Text)
select vendedor);
using (DataTable dt = query.CopyToDataTable<DataRow>())
{
this.dataGridViewProcura.Rows.Add(
dt.Rows[0][0], // Código
dt.Rows[0][1], // Nome
dt.Rows[0][2]); // Venda Mensal
}
}
[1]: Exception: InvalidCastException
Unable to cast object of type 'WhereEnumerableIterator`1[Projeto_TCC.Models.Vendedor]' to type 'System.Collections.Generic.IEnumerable`1[System.Data.DataRow]'.
Thanks in advance
There is one important thing here, you are casting your Linq query to (IEnumerable<DataRow>) when you are selecting the vendedor, so I assume that vendedor is an instance of Vendedor, so your query will return an IEnumerable<Vendedor>
That should solve your problem, but also, can you try using the generated DataTable as the DataSource for your DataGridView? It would be something like this:
var query = (from vendedor in db.Vendedores.AsEnumerable()
where vendedor.codigo == Convert.ToInt32(textBoxPesquisa.Text)
select vendedor);
var dt = query.CopyToDataTable<Vendedor>();
this.dataGridViewProcura.DataSource = dt;
Hope I can help!
EDIT
As a side (and very personal) note, you could try using lambdas on your select, they look prettier :)
var pesquisa = Convert.ToInt32(textBoxPesquisa.Text);
var query = db.Vendedores.Where(vendedor => vendedor.codigo == pesquisa);
var dt = query.CopyToDataTable<Vendedor>();
this.dataGridViewProcura.DataSource = dt;
A lot cleaner, don't you think?
EDIT 2
I've just realized what you said on CopyToDataTable being for DataRow only, so last (admittedly not so clean) solution would be to mimic the logic on the helper?
public DataTable CopyGenericToDataTable<T>(this IEnumerable<T> items)
{
var properties = typeof(T).GetProperties();
var result = new DataTable();
//Build the columns
foreach ( var prop in properties ) {
result.Columns.Add(prop.Name, prop.PropertyType);
}
//Fill the DataTable
foreach( var item in items ){
var row = result.NewRow();
foreach ( var prop in properties ) {
var itemValue = prop.GetValue(item, new object[] {});
row[prop.Name] = itemValue;
}
result.Rows.Add(row);
}
return result;
}
Now, things to consider:
This solution will not work with complex properties
Customizing the resulting table might be a bit tricky
While this might solve the issue, I don't think this is a very good approach, but it could be the start of a decent idea :)
I hope I can help this time!
This is a the MSDN recommended solution: https://msdn.microsoft.com/en-us/library/bb669096(v=vs.110).aspx
I have Implemented it successfully
(*with minor additions to handle nullable DateTime.)
as Follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Reflection;
/// <summary>
/// Converts Entity Type to DataTable
/// </summary>
public class ObjectShredder<T>
{
private System.Reflection.FieldInfo[] _fi;
private System.Reflection.PropertyInfo[] _pi;
private System.Collections.Generic.Dictionary<string, int> _ordinalMap;
private System.Type _type;
// ObjectShredder constructor.
public ObjectShredder()
{
_type = typeof(T);
_fi = _type.GetFields();
_pi = _type.GetProperties();
_ordinalMap = new Dictionary<string, int>();
}
/// <summary>
/// Loads a DataTable from a sequence of objects.
/// </summary>
/// <param name="source">The sequence of objects to load into the DataTable.</param>
/// <param name="table">The input table. The schema of the table must match that
/// the type T. If the table is null, a new table is created with a schema
/// created from the public properties and fields of the type T.</param>
/// <param name="options">Specifies how values from the source sequence will be applied to
/// existing rows in the table.</param>
/// <returns>A DataTable created from the source sequence.</returns>
public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options)
{
// Load the table from the scalar sequence if T is a primitive type.
if (typeof(T).IsPrimitive)
{
return ShredPrimitive(source, table, options);
}
// Create a new table if the input table is null.
if (table == null)
{
table = new DataTable(typeof(T).Name);
}
// Initialize the ordinal map and extend the table schema based on type T.
table = ExtendTable(table, typeof(T));
// Enumerate the source sequence and load the object values into rows.
table.BeginLoadData();
using (IEnumerator<T> e = source.GetEnumerator())
{
while (e.MoveNext())
{
if (options != null)
{
table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options);
}
else
{
table.LoadDataRow(ShredObject(table, e.Current), true);
}
}
}
table.EndLoadData();
// Return the table.
return table;
}
public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options)
{
// Create a new table if the input table is null.
if (table == null)
{
table = new DataTable(typeof(T).Name);
}
if (!table.Columns.Contains("Value"))
{
table.Columns.Add("Value", typeof(T));
}
// Enumerate the source sequence and load the scalar values into rows.
table.BeginLoadData();
using (IEnumerator<T> e = source.GetEnumerator())
{
Object[] values = new object[table.Columns.Count];
while (e.MoveNext())
{
values[table.Columns["Value"].Ordinal] = e.Current;
if (options != null)
{
table.LoadDataRow(values, (LoadOption)options);
}
else
{
table.LoadDataRow(values, true);
}
}
}
table.EndLoadData();
// Return the table.
return table;
}
public object[] ShredObject(DataTable table, T instance)
{
FieldInfo[] fi = _fi;
PropertyInfo[] pi = _pi;
if (instance.GetType() != typeof(T))
{
// If the instance is derived from T, extend the table schema
// and get the properties and fields.
ExtendTable(table, instance.GetType());
fi = instance.GetType().GetFields();
pi = instance.GetType().GetProperties();
}
// Add the property and field values of the instance to an array.
Object[] values = new object[table.Columns.Count];
foreach (FieldInfo f in fi)
{
values[_ordinalMap[f.Name]] = f.GetValue(instance);
}
foreach (PropertyInfo p in pi)
{
values[_ordinalMap[p.Name]] = p.GetValue(instance, null);
}
// Return the property and field values of the instance.
return values;
}
public DataTable ExtendTable(DataTable table, Type type)
{
// Extend the table schema if the input table was null or if the value
// in the sequence is derived from type T.
foreach (FieldInfo f in type.GetFields())
{
if (!_ordinalMap.ContainsKey(f.Name))
{
// Add the field as a column in the table if it doesn't exist
// already.
DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name]
: table.Columns.Add(f.Name, f.FieldType);
// Add the field to the ordinal map.
_ordinalMap.Add(f.Name, dc.Ordinal);
}
}
foreach (PropertyInfo p in type.GetProperties())
{
if (!_ordinalMap.ContainsKey(p.Name))
{
// Add the property as a column in the table if it doesn't exist already.
DataColumn dc = table.Columns[p.Name];
//Added Try Catch to account for Nullable Types
try
{
dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name]
: table.Columns.Add(p.Name, p.PropertyType);
}
catch (NotSupportedException nsEx)
{
string pType = p.PropertyType.ToString();
dc = pType.Contains("System.DateTime") ? table.Columns.Add(p.Name, typeof(System.DateTime)) : table.Columns.Add(p.Name);
//dc = table.Columns.Add(p.Name); //Modified to above statment in order to accomodate Nullable date Time
}
// Add the property to the ordinal map.
_ordinalMap.Add(p.Name, dc.Ordinal);
}
}
// Return the table.
return table;
}
}
}
The (big) caveat to this solution is that it is ** costly** and you have to customize it in the error handling.
you can put
var query = from ....
this.dataGridViewProcura.DataSource = query.tolist()
In my C# code, I have a source DataTable, and want to query it, storing the results to another DataTable.
I have A DataTable with stgId, fromdate, todate, colorCode, something1, something2 as columns. After querying with the where condition I need to remove something1 and something2 columns and to get the result in another DataTable.
Equivalent SQL query would be as shown below
SELECT
stgId,
fromdate,
todate,
colorCode
FROM
tblScheduling
WHERE
Mcode='123'
I want to get the result in another DataTable.
EDIT: Update After Answering
It is possible to get the result as DataRow[] type using where condition like this.
DataRow[] results = table.Select("A = 'foo' AND B = 'bar' AND C = 'baz'");
However I wanted the result set as new DataTable.
Quote from accepted answer
"Read about LINQ and lambda expression, they will be very useful for you. You can read about them here and here"
You can't use CopyToDataTable method directly, instead See: How to: Implement CopyToDataTable Where the Generic Type T Is Not a DataRow. After setting up your classes as per the link you can later call the method CopyToDataTable like:
var newDataTable = (dt.AsEnumerable()
.Where(r=> r.Field<string>("Mcode" == "123")
.Select new
{
stgId = r.Field<int>("stgId"),
fromdate = r.Field<DateTime>("fromdate"),
todate = r.Field<DateTime>("todate"),
colorCode = r.Field<int>("colorCode")
}).CopyToDataTable();
Remember to use the correct type in Field extension method.
The above requires following two classes to be setup in your code. *(its from the same MSDN link)
public static class CustomLINQtoDataSetMethods
{
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source)
{
return new ObjectShredder<T>().Shred(source, null, null);
}
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source,
DataTable table, LoadOption? options)
{
return new ObjectShredder<T>().Shred(source, table, options);
}
}
public class ObjectShredder<T>
{
private System.Reflection.FieldInfo[] _fi;
private System.Reflection.PropertyInfo[] _pi;
private System.Collections.Generic.Dictionary<string, int> _ordinalMap;
private System.Type _type;
// ObjectShredder constructor.
public ObjectShredder()
{
_type = typeof(T);
_fi = _type.GetFields();
_pi = _type.GetProperties();
_ordinalMap = new Dictionary<string, int>();
}
/// <summary>
/// Loads a DataTable from a sequence of objects.
/// </summary>
/// <param name="source">The sequence of objects to load into the DataTable.</param>
/// <param name="table">The input table. The schema of the table must match that
/// the type T. If the table is null, a new table is created with a schema
/// created from the public properties and fields of the type T.</param>
/// <param name="options">Specifies how values from the source sequence will be applied to
/// existing rows in the table.</param>
/// <returns>A DataTable created from the source sequence.</returns>
public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options)
{
// Load the table from the scalar sequence if T is a primitive type.
if (typeof(T).IsPrimitive)
{
return ShredPrimitive(source, table, options);
}
// Create a new table if the input table is null.
if (table == null)
{
table = new DataTable(typeof(T).Name);
}
// Initialize the ordinal map and extend the table schema based on type T.
table = ExtendTable(table, typeof(T));
// Enumerate the source sequence and load the object values into rows.
table.BeginLoadData();
using (IEnumerator<T> e = source.GetEnumerator())
{
while (e.MoveNext())
{
if (options != null)
{
table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options);
}
else
{
table.LoadDataRow(ShredObject(table, e.Current), true);
}
}
}
table.EndLoadData();
// Return the table.
return table;
}
public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options)
{
// Create a new table if the input table is null.
if (table == null)
{
table = new DataTable(typeof(T).Name);
}
if (!table.Columns.Contains("Value"))
{
table.Columns.Add("Value", typeof(T));
}
// Enumerate the source sequence and load the scalar values into rows.
table.BeginLoadData();
using (IEnumerator<T> e = source.GetEnumerator())
{
Object[] values = new object[table.Columns.Count];
while (e.MoveNext())
{
values[table.Columns["Value"].Ordinal] = e.Current;
if (options != null)
{
table.LoadDataRow(values, (LoadOption)options);
}
else
{
table.LoadDataRow(values, true);
}
}
}
table.EndLoadData();
// Return the table.
return table;
}
public object[] ShredObject(DataTable table, T instance)
{
FieldInfo[] fi = _fi;
PropertyInfo[] pi = _pi;
if (instance.GetType() != typeof(T))
{
// If the instance is derived from T, extend the table schema
// and get the properties and fields.
ExtendTable(table, instance.GetType());
fi = instance.GetType().GetFields();
pi = instance.GetType().GetProperties();
}
// Add the property and field values of the instance to an array.
Object[] values = new object[table.Columns.Count];
foreach (FieldInfo f in fi)
{
values[_ordinalMap[f.Name]] = f.GetValue(instance);
}
foreach (PropertyInfo p in pi)
{
values[_ordinalMap[p.Name]] = p.GetValue(instance, null);
}
// Return the property and field values of the instance.
return values;
}
public DataTable ExtendTable(DataTable table, Type type)
{
// Extend the table schema if the input table was null or if the value
// in the sequence is derived from type T.
foreach (FieldInfo f in type.GetFields())
{
if (!_ordinalMap.ContainsKey(f.Name))
{
// Add the field as a column in the table if it doesn't exist
// already.
DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name]
: table.Columns.Add(f.Name, f.FieldType);
// Add the field to the ordinal map.
_ordinalMap.Add(f.Name, dc.Ordinal);
}
}
foreach (PropertyInfo p in type.GetProperties())
{
if (!_ordinalMap.ContainsKey(p.Name))
{
// Add the property as a column in the table if it doesn't exist
// already.
DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name]
: table.Columns.Add(p.Name, p.PropertyType);
// Add the property to the ordinal map.
_ordinalMap.Add(p.Name, dc.Ordinal);
}
}
// Return the table.
return table;
}
}
foreach (DataRow dr in dataTable1.Rows) {
if (dr["Mcode"].ToString()=="123")
dataTable2.Rows.Add(dr.ItemArray);
}
The above example assumes that dataTable1 and dataTable2 have the same number, type and order of columns.
Edit 1
You can use clone method to copy structure of existing datatable into another.
http://msdn.microsoft.com/en-IN/library/system.data.datatable.clone.aspx
Suppose you have a datatable dt1 So you can create a clone as follows
DataTable dt2 = dt1.Clone();
and use the above loop as follows
foreach (DataRow dr in dt1.Rows) {
if (dr["Mcode"].ToString()=="123")
dt2.Rows.Add(dr.ItemArray);
}