Skip to content

Commit 89a6c54

Browse files
authored
Merge pull request #63 from PandaTechAM/development
Performance optimization and naming bug fix
2 parents 6029f7b + 90026ee commit 89a6c54

File tree

4 files changed

+73
-81
lines changed

4 files changed

+73
-81
lines changed

src/FileExporter/Dtos/PropertyData.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ internal class PropertyData
77
public required PropertyInfo Property { get; internal set; }
88
public bool HasBaseConverter { get; internal set; }
99
public required string Name { get; internal set; }
10+
public string ModelPropertyName => Property.Name;
1011
}

src/FileExporter/Extensions/EnumerableExtensions.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,16 +155,13 @@ private static ExportFile CreateZip(string baseName, MimeTypes innerType, IReadO
155155
var entryName = parts.Count == 1
156156
? $"{baseName}{innerType.Extension}"
157157
: $"{baseName}_{i + 1}{innerType.Extension}";
158-
159158
var entry = zip.CreateEntry(entryName, CompressionLevel.Optimal);
160-
161159
using var es = entry.Open();
162160
es.Write(parts[i]);
163161
}
164162
}
165163

166-
// no extra ToArray(); MemoryStream already owns the buffer we need
167-
return new ExportFile($"{baseName}.zip", MimeTypes.Zip, ms.GetBuffer()[..(int)ms.Length]);
164+
return new ExportFile(baseName, MimeTypes.Zip, ms.GetBuffer()[..(int)ms.Length]);
168165
}
169166

170167

src/FileExporter/FileExporter.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
<Copyright>MIT</Copyright>
99
<PackageIcon>Logo.jpg</PackageIcon>
1010
<PackageReadmeFile>Readme.md</PackageReadmeFile>
11-
<Version>4.0.7</Version>
11+
<Version>4.1.0</Version>
1212
<Company>PandaTech</Company>
1313
<Title>Model to File</Title>
1414
<PackageTags>Pandatech, lib, export, xlsx, csv, pdf</PackageTags>
1515
<Description>Export table data into xls, xlsx, csv, pdf formats</Description>
1616
<RepositoryUrl>https://github.com/PandaTechAM/be-lib-file-exporter</RepositoryUrl>
17-
<PackageReleaseNotes>Nuget updates</PackageReleaseNotes>
17+
<PackageReleaseNotes>Performance optimizations and naming bug fix</PackageReleaseNotes>
1818
</PropertyGroup>
1919

2020
<ItemGroup>

src/FileExporter/Helpers/DataTable.cs

