I am trying to write a couple of extensions to convert UniDataSets and UniRecords to DataSet and DataRow but I get the following error when I try to compile.
'System.Data.DataRow.DataRow(System.Data.DataRowBuilder)' is inaccessible due to its protection level
Is there any way to fix this or should I abandon this approach and come at it a different way?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using IBMU2.UODOTNET;
namespace Extentions
{
public static class UniDataExtentions
{
public static System.Data.DataSet ImportUniDataSet(this System.Data.DataSet dataSet, IBMU2.UODOTNET.UniDataSet uniDataSet)
{
foreach (UniRecord uniRecord in uniDataSet)
{
DataRow dataRow = new DataRow();
dataRow.ImportUniRecord(uniRecord);
dataSet.Tables[0].ImportRow(dataRow);
}
return dataSet;
}
public static void ImportUniRecord(this System.Data.DataRow dataRow, IBMU2.UODOTNET.UniRecord uniRecord)
{
int fieldCount = uniRecord.Record.Dcount();
// ADD COLUMS
dataRow.Table.Columns.AddRange(new DataColumn[fieldCount]);
// ADD ROW
for (int x = 1; x < fieldCount; x++)
{
string stringValue = uniRecord.Record.Extract(x).StringValue;
dataRow[x] = stringValue;
}
}
}
}
It doesn't matter whether it's in an extension method, or any method. The DataRow constructor is not publicly accessible. You need to use the DataTable.NewRow() method to create a new DataRow.
It will use the schema information from the data table to create a row that matches it. If you just tried to use the constructor on it's own the object would have no idea what schema should be used.
I tried a simpler approach, however it is for multiple rows and can be applied to a single row as well:
//Declare a variable for multiple rows
DataRow[] rows = null;
//get some data in a DataTable named table
//Select specific data from DataTable named table
rows = table.Select("column = 'ColumnValue'");
//Read the value in a variable from the row
string ColumnValue = rows[0]["column"].ToString();
hope this helps...
Related
I have searched high and low for a method to show the entire row of a C# datatable, both by referencing the row number and by simply writing the row contents to a string variable and showing the string in the console. I can specify the exact row and field value and display that value, but not the whole row. This is not a list in C#, this is a datatable.
For the simple code below, the output I get for the first WriteLine is "Horse", but the second two WriteLine commands, I get the console output of "System.Data.DataRow" instead of the whole row of data.
What am I doing wrong? Any help would be appreciated.
using System;
using System.Data;
using System.Threading;
namespace DataTablePractice
{
class Program
{
static void Main(string[] args)
{
// Create a DataTable.
using (DataTable table = new DataTable())
{
// Two columns.
table.TableName = "table";
table.Columns.Add("Number", typeof(string));
table.Columns.Add("Pet", typeof(string));
// ... Add two rows.
table.Rows.Add("4", "Horse");
table.Rows.Add("10", "Moose");
// ... Display first field of the first row in the console
Console.WriteLine(table.Rows[0].Field<string>(1));
//...Display the first row of the table in the console
Console.WriteLine(table.Rows[0]);
//...Create a new row variable to add a third pet
var newrow = table.Rows.Add("15", "Snake");
string NewRowString = newrow.ToString();
//...Display the new row of data in the console
Console.WriteLine(NewRowString);
//...Sleep for a few seconds to examine output
Thread.Sleep(4000);
}
}
}
}
When you run this:
Console.WriteLine(table.Rows[0]);
It's in effect calling this:
Console.WriteLine(table.Rows[0].ToString()); // prints object type, in this case a DataRow
If it were your own class, you could override ToString to return whatever you need, but you don't have that option with the DataRow class. And so it uses the default behavior as described here:
Default implementations of the Object.ToString method return the fully qualified name of the object's type.
You could iterate through the columns, like this for example:
var row = table.Rows[0];
for (var i = 0; i < row.Count; i++)
Console.Write(row[i] + " : ");
Or, a shorter way to print them all out:
Console.WriteLine(String.Join(" : ", table.Rows[0].ItemArray));
Given your data, maybe you just want to reference the two fields?
foreach (DataRow row in dt.Rows)
Console.WriteLine($"You have {row[0]} {row[1]}(s).");
// You have 4 Horse(s).
// You have 10 Moose(s).
While the answer here is excellent, I highly recommend using Spectre.Console
It is an open source library that helps you generate highly formatted console output.
With this, the code to write the output simply becomes:
public static void Print(this DataTable dataTable)
{
var table = new Table();
table.AddColumn("#");
for (int i=0;i<dataTable.Columns.Count;i++)
{
table.AddColumn(dataTable.Columns[i].ColumnName);
}
for(int i=0;i<dataTable.Rows.Count;i++)
{
var values = new List<string>
{
i.ToString()
};
for (int j = 0; j < dataTable.Columns.Count;j++)
{
values.Add(dataTable.Rows[i][j]?.ToString()??"null");
}
table.AddRow(values.ToArray());
}
AnsiConsole.Write(table);
}
I want to convert my Model data to DataSet or DataTable (to export in excel format)
db.EMPs.ToList()
db is DataContext , EMPs is dataclass .
How to export this list to DataTable, I can export rows to excel but how to access column name from header (column name should not be added manually in DataTable)
You can use ToDataTable extension method but you need to install MoreLinq first. To install MoreLINQ, run the following command in the Package Manager Console:
PM> Install-Package morelinq
Then add the following line to your using directives:
using MoreLinq;
And finally you can use ToDataTable extension method:
DataTable s = db.EMPs.ToDataTable();
To quickly create a file that can be read in Excel you could map the contents to a comma-separated value list using LINQ and then save the array to a file stream.
var records = db.EMP
.ToList()
.Select(record => $"\"{record.stringField}\",{record.numberField}")
.ToArray();
File.WriteAllLines("file.csv", records);
Using MoreLinq is the best way to convert a class to DataTable as already answered by S.Akbari
Below is another way I found to accomplish this by using System.Reflection
List<EMP> list= db.EMPs.ToList();
DataTable dt = new DataTable();
PropertyInfo[] Props = typeof(EMP).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting column names as Property names
dt.Columns.Add(prop.Name);
}
foreach (EMP e in list)
{
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(e, null);
}
dt.Rows.Add(values);
}
Took an example from the website and trying to create a loop that would tag certain cells based on their cell content which would be identified through the FindText Method from the Gembox component
My goal is:
find cell with a partial match of the keyword
going to the last column of that row
changing the color of that row to a specific color
keep going down document repeating previous commands
stopping once the document has ended
The search works in a sense of finding the query then doing what I instructed it to do, but it stops after the 1st search result.
Is there a way to loop the search using this method or can I use it and another method to test a cell to see if it has a partial piece of what I'm searching for?
This is the link that I'm basing my knowledge on:
https://www.gemboxsoftware.com/spreadsheet/examples/excel-search/109
Thanks again guys.
Below is me working out how the system works on a 1 query basis I'd like to do this for the whole document
using System;
using System.Drawing;
using System.Text;
using System.IO;
using GemBox.Spreadsheet;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace autoexcel2
{
class Program
{
[STAThread]
static void Main(string[] args)
{
//IF USING PRO PUT YOUR SERIAL BELOW
SpreadsheetInfo.SetLicense("FREE-lIMITED-KEY");
ExcelFile ef = ExcelFile.Load("sample.xlsx");
string searchText = "pharma";
var ws = ef.Worksheets[0];
StringBuilder sb = new StringBuilder();
int row;
int col;
ws.Cells.FindText(searchText, false, false, out row, out col);;
if (row == -1 || col == -1)
{
sb.AppendLine("cant find nada");
Console.WriteLine(sb.ToString());
}
else
{
ws.Cells[row,5].Style.FillPattern.SetSolid(Color.Aqua);
}
ef.Save("done.xlsx");
}
}
}
Try the following:
var workbook = ExcelFile.Load("sample.xlsx");
var worksheet = workbook.Worksheets[0];
var searchText = "pharma";
foreach (var currnetRow in worksheet.Rows)
{
int row, col;
if (currnetRow.Cells.FindText(searchText, false, false, out row, out col))
currnetRow.AllocatedCells.Last().Style.FillPattern.SetSolid(Color.Aqua);
}
workbook.Save("done.xlsx");
With this, you can find the first occurrence of searched text in the row and then format the row's last cell as needed.
But if you need to format those found cells, then the above might not work for you because a single row could have multiple cells with searched text.
In that case, you could use something like the following:
var workbook = ExcelFile.Load("sample.xlsx");
var worksheet = workbook.Worksheets[0];
var searchText = "pharma";
foreach (var row in worksheet.Rows)
{
var range = row.Cells.GetSubrangeAbsolute(row.Index, 0, row.Index, row.AllocatedCells.Count);
while (range.FindText(searchText, out int r, out int c))
{
worksheet.Cells[r, c].Style.FillPattern.SetSolid(Color.Aqua);
range = range.GetSubrangeAbsolute(r, c + 1, r, range.LastColumnIndex);
}
}
workbook.Save("done.xlsx");
I need to iterate the columnname and column datatype from a specific row. All of the examples I have seen have iterated an entire datatable. I want to pass a single row to a function to do a bunch of conditional processing. I want to separate the conditional processing for ease of readability.
This is what I have:
private void doMore(DataRow dr)
{
foreach (DataColumn c in dr.ItemArray) //loop through the columns.
{
MessageBox.Show(c.ColumnName.ToString());
}
}
The error returned is
System.InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Data.DataColumn'.
How would I get the column name from the row or do I have no choice and must pass the entire datatable to the function?
You would still need to go through the DataTable class. But you can do so using your DataRow instance by using the Table property.
foreach (DataColumn c in dr.Table.Columns) //loop through the columns.
{
MessageBox.Show(c.ColumnName);
}
You can make it easier in your code (if you're doing this a lot anyway) by using an extension on the DataRow object, like:
static class Extensions
{
public static string GetColumn(this DataRow Row, int Ordinal)
{
return Row.Table.Columns[Ordinal].ColumnName;
}
}
Then call it using:
string MyColumnName = MyRow.GetColumn(5);
You need something like this:
foreach(DataColumn c in dr.Table.Columns)
{
MessageBox.Show(c.ColumnName);
}
use DataTable object instead:
private void doMore(DataTable dt)
{
foreach(DataColumn dc in dt.Columns)
{
MessageBox.Show(dc.ColumnName);
}
}
As I iterate through a DataTable object, I need to check each of its DataRow objects against the items in a generic string List.
I found a blog post using the List's Find method along with a delegate, but whereas that example has a separate class (Person), I'm attempting something like the following using an instance of the string object:
// My definition of the List object.
List<string> lstAccountNumbers = new List<string>();
...
// I populate the List via its Add method.
...
foreach (DataRow drCurrentRow in dtMyDataTable.Rows)
{
if (lstAccounts.Find(delegate(string sAccountNumber) { return sAccountNumber == drCurrentRow["AccountNumber"]; })
{
Found_DoSomething();
}
else
{
NotFound_DoSomethingElse();
}
}
However, with this syntax I'm receiving "Cannot implicitly convert type 'string' to 'bool'" for the if block.
Could someone please clarify what I'm doing wrong and how best to accomplish what I'm trying to do?
Same Delegate Different method.
You want to use Exists Not Find.
Find Returns a value while exists returns a bool.
if (lstAccounts.Exists(delegate(string sAccountNumber) { return sAccountNumber == drCurrentRow["AccountNumber"]; })
why would not this work for you?
foreach (DataRow drCurrentRow in dtMyDataTable.Rows)
{
if (lstAccounts.Contains(drCurrentRow["AccountNumber"].ToString()))
{
Found_DoSomething();
}
else
{
NotFound_DoSomethingElse();
}
}
The problem is the if (lstAccounts.Find part.
This Find will return a string if found and the if is expecting a bool output.
Change your statement to use Exists or compare your original value to the Find result.
The list Find method returns a string so you should compare it using Equals method or ==.In that case the if condition will be fine.
try using linq, you can create a helper that takes in col name etc...
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication1
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
DataTable table = new DataTable();
table.Columns.Add("col1", typeof(string));
DataRow row;
row = table.NewRow();
row["col1"] = "123";
table.Rows.Add(row);
row = table.NewRow();
row["col1"] = "456";
table.Rows.Add(row);
LinqList<DataRow> rows = new LinqList<DataRow>(table.Rows);
// do a simple select
DataRow [] selectedRows = (from r in rows where (string)r["col1"] == "123" select r).ToArray();
if(selectedRows.Length > 0)
{
lable1.Text = "success";
}
else
{
lable1.Text = "failed";
}
}
}
// simple wrapper that implements IEnumerable<T>
internal class LinqList<T> : IEnumerable<T>, IEnumerable
{
IEnumerable items;
internal LinqList(IEnumerable items)
{
this.items = items;
}
#region IEnumerable<DataRow> Members
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
foreach (T item in items)
yield return item;
}
IEnumerator IEnumerable.GetEnumerator()
{
IEnumerable<T> ie = this;
return ie.GetEnumerator();
}
#endregion
}
}
taken code from this url
Iterate through a DataTable to find elements in a List object?