C# ExcelDataReader read from specific columns only - c#

i'm trying to get data from my excel sheet to add it into database which works perfectly but i only want the data under specific headers.
Here is my config code:
var headers = new List<string>;
DataSet result = excelDataReader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
{
UseHeaderRow = true,
ReadHeaderRow = rowReader =>
{
for (var i = 0; i < rowReader.FieldCount; i++)
headers.Add(Convert.ToString(rowReader.GetValue(i)));
},
FilterColumn = (columnReader, columnIndex) =>
headers.IndexOf("LOCATION") == columnIndex
|| headers.IndexOf("PARENT") == columnIndex
|| headers.IndexOf("DESCRIPTION") == columnIndex
}
});
LOCATION,PARENT and DESCRIPTION are the columns header names.
and here is the code i'm using to add the data to database
foreach (DataTable table in result.Tables)
{
foreach (DataRow row in table.Rows)
{
if (!existedLocations.Any(l => l.ShortCode?.Replace(" ", String.Empty) == row[0].ToString().Replace(" ", String.Empty)))
{
addtable.Name = addtable.NameAr = row[2].ToString().Substring(row[2].ToString().LastIndexOf(',') + 1);
addtable.ParentLocation = connection.Locations.FirstOrDefault(l => l.ShortCode == row[1].ToString()).Id;
addtable.LocationType = (int)LocationsTypes.Area;
addtable.ShortCode = row[0].ToString();
addtable.Category = (int)LocationsCategory.indoor;
addtable.IsActive = 1;
addtable.Isdeleted = 0;
existedLocations.Add(addtable);
connection.Locations.InsertOnSubmit(addtable);
connection.SubmitChanges();
addtable = new Location();
}
}
}
the sheets headers is defined as following
sheet1
sheet2

Well, you have two sheets, with the same headers but in different position. Your code is adding the headers of the first sheet to the list and then the ones from the second sheet. So, when you look for the headers to filter in the second sheet, you get the indexes from the first one, as IndexOf will get the first occurence.
Also, it appears that you're only using headers list to filter the columns, so you can simplify:
var result = reader.AsDataSet(new ExcelDataSetConfiguration()
{
ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration()
{
UseHeaderRow = true,
FilterColumn = (columnReader, columnIndex) =>
{
string header = columnReader.GetString(columnIndex);
return (header == "LOCATION" ||
header == "PARENT" ||
header == "DESCRIPTION"
);
}
}
});

Related

csvHelper Put values from different lines into one filed in Database

I have a .csv file structured like so, first row is the header column, for each SomeID I need to add the NetCharges together(or substract if the code calls for it) and put each item into its own column by the SomeCode column.
Heres the file I receive;
SomeID,OrderNumber,Code,NetCharge,Total
23473,30388,LI 126.0000, 132.00
96021, 000111, LI, 130.00, 126.00
23473,30388,FU 6.0000, 132.00
4571A,10452,LI,4100.0000, 4325.0000
4571A,10452,FU,150.00,4325.0000
4571A,10452,DT,75.00,4325.0000
I need to insert the data to my sql table which is structured like this. This is what I'm aiming for:
ID OrderNumber LICode LICodeValue FUCode FUCodeValue DTCode, DTCodeValue, total
23473 30388n LI 126.000 FU 6.0000 NULL NULL 132.0000
4571A 10452 LI 4100.0000 FU 150.0000 DT 75.00 4325.0000
My SomeID will not always be grouped together like the 4571A id is.I basically need to iterate over this file and create one record for each SomeID. I cannot seem to find a way with csvHelper. I'm using C# and csvHelper. I have trid this so far but I cannot get back to the SomeId after passing on to the nexr one:
using (var reader = new StreamReader( "C:\testFiles\some.csv" ))
using (var csv = new CsvReader( reader, CultureInfo.InvariantCulture ))
{
var badRecords = new List<string>();
var isRecordBad = false;
csv.Configuration.HasHeaderRecord = true;
csv.Configuration.HeaderValidated = null;
csv.Configuration.IgnoreBlankLines = true;
csv.Configuration.Delimiter = ",";
csv.Configuration.BadDataFound = context =>
{
isRecordBad = true;
badRecords.Add( context.RawRecord );
};
csv.Configuration.MissingFieldFound = ( s, i, context ) =>
{
isRecordBad = true;
badRecords.Add( context.RawRecord );
};
List<DataFile> dataFile = csv.GetRecords<DataFile>().ToList();
//initialize variable
string lastSomeId = "";
if (!isRecordBad)
{
foreach (var item in dataFile)
{
// check if its same record
if (lastSomeId != item.SomeID)
{
MyClass someClass = new MyClass();
lastSomeId = item.SomeID;
//decimal? LI = 0;//was going to use these as vars for calculations not sure I need them???
//decimal? DSC = 0;
//decimal? FU = 0;
someClass.Id = lastSomeId;
someClass.OrdNum = item.OrderNumber;
if (item.Code == "LI")
{
someClass.LICode = item.Code;
someClass.LICodeValue = item.NetCharge;
}
if (item.Code == "DT")
{
someClass.DTCode = item.Code;
someClass.DTCodeValue = item.NetCharge
}
if (item.Code == "FU")
{
someClass.FUCode = item.Code;
someClass.FUCodeValue = item.NetCharge;
}
someClass.Total = (someClass.LICodeValue + someClass.FUCodeValue);
//check for other values to calculate
//insert record to DB
}
else
{
//Insert into db after maipulation of values
}
}
}
isRecordBad = false;
}//END Using
Any clues would be greatly appreciated. Thank you in advance.

