EPPlus - join string with named cell - c#

I need to create an Excel file in which the user can later adjust a specific information. I'm using C# and EPPlus v6.0.4. For example, if the input is a list of products, I want it to be joined with ' taxes included' string (which can be later changed by the user at Excel):
descriptionA -> descriptionA taxes included
descriptionB -> descriptionB taxes included
descriptionC -> descriptionC taxes included
I'm assuming two worksheets: ws1 (parameter) and ws2 (output list). As shown below, cell B1 is where the user will be able to change the "taxes included" string.
ws1.Cells["A1"].Value = "Additional information:";
excel.Workbook.Names.Add("auxData", ws1.Cells["B1"]);
ws1.Cells["B1"].Value = " taxes included 12%";
At the second worksheet (ws2) I will have the data being populated.
int excelLine = 1;
foreach (var product in productList)
{
string productDescription = product.Description;
ws2.Cells["A" + excelLine].Formula = .....; //need ideas on how to solve this
excelLine ++;
}
At the above .Formula I was trying CONCAT or similar function but its not working (excel file is generated with errors or the formula is not accepted).
The expected output is a cell value ="product full description variable string" & auxData, therefore suitable to B1 text changes by the user (auxData is an Excel name to =ws1!$B$1).

My own solution was:
int excelLine = 1;
foreach (var product in productList)
{
string cellDescription = "=\"" + product.Description + " -- additional information \" & auxData & \"%\"";
ws2.Cells["A" + excelLine].Formula = cellDescription;
excelLine ++;
}

Related

Update a table column by matching the column name to a string

I have a table with many columns and I need to update the column that matches a set of parameters. Is it possible to concatenate a string and then use the string result to update a matching named column of a database using Telerik's OpenAccess? If so, I'm thinking reflection is required here? I would like to be able to do something like shown below:
A simplified example table:
Sku QtyOnHand Whse1Aug2017 Whse2Aug2017 Whse3Aug2017
==================================================================
ABC-123 87 2 4 8
XYZ-789 43 0 5 4
string warehouseId = "1"
string month = "Aug"
string year = "2017"
string sku = "ABC-123"
int qtySold = 3;
string columnName = "Whse" + warehouseId + month + year;
var query = (from s in model.Sales
where s.SKU == sku
select s).FirstOrDefault();
query.columnName = query.columnName + qtySold;
query.SaveChanges();
You can use Reflection for this. Eg
void UpdateProperty(object targetObject, string propertyName, object value)
{
var pi = targetObject.GetType().GetProperty(propertyName);
pi.SetValue(targetObject, value);
}
The Reflection would do it but is a bit expensive.
Telerik Data Access does this out of the box. Check the API for setting and getting values from artificial types/fields. See the section "Setting and Getting Artificial Properties/Fields":
http://docs.telerik.com/data-access/feature-reference/api/context-api/feature-ref-api-context-api-artificial-data-api
here is an example how it works:
category.SetFieldValue( "CategoryName", "MyCategory" );
category.SetFieldValue( "Description", "New Description" );

Scanning my table c# mysql

