2015-07-15 11 views
15

Próbuję wyeksportować niektóre dane do arkusza Excela S1, którego dane będą wyświetlane jako widoki przestawne w następnych dwóch arkuszach S2 and S3. Jestem w stanie stworzyć pojedynczy pivot i działa idealnie. Ale kiedy tworzę dwa pivots, wynikowy plik programu Excel jest uszkodzony.ClosedXML - Tworzenie wielu tabel przestawnych

przez skorumpowanych Znaczy,

Po kliknięciu tak, ja się tym -

Corrupt

Oto kod używam do tworzenia czopami -

using XL = ClosedXML.Excel; 
... 
XL.XLWorkbook wb = new XL.XLWorkbook(); 
dsData = Session["ExportData"] as DataSet; 

var sheet1 = wb.Worksheets.Add("output table"); 
sheet1.Cell(1, 1).InsertTable(dsData.Tables[0], "output table", true); 

// sheet1 is the reference sheet S1 
var dataRange = sheet1.RangeUsed(); 

// First Pivot 
XL.IXLWorksheet ptSheet1 = wb.Worksheets.Add("S2"); 

var pt1 = ptSheet1.PivotTables.AddNew("PivotTable1", ptSheet.Cell(3, 1), dataRange); 


pt1.ReportFilters.Add("CX"); 

pt1.RowLabels.Add("C1"); 
pt1.RowLabels.Add("C2"); 
pt1.RowLabels.Add("C3"); 
pt1.RowLabels.Add("C4"); 

pt1.ColumnLabels.Add("CL1"); 
pt1.ColumnLabels.Add("CL2"); 
pt1.ColumnLabels.Add("CL3"); 

pt1.Values.Add("V").SummaryFormula = XL.XLPivotSummary.Sum; 


// Second Pivot 
XL.IXLWorksheet ptSheet2 = wb.Worksheets.Add("S3"); 

var pt2 = ptSheet2.PivotTables.AddNew("PivotTable2", ptSheet1.Cell(3, 1), dataRange); 

pt2.ReportFilters.Add("QQ"); 

pt2.RowLabels.Add("C1"); 
pt2.RowLabels.Add("C2"); 

pt2.ColumnLabels.Add("CL1"); 
pt2.ColumnLabels.Add("CL2"); 
pt2.ColumnLabels.Add("CL3"); 

pt2.Values.Add("V").SummaryFormula = XL.XLPivotSummary.Sum; 

C1, C2, C3. C4 and V są nazwami kolumn w moim arkuszu referencyjnym S1.

+1

co masz na myśli mówiąc, że jest uszkodzony? pojawił się błąd? proszę pokazać nam cały kod do wywozu – jomsk1e

+0

@ jomsk1e Mam zaktualizowane pytanie, proszę sprawdzić. –

+1

Mam dokładnie ten sam problem. . czy kiedykolwiek wymyśliłeś rozwiązanie lub obejście? – leora

Odpowiedz

11

Problem jest spowodowany przez błąd implementacji ClosedXML.

może być łatwo powielane przy użyciu następującego fragmentu (zmodyfikowana wersja ich przykład Tabele) i otwarcia pliku wynikowego w Excelu:

static void CreateTestPivotTables(string filePath) 
{ 
    var wb = new XLWorkbook(); 

    var wsData = wb.Worksheets.Add("Data");    
    wsData.Cell("A1").Value = "Category"; 
    wsData.Cell("A2").Value = "A"; 
    wsData.Cell("A3").Value = "B"; 
    wsData.Cell("A4").Value = "B"; 
    wsData.Cell("B1").Value = "Number"; 
    wsData.Cell("B2").Value = 100; 
    wsData.Cell("B3").Value = 150; 
    wsData.Cell("B4").Value = 75; 
    var source = wsData.Range("A1:B4"); 

    for (int i = 1; i <= 2; i++) 
    { 
     var name = "PT" + i; 
     var wsPT = wb.Worksheets.Add(name); 
     var pt = wsPT.PivotTables.AddNew(name, wsPT.Cell("A1"), source); 
     pt.RowLabels.Add("Category"); 
     pt.Values.Add("Number") 
      .ShowAsPctFrom("Category").And("A") 
      .NumberFormat.Format = "0%"; 
    } 

    wb.SaveAs(filePath); 
} 

błędów jest umieszczony w XLWorkbook_Save.cs - GeneratePivotTables Metoda:

private static void GeneratePivotTables(WorkbookPart workbookPart, WorksheetPart worksheetPart, 
    XLWorksheet xlWorksheet, 
    SaveContext context) 
{ 
    foreach (var pt in xlWorksheet.PivotTables) 
    { 
     var ptCdp = context.RelIdGenerator.GetNext(RelType.Workbook); 

     var pivotTableCacheDefinitionPart = workbookPart.AddNewPart<PivotTableCacheDefinitionPart>(ptCdp); 
     GeneratePivotTableCacheDefinitionPartContent(pivotTableCacheDefinitionPart, pt); 

     var pivotCaches = new PivotCaches(); 
     var pivotCache = new PivotCache {CacheId = 0U, Id = ptCdp}; 

     pivotCaches.AppendChild(pivotCache); 

     workbookPart.Workbook.AppendChild(pivotCaches); 

     var pivotTablePart = 
      worksheetPart.AddNewPart<PivotTablePart>(context.RelIdGenerator.GetNext(RelType.Workbook)); 
     GeneratePivotTablePartContent(pivotTablePart, pt); 

     pivotTablePart.AddPart(pivotTableCacheDefinitionPart, context.RelIdGenerator.GetNext(RelType.Workbook)); 
    } 
} 

