diff --git a/ClosedXML/Excel/Exceptions/ClosedXMLException.cs b/ClosedXML/Excel/Exceptions/ClosedXMLException.cs new file mode 100644 index 0000000..3a00816 --- /dev/null +++ b/ClosedXML/Excel/Exceptions/ClosedXMLException.cs @@ -0,0 +1,19 @@ +using System; + +namespace ClosedXML.Excel.Exceptions +{ + public abstract class ClosedXMLException : Exception + { + protected ClosedXMLException() + : base() + { } + + protected ClosedXMLException(String message) + : base(message) + { } + + protected ClosedXMLException(String message, Exception innerException) + : base(message, innerException) + { } + } +} diff --git a/ClosedXML/Excel/Exceptions/EmptyTableException.cs b/ClosedXML/Excel/Exceptions/EmptyTableException.cs new file mode 100644 index 0000000..1f657e2 --- /dev/null +++ b/ClosedXML/Excel/Exceptions/EmptyTableException.cs @@ -0,0 +1,19 @@ +using System; + +namespace ClosedXML.Excel.Exceptions +{ + public class EmptyTableException : ClosedXMLException + { + public EmptyTableException() + : base() + { } + + public EmptyTableException(String message) + : base(message) + { } + + public EmptyTableException(String message, Exception innerException) + : base(message, innerException) + { } + } +} diff --git a/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/Excel/XLWorkbook_Save.cs index 1544814..a1b1227 100644 --- a/ClosedXML/Excel/XLWorkbook_Save.cs +++ b/ClosedXML/Excel/XLWorkbook_Save.cs @@ -1,4 +1,5 @@ using ClosedXML.Excel.ContentManagers; +using ClosedXML.Excel.Exceptions; using ClosedXML.Extensions; using ClosedXML.Utils; using DocumentFormat.OpenXml; @@ -407,6 +408,10 @@ { var tables = worksheet.Tables as XLTables; + var emptyTable = tables.FirstOrDefault(t => t.DataRange == null); + if (emptyTable != null) + throw new EmptyTableException($"Table '{emptyTable.Name}' should have at least 1 row."); + TableParts tableParts; if (worksheetPart.Worksheet.Elements().Any()) { @@ -434,7 +439,7 @@ tables.Deleted.Clear(); - foreach (var xlTable in worksheet.Tables.Cast()) + foreach (var xlTable in tables.Cast()) { if (String.IsNullOrEmpty(xlTable.RelId)) xlTable.RelId = context.RelIdGenerator.GetNext(RelType.Workbook); @@ -456,7 +461,7 @@ } } - tableParts.Count = (UInt32)worksheet.Tables.Count(); + tableParts.Count = (UInt32)tables.Count(); } private void GenerateExtendedFilePropertiesPartContent(ExtendedFilePropertiesPart extendedFilePropertiesPart) diff --git a/ClosedXML_Tests/Excel/Tables/TablesTests.cs b/ClosedXML_Tests/Excel/Tables/TablesTests.cs index d6cb000..e29fcb4 100644 --- a/ClosedXML_Tests/Excel/Tables/TablesTests.cs +++ b/ClosedXML_Tests/Excel/Tables/TablesTests.cs @@ -1,5 +1,6 @@ using ClosedXML.Attributes; using ClosedXML.Excel; +using ClosedXML.Excel.Exceptions; using NUnit.Framework; using System; using System.Collections.Generic; @@ -830,7 +831,6 @@ ws.FirstCell().InsertTable(l); Assert.Throws(() => ws.RangeUsed().CreateTable()); } - } [Test] @@ -844,7 +844,6 @@ TestDelegate action = () => table.CopyTo(ws1); Assert.Throws(typeof(InvalidOperationException), action); - } [Test] @@ -938,6 +937,37 @@ Assert.AreEqual("", ws2.Cell("C2").Value); } + [Test] + public void SavingTableWithNullDataRangeThrowsException() + { + using (var ms = new MemoryStream()) + using (var wb = new XLWorkbook()) + { + var ws = wb.AddWorksheet("Sheet1"); + + var data = Enumerable.Range(1, 10) + .Select(i => new + { + Number = i, + NumberString = String.Concat("Number", i.ToString()) + }); + + var table = ws.FirstCell() + .InsertTable(data) + .SetShowTotalsRow(); + + table.Fields.Last().TotalsRowFunction = XLTotalsRowFunction.Count; + + table.DataRange.Rows() + .OrderByDescending(r => r.RowNumber()) + .ToList() + .ForEach(r => r.WorksheetRow().Delete()); + + Assert.IsNull(table.DataRange); + Assert.Throws(() => wb.SaveAs(ms)); + } + } + private void AssertTablesAreEqual(IXLTable table1, IXLTable table2) { Assert.AreEqual(table1.RangeAddress.ToString(XLReferenceStyle.A1, false), table2.RangeAddress.ToString(XLReferenceStyle.A1, false));