So i'm making a library system, and i encounter a problem in my Borrowing and Returning of books.
When i borrow a book then return it changing the status to return, then borrowing that same book again success, then when i'm returning it my trapping for return books message show.
sql = "SELECT * FROM tbltransactionbooks WHERE fBarCodeNo LIKE '" + txtBARCODE_R.Text.Trim() + "%'";
cfgotcall.engageQuery(sql);
if (cfgotcall.tbl.Rows[0]["fStatus"].ToString().Equals("Borrowed"))
{
txtTITLE_R.Text = cfgotcall.tbl.Rows[0]["fBookTitle"].ToString();
txtAUTHOR_R.Text = cfgotcall.tbl.Rows[0]["fAuthor"].ToString();
txtYEAR_R.Text = cfgotcall.tbl.Rows[0]["fBookYr"].ToString();
txtACCNO_R.Text = cfgotcall.tbl.Rows[0]["fAccNo"].ToString();
txtCALLNO_R.Text = cfgotcall.tbl.Rows[0]["fCallNo"].ToString();
txtBARCODE_BR.Text = cfgotcall.tbl.Rows[0]["fBarcodeNo"].ToString();
txtSEARCH.Text = cfgotcall.tbl.Rows[0]["fStudent"].ToString();
txtReturnDate.Text = cfgotcall.tbl.Rows[0]["fBorrowDate"].ToString();
txtIDNO.Text = cfgotcall.tbl.Rows[0]["fIDStudent"].ToString();
txtLEVEL.Text = cfgotcall.tbl.Rows[0]["fLevel"].ToString();
}
else
{
MessageBox.Show("Book already returned.");
}
What i debug in my own code in the pic is it doesn't scan the whole rows in the tbltransactionbooks it only reads the first row of my table.
33 123 NAME IT 2/20/2017 2/20/2017 [HISTORY OF] COMPUTERS: THE MACHINES WE THINK WITH Returned
33 123 NAME IT 2/21/2017 2/21/2017 [HISTORY OF] COMPUTERS: THE MACHINES WE THINK WITH Borrowed
![2]: http://i66.tinypic.com/28ajgwg.jpg
How dow I scan the whole rows in my table? If my code above does not look good I'm open in suggestion of how I am able make it clean. thanks
cfgotcall.tbl.Rows[0] refers to the the first row only.
You should iterate each row:
sql = "SELECT * FROM tbltransactionbooks WHERE fBarCodeNo LIKE '" + txtBARCODE_R.Text.Trim() + "%'";
cfgotcall.engageQuery(sql);
foreach(var row in cfgotcall.tbl.Rows)
{
if (row["fStatus"].ToString().Equals("Borrowed"))
{
txtTITLE_R.Text = row["fBookTitle"].ToString();
txtAUTHOR_R.Text = row["fAuthor"].ToString();
txtYEAR_R.Text = row["fBookYr"].ToString();
txtACCNO_R.Text = row["fAccNo"].ToString();
txtCALLNO_R.Text = row["fCallNo"].ToString();
txtBARCODE_BR.Text = row["fBarcodeNo"].ToString();
txtSEARCH.Text = row["fStudent"].ToString();
txtReturnDate.Text = row["fBorrowDate"].ToString();
txtIDNO.Text = row["fIDStudent"].ToString();
txtLEVEL.Text = row["fLevel"].ToString();
}
else
{
MessageBox.Show("Book already returned.");
}
}
To avoid getting run time errors due to typos in the column names and the SQL query, you can use LINQ to SQL or Entity Framework. This way each row is converted to an object and you can access each column by accessing an object property\field.
The first row is checked because use access only the first row:
if (cfgotcall.tbl.Rows[0]...)
To check all the rows, iterate through the cfgotcall.tbl.Rows collection either using the for or foreach loop.
You are only accessing the first row [0] of the table. You need to itterate through all of them using for or foreach loop.
Side note: I guess this is a homework. It will not do you any good if you find complete solution in the internet. You should rather try to understand how collections/arrays work and how to traverse them using loops.
A couple of tutorials to help you with the task:
https://msdn.microsoft.com/en-us/library/aa288462(v=vs.71).aspx
http://csharp.net-informations.com/collection/csharp-collection-tutorial.htm

ORA-01843: not a valid month - issue on second pc