array entered longer than column

I have a permission form and I want to enter all buttons and MenuStrip to databases.
But when I try to use this function a false message appears
public DataTable loadFormsItemsNameDb(string FormName)
{
var formtype = Assembly.GetExecutingAssembly().GetTypes()
.Where(a => a.BaseType == typeof(Form) && a.GetTypeInfo().Name == FormName)
.FirstOrDefault();
Form f = (Form)Activator.CreateInstance(formtype);
DataTable formsitem = new DataTable();
var ms = f.Controls.OfType<MenuStrip>();
if (ms.Count() > 0)
{
for (int i= 0; i< ms.ElementAt(0).Items.Count; i++)
{
string name = ms.ElementAt(0).Items[i].Name;
string Text = ms.ElementAt(0).Items[i].Text;
string mType = ms.ElementAt(0).Items[i].GetType().ToString();
formsitem.Rows.Add(f.Name, name, Text);
}
}
var BTN = f.Controls.OfType<Button>();
if (BTN.Count() > 0)
{
for (int i = 0; i < BTN.Count(); i++)
{
string name = BTN.ElementAt(i).Name;
string Text = BTN.ElementAt(i).Text;
string mType = BTN.ElementAt(i).GetType().ToString();
formsitem.Rows.Add(f.Name, name, Text, mType);
}
}
return formsitem;
}
After you create a DataTable , you need to define its structure using columns.
for eg.
DataColumn column = new DataColumn();
column.DataType = System.Type.GetType("System.Decimal");
column.AllowDBNull = false;
column.Caption = "Price";
column.ColumnName = "Price";
column.DefaultValue = 25;
table.Columns.Add(column);
and then you can add a row to a table. Here you have not specified the columns for the table.
Form f = (Form)Activator.CreateInstance(formType);
DataTable formsItem = new DataTable();
//************
// Add This Columns Name To Solve Problem ( longer than column )
formsItem.Columns.Add("FIFName");
formsItem.Columns.Add("FIName");
formsItem.Columns.Add("FIText");
formsItem.Columns.Add("FImType");
// *******************
var MS = f.Controls.OfType<MenuStrip>();

C# ClosedXML assign values from cells in a specific row to string

I'm using ClosedXML elsewhere in my script where I'm iterating through every row like this and it works.
var workbook = new XLWorkbook(ObjectRepPath);
var rows = workbook.Worksheet(1).RangeUsed().RowsUsed().Skip(1);
foreach (var row in rows)
{
objPage = row.Cell(1).GetString();
objElement = row.Cell(2).GetString();
if (objPage == page && objElement == element)
{
locType = row.Cell(3).GetString();
locParm = row.Cell(4).GetString();
}
}
After that I need to pull the data from the cells in a randomly selected row. Here's what I've got so far, which is not working...
var workbook = new XLWorkbook(extFile);
var ws = workbook.Worksheets.Add("Cell Values");
var rnd = new Random();
int rowNum = rnd.Next(2, workbook.Worksheet(1).RangeUsed().RowsUsed().Count());
var dataRow = ws.Row(rowNum);
string dangit = dataRow.Cell(1).GetString();
System.Diagnostics.Debug.WriteLine("Why is this dang thing not working... " + dangit);
Output: Why is this damn thing not working...
It just comes back empty. No error. Does anyone see something I don't?
Alright, I found the solution.
I changed the line ...
var ws = workbook.Worksheets.Add("Cell Values");
to ....
var ws = workbook.Worksheet(1);
and now this works ....
Storage.StreetAddress = ws.Cell(xlRow, 1).GetString();

CSV to GridView than CRUD operations