Lines changed: 69 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ internal class DataTable<T>
2020
{
2121
private readonly IEnumerable<PropertyData> _properties;
2222
private readonly IEnumerable<T> _records;
23+
private readonly Dictionary<string, object?> _defaults = new();
2324

24-
internal DataTable()
25+
private DataTable()
2526
{
2627
_records = [];
2728
_properties = [];
@@ -64,39 +65,24 @@ internal DataTable(IEnumerable<T> data, string name, IEnumerable<IPropertyRule>
6465
var modelProperties = typeof(T).GetProperties()
6566
.ToDictionary(x => x.Name, x => x);
6667

67-
_properties = rules
68-
.Select(x => new PropertyData
69-
{
70-
Property = modelProperties[x.PropertyName()],
71-
HasBaseConverter = false,
72-
Name = x.ColumnName()
73-
})
74-
.ToList();
68+
_properties = rules.Select(r => new PropertyData
69+
{
70+
Property = modelProperties[r.PropertyName()],
71+
HasBaseConverter = false,
72+
Name = r.ColumnName()
73+
})
74+
.ToList();
7575

76-
Headers = _properties.Select(x => x.Name)
76+
Headers = _properties.Select(p => p.Name)
7777
.ToList();
7878

79-
var ruleByDefaultValue = rules
80-
.Where(x => x.DefaultColumnValue() != null)
81-
.ToDictionary(x => x.PropertyName(), x => x.DefaultColumnValue());
82-
83-
foreach (var model in data)
79+
// collect defaults per *model* property name
80+
foreach (var r in rules)
8481
{
85-
var properties = model!.GetType()
86-
.GetProperties();
87-
foreach (var property in properties)
82+
var def = r.DefaultColumnValue();
83+
if (def != null)
8884
{
89-
if (ruleByDefaultValue.TryGetValue(property.Name, out var value))
90-
{
91-
if (!model.GetType()
92-
.IsGenericType || model.GetType()
93-
.Name
94-
.Contains("String"))
95-
{
96-
model.GetType()
97-
.GetProperty(property.Name)!.SetValue(model, value);
98-
}
99-
}
85+
_defaults[r.PropertyName()] = def;
10086
}
10187
}
10288

@@ -114,10 +100,15 @@ internal IEnumerable<IDictionary<string, string>> GetRecordsForExport()
114100

115101
foreach (var property in _properties)
116102
{
117-
var value = property.Property.GetValue(dataRow);
103+
var raw = property.Property.GetValue(dataRow);
118104

119-
var toString = ConvertDataToString(value, property.HasBaseConverter);
105+
// If the model value is null and we have a default for that model property, use it
106+
if (raw is null && _defaults.TryGetValue(property.ModelPropertyName, out var def))
107+
{
108+
raw = def;
109+
}
120110

111+
var toString = ConvertDataToString(raw, property.HasBaseConverter);
121112
row.Add(property.Name, toString);
122113
}
123114

@@ -128,78 +119,81 @@ internal IEnumerable<IDictionary<string, string>> GetRecordsForExport()
128119
internal List<byte[]> ToCsv()
129120
{
130121
var records = GetRecordsForExport();
131-
132-
var recordsChunks = records.Chunk(Constants.CsvLinesCount);
122+
var chunks = records.Chunk(Constants.CsvLinesCount);
133123

134124
var files = new List<byte[]>();
135125

136-
var csv = new StringBuilder();
137-
csv.AppendLine(string.Join(",", Headers));
138-
139-
foreach (var chunk in recordsChunks)
126+
foreach (var chunk in chunks)
140127
{
128+
var sb = new StringBuilder();
129+
sb.AppendLine(string.Join(",", Headers));
130+
141131
foreach (var record in chunk)
142132
{
143-
csv.AppendLine(string.Join(",", record.Values.Select(Encapsulate)));
133+
sb.AppendLine(string.Join(",", record.Values.Select(Encapsulate)));
144134
}
145-
}
146-
147-
var data = Encoding.UTF8
148-
.GetBytes(csv.ToString()
149-
.Trim());
150135

151-
var file = Encoding.UTF8
152-
.GetPreamble()
153-
.Concat(data)
154-
.ToArray();
155-
156-
files.Add(file);
136+
var data = Encoding.UTF8.GetBytes(sb.ToString()
137+
.TrimEnd());
138+
var file = Encoding.UTF8
139+
.GetPreamble()
140+
.Concat(data)
141+
.ToArray();
142+
files.Add(file);
143+
}
157144

158145
return files;
159146
}
160147

161148
internal List<byte[]> ToXlsx()
162149
{
163150
var records = GetRecordsForExport();
164-
165151
var recordsChunks = records.Chunk(Constants.ExcelLinesCount);
166152

167153
var files = new List<byte[]>();
168154

169-
var workbook = new XLWorkbook();
170-
var worksheet = workbook.Worksheets.Add(Name.ToValidName());
171-
172-
for (var i = 0; i < Headers.Count; i++)
155+
foreach (var chunk in recordsChunks)
173156
{
174-
worksheet.Cell(1, i + 1)
175-
.Value = Headers[i];
176-
worksheet.Cell(1, i + 1)
177-
.Style.Font.Bold = true;
178-
}
157+
using var workbook = new XLWorkbook();
158+
var ws = workbook.Worksheets.Add(Name.ToValidName());
179159

180-
worksheet.SheetView.FreezeRows(1);
181-
worksheet.RangeUsed()!
182-
.SetAutoFilter(true);
183-
worksheet.Columns()
184-
.AdjustToContents();
160+
// header
161+
for (var c = 0; c < Headers.Count; c++)
162+
{
163+
var cell = ws.Cell(1, c + 1);
164+
cell.Value = Headers[c];
165+
cell.Style.Font.Bold = true;
166+
}
185167

186-
foreach (var chunk in recordsChunks)
187-
{
188-
for (var i = 0; i < chunk.Length; i++)
168+
ws.SheetView.FreezeRows(1);
169+
ws.Range(1, 1, 1, Headers.Count)
170+
.SetAutoFilter();
171+
172+
// data
173+
var row = 2;
174+
foreach (var t in chunk)
189175
{
190176
for (var j = 0; j < Headers.Count; j++)
191177
{
192-
worksheet.Cell(i + 2, j + 1)
193-
.Value = chunk[i][Headers[j]];
194-
worksheet.Cell(i + 2, j + 1)
195-
.Style.NumberFormat.Format = "@";
178+
var cell = ws.Cell(row, j + 1);
179+
cell.Value = t[Headers[j]];
180+
cell.Style.NumberFormat.Format = "@";
196181
}
182+
183+
row++;
197184
}
198-
}
199185

200-
using var stream = new MemoryStream();
201-
workbook.SaveAs(stream);
202-
files.Add(stream.ToArray());
186+
// cheap width based on header only
187+
for (var c = 1; c <= Headers.Count; c++)
188+
{
189+
ws.Column(c)
190+
.Width = Math.Max(Headers[c - 1].Length + 2, 10);
191+
}
192+
193+
using var stream = new MemoryStream();
194+
workbook.SaveAs(stream);
195+
files.Add(stream.ToArray());
196+
}
203197

204198
return files;
205199
}

0 commit comments

Comments
 (0)