On my pc (Win7) the statement is running without error. If I copy the c# .exe to a server (Win2012 server) where the program should finally run then I get the error
ORA-01843: not a valid month
I read a csv-file and insert it into a oracle-db with the statement
command.CommandText = "INSERT INTO table (DATUM, ...) VALUES('" + dr[0].ToString() + "',..."')";
dr[0].ToString() has the value "01.06.2016"
The column DATUM is type DATE in the oracle-db.
I debugged the code with a messagebox and get this result:
I can't see any difference between those two statements, the left one from the server is calling the error when I execute int rowsupdated = command.ExecuteNonQuery();
I already compared the region settings and they are the same (german) on both systems. What else could cause the problem? Thanks
Part for filling the Datatable (source for dr):
StreamReader oStreamReader = new StreamReader(Zielverzeichnis + Dateiname, System.Text.Encoding.UTF8); //nach, für Umlaute
DataTable dtCSV_Import = null;
int RowCount = 0;
string[] ColumnNames = null;
string[] oStreamDataValues = null;
//using while loop read the stream data till end
while (!oStreamReader.EndOfStream)
{
String oStreamRowData = oStreamReader.ReadLine().Trim();
if (oStreamRowData.Length > 0)
{
oStreamDataValues = oStreamRowData.Split(';');
//Bcoz the first row contains column names, we will poluate
//the column name by
//reading the first row and RowCount-0 will be true only once
if (RowCount == 0)
{
RowCount = 1;
ColumnNames = oStreamRowData.Split(';');
dtCSV_Import = new DataTable();
//using foreach looping through all the column names
foreach (string csvcolumn in ColumnNames)
{
DataColumn oDataColumn = new DataColumn(csvcolumn.ToUpper(), typeof(string));
//setting the default value of empty.string to newly created column
oDataColumn.DefaultValue = string.Empty;
//adding the newly created column to the table
dtCSV_Import.Columns.Add(oDataColumn);
}
}
else
{
//creates a new DataRow with the same schema as of the oDataTable
DataRow oDataRow = dtCSV_Import.NewRow();
//using foreach looping through all the column names
//Prüfen was kleiner ist, Spalten aus XML oder tatsächliche Spalten in der CSV -> sonst Fehler [i]
if (oStreamDataValues.Length < ColumnNames.Length)
{
for (int i = 0; i < oStreamDataValues.Length; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
}
else
{
for (int i = 0; i < ColumnNames.Length; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
}
//adding the newly created row with data to the oDataTable
dtCSV_Import.Rows.Add(oDataRow);
}
}
}
//close the oStreamReader object
oStreamReader.Close();
//release all the resources used by the oStreamReader object
oStreamReader.Dispose();
If you are inserting values into a date column and try to insert a string value then Oracle will implicitly call TO_DATE() using the NLS_DATE_FORMAT session parameter as the format mask. If this format mask does not match then you will get an exception.
Session parameters can be set by individual users within their sessions - so if user Alice has the expected parameters this does not mean that user Bob will have the same parameters and the identical query you are using will not work as you are relying on implicitly casting values. Or even worse, Bob has the expected parameters today and then tomorrow decided that he would prefer his dates formatted as DD-MON-YYYY and changes his NLS_DATE_FORMAT and suddenly, without changing your code, everything breaks and you are going to have a very bad time debugging the error.
If you want to insert a date then either:
Pass it as a bind variable (the best option) without converting it to a string; or
Use date literals (i.e. DATE '2016-06-01'); or
Use TO_DATE() with a specified format mask (i.e. TO_DATE( '" + dr[0].ToString() + "', 'DD.MM.YYYY' )).
You can read about bind variables in the Oracle Documentation or in this SO question.

Column missing from excel spreedshet

I have a list of invoices that and I transferred them to an Excel spreadsheet.
All the columns are created into the spreadsheet except for the Job Date column. That is blank in the spreadsheet.
Here's the code:
string Directory = ConfigurationSettings.AppSettings["DownloadDestination"] + Company.Current.CompCode + "\\";
string FileName = DataUtils.CreateDefaultExcelFile(Company.Current.CompanyID, txtInvoiceID.Value, Directory);
FileInfo file = new FileInfo(FileName);
Response.Clear();
Response.ContentType = "application/x-download";
Response.AddHeader("Content-Length", file.Length.ToString());
Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
Response.CacheControl = "public";
Response.TransmitFile(file.FullName);
Response.Flush();
Context.ApplicationInstance.CompleteRequest();
public static string CreateDefaultExcelFile(int CompanyID, string InvoiceNo, string CreateDirectory)
{
List<MySqlParameter> param = new List<MySqlParameter>{
{ new MySqlParameter("CompanyID", CompanyID) },
{ new MySqlParameter("InvoiceNo", InvoiceNo) }
};
DataTable result = BaseDisplaySet.CustomFill(BaseSQL, param);
string FileName = CreateDirectory + "InvoiceFile_" + DateTime.Now.ToString("yyyyMMddhhmmssff") + ".";
FileName += "xlsx";
XLWorkbook workbook = new XLWorkbook();
workbook.Worksheets.Add(result, "Bulk Invoices");
workbook.SaveAs(FileName);
return FileName;
}
private const string BaseSQL = " SELECT q.InvoiceNo AS InvoiceNumber, j.JobNo, j.JobDate AS JobDate, " +
" (SELECT Name FROM job_address WHERE AddressType = 6 AND JobID = j.ID LIMIT 0,1) AS DebtorName, " +
" (SELECT CONCAT(Name,CONCAT(',',Town)) FROM job_address WHERE AddressType = 3 AND JobID = j.ID LIMIT 0,1) AS CollectFrom, " +
" (SELECT CONCAT(Name,CONCAT(',',Town)) FROM job_address WHERE AddressType = 2 AND JobID = j.ID LIMIT 0,1) AS DeliverTo, " +
" deladd.Town AS DeliverToTown, deladd.County AS DeliveryToCounty, " +
" (SELECT DocketNo FROM job_dockets WHERE JobID = j.ID LIMIT 0,1) AS DocketNo, " +
" SUM(j.DelAmt) AS DelAmount, " +
" (SELECT CAST(group_concat(DISTINCT CONCAT(AdvisedQty,' ',PieceType) separator ',') AS CHAR(200)) FROM job_pieces WHERE JobID = j.ID GROUP BY JobID ) AS PieceBreakDown " +
" FROM Invoice q " +
" LEFT JOIN customer c ON q.accountcode = c.ID " +
" INNER JOIN job_new j ON q.JobID = j.ID " +
" LEFT JOIN job_address coladd ON coladd.JobID = j.ID AND coladd.AddressType = 3 " +
" LEFT JOIN job_address deladd ON deladd.JobID = j.ID AND deladd.AddressType = 2 " +
" WHERE q.IsActive = 1 AND q.Company_ID = ?CompanyID AND q.InvoiceNo = ?InvoiceNo " +
" group by j.id";
The sql returns all the correct information and as you can see the job date is there:
But when I open the Excel file after it is created, the job date column is blank:
You should convert JobDate in BaseSQL to string.
A sample example is given below. You can use it to get an idea how to convert datetime to varchar.
DECLARE #myDateTime DATETIME
SET #myDateTime = '2008-05-03'
--
-- Convert string
--
SELECT LEFT(CONVERT(VARCHAR, #myDateTime, 120), 10)
I don't know what framework do you use to export data to excel and how powerful it is, but I do know that Excel does not directly support dates (surprise!), at least not in xml-based (OpenXml) xlsx documents. It works only with strings and numbers (which are saved in underlying document as string and number literals)
Considering that, you can use simple workaround: convert your dates to strings via either cast/convert in sql or ToString() in C#. You will loose Excel date functionality (like date filters, custom formats), obviously.
However, it is not an only way (cheers!). You can save your data in the same way Excel stores it. If your framework does not support it, you will have to do it yourself: the recipe will be the same as with creation xlsx documents by hand with DocumentFormat.OpenXml.dll.
Actually, Excel uses "OLE-Automation Date" format as internal representation for dates, which is implemented as a floating-point number whose integral component is the number of days before or after midnight, 30 December 1899, and whose fractional component represents the time on that day divided by 24. This representation is stored in document as number literal. Excel distinguishes dates and numbers by numbering format of corresponding cell. With that in mind, you can use not so simple workaround:
First, convert your dates to numbers:
DateTime date = DateTime.Now;
double dateValue = date.ToOADate();
//or
TimeSpan time = DateTime.Now.TimeOfDay;
double timeValue = (DateTime.FromOADate(0) + time).ToOADate();
Then double variable should be set to CellValue of Excel Cell, you can create new column with double datatype in DataTable, fill it using this transformation, then drop original DateTime column.
Second, apply date format to desired cells. Unfortunately, required code will differ between frameworks, but the principle should be the same:
Locate corresponding cell range (either CellRange or Cells, maybe Columns)
Set date format string (via something like range.NumberFormat.Format="dd/mm/yyyy" or range.NumberFormatString="dd/mm/yyyy")
If, however, this framework does not support simplified formatting (very strange framework that will be), you will have to either set range.NumberFormatId=22 for standard date format or create new number format. If you are rather unlucky and this framework is as simple as DocumentFormat.OpenXml, you will have to create custom CellFormat with correspoding NumberFormatId (22 or id of custom NumberFormat), add it to stylesheet and set styleIndex for corresponding range.
I don't know if it's worth checking out, but when working with large datasets and datatables in the past I usually use ClosedXML to get it done. It's easy to just pass a datatable and let it handle creating the XLSX for it. I have it running my my Windows Server 2008 r2 without issue handling large requests with multiple sheets so I know it works really well.
https://closedxml.codeplex.com/

Get the list numbers from Word document?

I'm using Microsoft.Office.Interop.Word to parse a Word 2010 document. I'm grabbing all the text from every cell in the first column of every table on every page. The problem I'm having, though, is that when I get the text, it's not including the list numbers. For example, the text in my table looks like this:
My program loops through the document and grabs the text from every cell in the first column. Instead of getting "1. Introduction", though, I'm getting "Introduction". Here's what the data looks like that I'm getting:
As you can see, I'm not getting the list numbers, just the text (i.e. "Introduction" instead of "1. Introduction").
Here's the loop I'm using to get the data:
// Loop through each table in the document,
// grab only text from cells in the first column
// in each table.
foreach (Table tb in docs.Tables)
{
for (int row = 1; row <= tb.Rows.Count; row++)
{
var cell = tb.Cell(row, 1);
var text = cell.Range.Text;
dt.Rows.Add(text);
}
}
Can someone offer any pointers on how to grab the list numbers from each cell, as well as the text? I imagine it will be something like this:
var text = cell.Range.ListNumber + " " + cell.Range.Text;
...but I can't figure it out, exactly.
Found the answer. I had to get the ListString value:
// Loop through each table in the document,
// grab only text from cells in the first column
// in each table.
foreach (Table tb in docs.Tables)
{
for (int row = 1; row <= tb.Rows.Count; row++)
{
var cell = tb.Cell(row, 1);
var listNumber = cell.Range.ListFormat.ListString;
var text = listNumber + " " + cell.Range.Text;
dt.Rows.Add(text);
}
}

Categories

Resources