How to update Excel PIvot Table data using C# - c#

let me outline my requirement. I have an excel spreadsheet with multiple pivot tables ( linked to charts / slicers etc ) and 2 worksheets with the data that those pivot tables refer to. Currently I have to manually execute a SQL query, copy the data, paste it over the current data in the spreadsheet and then refresh the pivot tables every day.
This is sub-optimal at best. So what I am trying to achieve is some C# code that I can execute on a schedule.
Using EPPlus, I have managed to load the excel file as a template, create a new one, get the data from SQL, update the 2 datasheets with the new data and then save the file.
using (var templateStream = new MemoryStream(File.ReadAllBytes(#"PATH_TO_TEMPLATE_FILE")))
{
using (var newStream = new MemoryStream())
{
//Create e NEW excel doc from the given template
using (ExcelPackage excelPackage = new ExcelPackage(newStream, templateStream))
{
//load the data from SQL
DataSet data = LoadDatasetFromQuery(configs, QueueItem);
//loop over the DataTables inside the DataSet
for (int i = 1; i <= data.Tables.Count; i++)
{
//Resolve the worksheet to put the data on
var worksheetName = configs.FirstOrDefault(c => c.Name.StartsWith($"Worksheet.{i}."));
ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[worksheetName.Value];
//Put the data on the worksheet top/left = B3
worksheet.Cells["B3"].LoadFromDataTable(data.Tables[i - 1], false);
}
//Save the file to the memory stream
excelPackage.Save();
}
//Write the file to the file system
File.WriteAllBytes(#"PATH_TO_OUTPUT_FILE", newStream.ToArray());
}
}
The problem is, when I try and open the excel file, it says it is corrupt and tries to repair it, which is does, by removing the pivot tables completely. My template file makes use of named ranges as referred to in this SO post but that has not resolved the issue.
Herewith the excel log of how it completed the "repair"
I have also dabbled a little bit in using the interop library ( Microsoft.Office.Interop.Excel ) but that is really like a black hole when it comes to debugging / documentation etc. I'm not averse to using it, I just don't know how. ( well nothing I have tried works properly anyways )
Any help with the above will be greatly appreciated. If you need more information, feel free to ask.

Ok, so it seems my above code was correct, but the excel template I was loading was dodgy. In order to correct the issue I had to make sure that all the pivot tables used named ranges to refer to the data ( click anywhere on the pivot table, then click on the Formulas tab in the top ribbon and then click on Name Manager ) source and then use the offset calculation ( to enable a dynamic range ) as suggested in the link in my post above.
=OFFSET(DataSource!$A$1,0,0,COUNTA(DataSource!$A:$A),COUNTA(DataSource!$1:$1))
where DataSource = the name of the worksheet with the data
Finally, I set up the pivots to refresh their data on opening ( right click on the pivot table, go to data tab and tick the "refresh on open" option )
There is a bit of a pain in that when I open the generated doc it is in "Protected mode" so the data + calcs dont refresh, but if I just click "Enable Editing" it all updates and normal service is resumed, happy days!

Related

How do create and make user download an Excel file from variable data in arrays?

I'm working on a project in .NET Core 1.1, and now I have to give the possibility to the user of downloading an Excel file which data is dependant on parameters chosen by the user, so the Excel should be created in the moment when the user clicks the "Export to Excel" button and downloaded.
I've been searching on the internet but I haven't gotten any clear answers to be honest. I guess I will have to use the Open XML SDK, but in order to create it in memory and such, I don't have enough knowledge.
To sum up, I have data in arrays, and I would like to be able, in the moment the user clicks a button, create the excel virtually with the data previously stored in arrays and then download it in the users browser.
Do you also want to show your data before download? Maybe you can use DataTables:
DataTables is a plug-in for the jQuery Javascript library. It is a
highly flexible tool, built upon the foundations of progressive
enhancement, that adds all of these advanced features to any HTML
table.
Pagination Previous, next and page navigation. Instant search Filter
results by text search.
using NPOI https://github.com/tonyqus/npoi
something in the line of this:
void safearrayAsExcel(object[,] rows,string filename){
var workbook = new HSSFWorkbook();
var sheet = workbook.CreateSheet("New Sheet");
for(int i = 0; i < rows.length;i++)
{
var row sheet.CreateRow(i);
for(int j = 0; j < row.length;j++)
row .CreateCell(j).SetCellValue(rows[i,j]);
}
FileStream fileOut = new FileStream(fileName, FileMode.Create);
workbook.Write(fileOut);
}
you can ofcourse use a memorystream instead of filestream and do whatever you want with the generated excel
use HSSFWorkbook for xls format. and XSSFWorkbook for xlsx format.
i dont completely know about compatibliy issues with .net core 1.1 and .net standard 2.0 but there should be a way go get it work

How to directly embed an excel chart from memory onto a powerpoint slide?

I have a VSTO addin that receives an excel chart (in byte array) over a network from a server. I would like to paste this chart onto a powerpoint slide programmatically without having to save the chart to disk first.
However, when I look through all the .Add* methods exposed by Microsoft.Office.Interop.PowerPoint.Shapes, they all seem to require a file path in string . In other words, I would have to convert the binary data to a file in a supported format on the system and get its path before I can use those functions.
Are there any way to directly use this binary data and paste it on the powerpoint slide without having to save it as a file on the system first?
using Microsoft.Office.Interop.Excel;
void CreateChart()
{
ChartData gChartData;
Workbook gWorkBook;
Worksheet gWorkSheet;
// Create the chart and set a reference to the chart data.
var myChart = ActivePresentation.Slides[1].Shapes.AddChart() as Microsoft.Office.Interop.PowerPoint.Chart;
gChartData = myChart.ChartData;
// Set the Workbook and Worksheet references.
gWorkBook = gChartData.Workbook;
gWorkSheet = gWorkBook.Worksheets[1];
// Add the data to the workbook.
gWorkSheet.ListObjects["Table1"].Resize(gWorkSheet.Range["A1:B5"]);
gWorkSheet.Range["Table1[[#Headers],[Series 1]]"].Value = "Items";
gWorkSheet.Range["a2"].Value = "Coffee";
gWorkSheet.Range["a3"].Value = "Soda";
gWorkSheet.Range["a4"].Value = "Tea";
gWorkSheet.Range["a5"].Value = "Water";
gWorkSheet.Range["b2"].Value = "1000";
gWorkSheet.Range["b3"].Value = "2500";
gWorkSheet.Range["b4"].Value = "4000";
gWorkSheet.Range["b5"].Value = "3000";
//ToDo: Style
}
fill the data as you like (you may fill it with a for loop and fill the $"a{i}" column with the number of the entry (i))
See this Article for further Information
UPDATE 21.04.2021:
This isn't what the OP asked for.
In his comment he said:
Even if it is in a text format, I would still have trouble pasting it directly onto the slide because all the methods to embed onto PowerPoint slide exposed by Microsoft.Office.Interop.PowerPoint.Shapes only accept the path of the file in string-not the file itself-as its parameter to access the required file... if I'm not mistaken.
This is not correct. I pointed out a way to create charts programmatically without having to create an excel sheet an save it somewhere.
If you would have gotten the data in a defined format (e.g. json) you could use my code to generate the chart.
But now what you seem to be waiting for:
If you click copy with and excel-chart selected, then open your PowerPoint presentation, set your selection where your want the chart to be and paste the chart, it will be inserted there no problem.
But how can I sent this Data and then paste it?
The Excel-Chart has got a method to copy itself:
https://learn.microsoft.com/de-de/office/vba/api/excel.chart(object)
Convert the data in your clipboard to binary data
Send the data
Convert the data back and store it in your clipboard
Use the TextRange of your Powerpoint-Selection to paste the data
https://learn.microsoft.com/de-de/office/vba/api/powerpoint.textrange

EPPlus with OpenXML and streams

I am trying to automate a Powerpoint presentation. I am using OpenXML to navigate the powerpoint presentation up to the point that I find the Excel linked to a chart. Now I want to use EPPlus to load a datatable into one of the worksheets (because EPPlus has a simple LoadFromDataTable function whereas I think I would have to write lots of code to use OpenXML).
So my problem is this.
I have a PresentationDocument in memory. And I have navigated to the particular chart that I want to manipulate via:
doc.PresentationPart.SlideParts.ElementAt(0).ChartParts.ElementAt(0)
I get the Excel part using:
var stream = chartpart.EmbeddedPackagePart.GetStream()
Then I tried:
using(var pck = new ExcelPackage(stream)) {
`do stuff;
`pck.Save();
}
and then at the end I do a doc.PresentationPart.Presentation.Save but this hasn't changed the Presentation. I can change it using OpenXML instead with:
using (var xl = Spreadsheet.Document.Open(stream, true))
{
`do stuff;
`xl.Close();
}
With everything else the same. So I guess either xl.Close() is doing stuff that pck.Save() isn't or I am using the stream incorrectly - can anyone advise?

C# EPPlus delete row from excel sheet

I'm currently working with an Excel file that has leading rows that have information I don't need. These extra rows also mess with importing that data in the header row below. So I'm trying to remove them to work with the data.
using (var pack = new ExcelPackage(myFileInfo))
{
// Should return the sheet name
var ws = pack.Workbook.Worksheets.FirstOrDefault();
// Should Delete rows 1-5 and shift up the rows after deletion
ws.DeleteRow(1,5,true);
}
I was thinking something like the above would work, but I've not had much success with it.
The goal would be to delete rows 1-5, shift up the rest of the data (maybe a merge would work?) then convert it into a datatable.
Anyone have tips tips or resources on removing rows from my excel sheet (prior to moving it into a datatable since that is where the issue occurs)
The code as you have it will remove the first 5 rows but you also need to do something with the amended file. You could save it in place with:
pack.Save();
or save to a new location with:
pack.SaveAs(new FileInfo(outputFilePath));
I have uploaded a complete example here:
static void Main(string[] args)
{
var myFileInfo = new FileInfo("Demo.xlsx");
using (var pack = new ExcelPackage(myFileInfo))
{
var ws = pack.Workbook.Worksheets.FirstOrDefault();
ws.DeleteRow(1, 5, true);
pack.SaveAs(new FileInfo("output.xlsx"));
}
}
If you build and run the solution you can see that it transforms the demo file from this in the input file (Demo.xlsx):
to this in the output file:
with the first 5 rows removed and everything shifted up.

Epplus, Out of memory

Sorry for my English. I used the library Epplus and I really like it. But I've got a problem: Out of Memory. Need to write large amounts of data, no matter what. I want to know is it possible to append to the end of the Excel file is not stored in the memory of all. Or create multiple files and then concatenate into one file. Thanks in advance.
1)if you retrieve your data from database
use a datareader instead of datatable
2)write the excel to a temp file, delete it after done(if it's web environment, use response.writefile then delete it)
3)write the header first then append data to it
something like this (using my phone to type this)
var pck = new ExcelPackage();
var ws = pck.AddSheet("sheet1");
//write header here
pck.saveas(fileinfo);
pck.dispose(); // not sure if function existed
pck= new excelpage(fileino.fullname);
ws = pck.worksheets[1];
var rowIndex =0;
while (reader.read())
{
if (++rowindex % 100000 == 0)
{
// save and re-open
}
//write row here
}
pck.save();
//dispose / send file / delete file etc

Categories

Resources