i am making a Job reporter application, and till now what i did is, imported C.S.V file to grid view and displaying it by saving it in a data table, now what i want is,update and save the record back in the c.s.v file, i am not using any S.Q.L or any type of database, is it possible to do this?
please help me, i have to deliver project in two hours.
The project is C# Win forms.
Also help me in how i can serialize it to upload into ftp server.
THE CODE IS here...
private void openProjectToolStripMenuItem_Click_1(object sender, EventArgs e)
{
// int size = -1;
OpenFileDialog ofd = new OpenFileDialog()
{
Title = "Choose a File",
InitialDirectory = #"c:\dev\",
Filter = "Text Files (.txt)|*.txt|XML Files|*.xml|Word Documents (.docx)|*.docx",
RestoreDirectory = true,
Multiselect = false
};
if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
{
MessageBox.Show("No file selected!");
return;
}
using (StreamReader oStreamReader = new StreamReader(ofd.FileName))
{
try
{
Application.DoEvents();
DataSet ds = new DataSet("ApplicationData");
//some updates in the Datatable
DataTable JobHeaderDataTable = new DataTable("JobHeaderDataTable");
DataTable JobDate = new DataTable("JobDate");
DataTable JobDateItems = new DataTable("JobDateItems");
ds.Tables.Add(JobHeaderDataTable);
ds.Tables.Add(JobDate);
ds.Tables.Add(JobDateItems);
int rowCount = 0;
string[] columnNames = null;
string[] oStreamDataValues = null;
while (!oStreamReader.EndOfStream)
{
string oStreamRowData = oStreamReader.ReadLine().Trim();
if (oStreamRowData.Length > 0)
{
oStreamDataValues = oStreamRowData.Split('-');
if (rowCount == 0 && oStreamDataValues[0].ToString() == "HDR")
{
rowCount = 1;
columnNames = oStreamDataValues;
for (int i = 1; i < columnNames.Length; i++)
{
DataColumn oDataColumn = new DataColumn(columnNames[i].ToUpper(), typeof(string));
oDataColumn.DefaultValue = string.Empty;
JobHeaderDataTable.Columns.Add(oDataColumn);
}
//// For Slider
//txtCompany.Text = oStreamDataValues.GetValue(1).ToString();
//txtLocation.Text = oStreamDataValues.GetValue(2).ToString();
//txtRigName.Text = oStreamDataValues.GetValue(3).ToString();
//txtState.Text = oStreamDataValues.GetValue(4).ToString();
//txtCounty.Text = oStreamDataValues.GetValue(5).ToString();
//txtWellName.Text = oStreamDataValues.GetValue(6).ToString();
//txtTownship.Text = oStreamDataValues.GetValue(7).ToString();
//txtDescription.Text = oStreamDataValues.GetValue(8).ToString();
//txtBentHstSub.Text = oStreamDataValues.GetValue(9).ToString();
//txtBilToBend.Text = oStreamDataValues.GetValue(10).ToString();
//txtPadOD.Text = oStreamDataValues.GetValue(11).ToString();
//txtNBStab.Text = oStreamDataValues.GetValue(11).ToString();
//txtJob_ID.Text = oStreamDataValues.GetValue(12).ToString();
//// For Header
//txtCompanyHeader.Text = oStreamDataValues.GetValue(1).ToString();
//txtLocationHeader.Text = oStreamDataValues.GetValue(2).ToString();
//txtRigNameHeader.Text = oStreamDataValues.GetValue(3).ToString();
//txtStateHeader.Text = oStreamDataValues.GetValue(4).ToString();
//txtCountyHeader.Text = oStreamDataValues.GetValue(5).ToString();
//txtWellNameHeader.Text = oStreamDataValues.GetValue(6).ToString();
//txtTownshipHeader.Text = oStreamDataValues.GetValue(7).ToString();
//txtDescriptionHeader.Text = oStreamDataValues.GetValue(8).ToString();
//txtBentHstSubHeader.Text = oStreamDataValues.GetValue(9).ToString();
//txtBillToBendHeader.Text = oStreamDataValues.GetValue(10).ToString();
//txtPadODHeader.Text = oStreamDataValues.GetValue(11).ToString();
//txtNBStabHeader.Text = oStreamDataValues.GetValue(11).ToString();
//txtJob_IDHeader.Text = oStreamDataValues.GetValue(12).ToString();
}
else
{
DataRow oDataRow = JobHeaderDataTable.NewRow();
for (int i = 1; i < columnNames.Length; i++)
{
oDataRow[columnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
JobHeaderDataTable.Rows.Add(oDataRow);
}
}
}
oStreamReader.Close();
oStreamReader.Dispose();
foreach (DataRow dr in JobHeaderDataTable.Rows)
{
dataGridView2.DataSource = JobHeaderDataTable;
dataGridView4.DataSource = JobDate;
dataGridView5.DataSource = JobDateItems;
}
}
catch (IOException)
{
}
}
}
Save yourself some headache and check out, ClosedXML, and create the csv using this answer is available Can I save an EXCEL worksheet as CSV via ClosedXML?.
System.IO.File.WriteAllLines(csvFileName,
worksheet.RowsUsed().Select(row =>
string.Join(";", row.Cells(1, row.LastCellUsed(false).Address.ColumnNumber)
.Select(cell => cell.GetValue<string>()))
));

How I get the index of a DataTable Row with two calues of two other Column Values?

To My Application:
I have two DataTables and I want to filter out the first DataTable to the second. For this I get the columns user and modul from the first DataTable and if it not exist in the second I add a new row.
This is the structure from my second DataTable:
User | Modul | Time | Department | Status
and I want to check two Columns (User and Modul) whether the row with this values in the second DataTable exist. If the Entry Exist I need the row index. How I can do this with Linq?
The name of my second DataTable is analyse_table.
here my code:
private static DataTable FilterDataTable(DataTable nofilter_datatable)
{
DataTable analyse_table = new DataTable("Filter_Analyse");
DataColumn User = new DataColumn("User", typeof(string));
DataColumn Modul = new DataColumn("Modul", typeof(string));
DataColumn TIME = new DataColumn("TIME", typeof(string));
DataColumn Department = new DataColumn("Department", typeof(string));
DataColumn Status = new DataColumn("Status", typeof(string));
analyse_table.Columns.Add(User);
analyse_table.Columns.Add(Modul);
analyse_table.Columns.Add(TIME);
analyse_table.Columns.Add(Department);
analyse_table.Columns.Add(Status);
foreach (DataRow nf_row in nofilter_datatable.Rows)
{
string user = nf_row["User"].ToString();
string modul = nf_row["Modul"].ToString();
string OUT = nf_row["OUT"].ToString();
string IN = nf_row["IN"].ToString();
bool contains_user = analyse_table.AsEnumerable()
.Any(row => user == row.Field<string>("User"));
bool contains_modul = analyse_table.AsEnumerable()
.Any(Row => modul == Row.Field<string>("Modul"));
if (!contains_user || !contains_modul)
{
try
{
DataRow row = analyse_table.NewRow();
row["User"] = user;
row["Modul"] = modul;
if (OUT != string.Empty)
{
row["TIME"] = OUT;
row["Status"] = "OUT";
}
else if (IN != string.Empty)
{
row["TIME"] = IN;
row["Status"] = "IN";
}
string[] userSpli = user.Split('#');
row["Department"] = GetActiveDirectoryAttribute(userSpli[0], "Department", domaincontroller);
analyse_table.Rows.Add(row);
}
catch (Exception)
{
}
}
if (contains_user && contains_modul)
{
//index??
//string status = analyse_table.Rows[0]["Status"].ToString();
}
}
return analyse_table;
}
I need help.
There is no need to know the index in the analyse_table, using FirstOrDefault should allow you to find directly the row required
var rowUser = analyse_table.AsEnumerable()
.FirstOrDefault(row => user == row.Field<string>("User"));
var rowModul = analyse_table.AsEnumerable()
.FirstOrDefault(Row => modul == Row.Field<string>("Modul"));
if (rowUser == null || rowModul == null)
{
// Not exist so I add a new row
}
if (rowUser != null && rowModul != null)
{
string statusUser = rowUser["Status"].ToString();
string statusModul = rowModul["Status"].ToString();
}
However, having executed two different queries to search for your rows, we have no guarantees that the two rows are the same. So perhaps you need to change your code to search for both user and modul in the same row
var rowResult = analyse_table.AsEnumerable()
.FirstOrDefault(row => (user == row.Field<string>("User") &&
modul == row.Field<string>("Modul"));
if(rowResult == null)
// add new
else
// read status
I assume you want to add all missing rows that are in the first table but not in the second, the rows are identified via two columns User + Modul.
You could use a "LEFT OUTER JOIN" to link both tables on an anonymous type containing these columns. This is much more efficient.
var newRowsInFirst = from r1 in first_table.AsEnumerable()
join r2 in analyse_table.AsEnumerable()
on new { User=r1.Field<string>("User"), Modul=r1.Field<string>("Modul") }
equals new { User=r2.Field<string>("User"), Modul=r2.Field<string>("Modul") }
into gj from g2 in gj.DefaultIfEmpty()
where g2 == null
select r1;
Then use a simple foreach-loop to add these rows.
foreach(var newRow in newRowsInFirst)
{
analyse_table.ImportRow(newRow);
// or:
//DataRow addedRow = analyse_table.Rows.Add();
//addedRow.ItemArray = newRow.ItemArray;
}

Categories