linią workbookPart.Workbook.AppendChild(pivotCaches); która dodaje wielokrotność PivotCaches do workbookPart.Workbook podczas gdy wolno zawierać 0 lub 1.

Z powiedział, że jest to jedyny sposób, aby to naprawić jest wewnątrz kodu źródłowego poprzez modyfikację powyższej metody w następujący sposób:

private static void GeneratePivotTables(WorkbookPart workbookPart, WorksheetPart worksheetPart, 
    XLWorksheet xlWorksheet, 
    SaveContext context) 
{ 
    var pivotCaches = workbookPart.Workbook.GetFirstChild<PivotCaches>(); 
    foreach (var pt in xlWorksheet.PivotTables) 
    { 
     var ptCdp = context.RelIdGenerator.GetNext(RelType.Workbook); 

     var pivotTableCacheDefinitionPart = workbookPart.AddNewPart<PivotTableCacheDefinitionPart>(ptCdp); 
     GeneratePivotTableCacheDefinitionPartContent(pivotTableCacheDefinitionPart, pt); 

     if (pivotCaches == null) 
      workbookPart.Workbook.AppendChild(pivotCaches = new PivotCaches()); 
     var pivotCache = new PivotCache { CacheId = (uint)pivotCaches.Count(), Id = ptCdp }; 
     pivotCaches.AppendChild(pivotCache); 

     var pivotTablePart = 
      worksheetPart.AddNewPart<PivotTablePart>(context.RelIdGenerator.GetNext(RelType.Workbook)); 
     GeneratePivotTablePartContent(pivotTablePart, pt); 
     pivotTablePart.PivotTableDefinition.CacheId = pivotCache.CacheId; 

     pivotTablePart.AddPart(pivotTableCacheDefinitionPart, context.RelIdGenerator.GetNext(RelType.Workbook)); 
    } 
} 

Aktualizacja: Dobrą wiadomością jest to, że mój post wywołał ClosedXML source repository fix przez Francois Botha (także kredyty do petelids, którzy go tam przenieśli), więc możesz zabrać kod stamtąd aż do następnego wydania, które - mam nadzieję - uwzględni to.

+0

Jako opiekun pakietu, chciałbym, aby ludzie mogli zgłaszać poprawki jako żądania ściągnięcia. http: // github.com/ClosedXML/ClosedXML –

+0

@FrancoisBotha Pewnie, pracowałem wczoraj nad pytaniami i nie mam czasu na wniesienie wkładu (ma pewne dodatkowe wymagania, jak myślę, a nie jak po prostu wyrzucenie fragmentu kodu), a następnie wydaje się, że petelidy użytkownika już to zrobił. –

+1

@IvanStoev - Zrobiłem to, ale rzuciłem się i zrobiłem z tego odrobinę haszyszu. Usunąłem odpowiedź, ponieważ nie dodawałem żadnej wartości (i zamiast tego wznowiłem twoje). FrancoisBotha stworzył lepszą poprawkę. – petelids

2

Wypróbuj tę modyfikację. Zrobiłem notatkę, w której dodałem dodatkową linię. Ponadto, myślę, że metoda AddNew() mogła mieć niewłaściwe odniesienie do arkusza roboczego? Być może próbujesz dodać tabelę przestawną nad drugą. To mogła być raczej kwestia niż dodatkowa linia, którą dodałem.

using XL = ClosedXML.Excel; 
... 
XL.XLWorkbook wb = new XL.XLWorkbook(); 
dsData = Session["ExportData"] as DataSet; 
var sheet1 = wb.Worksheets.Add("output table"); 
sheet1.Cell(1, 1).InsertTable(dsData.Tables[0], "output table", true); 

// sheet1 is the reference sheet S1 
var dataRange = sheet1.RangeUsed(); 
PivotCache cache = wb.PivotCaches.Add(dataRange); //---THIS LINE HAS BEEN ADDED--- 

// First Pivot 
XL.IXLWorksheet ptSheet1 = wb.Worksheets.Add("S2"); 
var pt1 = ptSheet1.PivotTables.AddNew("PivotTable1", ptSheet1.Cell(3, 1), cache); 
//Changed ptSheet.Cell... to ptSheet1.Cell... 
pt1.ReportFilters.Add("CX"); 
pt1.RowLabels.Add("C1"); 
pt1.RowLabels.Add("C2"); 
pt1.RowLabels.Add("C3"); 
pt1.RowLabels.Add("C4"); 
pt1.ColumnLabels.Add("CL1"); 
pt1.ColumnLabels.Add("CL2"); 
pt1.ColumnLabels.Add("CL3"); 
pt1.Values.Add("V").SummaryFormula = XL.XLPivotSummary.Sum; 

// Second Pivot 
XL.IXLWorksheet ptSheet2 = wb.Worksheets.Add("S3"); 
var pt2 = ptSheet2.PivotTables.AddNew("PivotTable2", ptSheet2.Cell(3, 1), cache); 
//Changed ptSheet1.Cell... to ptSheet2.Cell... 
pt2.ReportFilters.Add("QQ"); 
pt2.RowLabels.Add("C1"); 
pt2.RowLabels.Add("C2"); 
pt2.ColumnLabels.Add("CL1"); 
pt2.ColumnLabels.Add("CL2"); 
pt2.ColumnLabels.Add("CL3"); 
pt2.Values.Add("V").SummaryFormula = XL.XLPivotSummary.Sum;