@@ -230,6 +230,7 @@ You can find the benchmarks' results for the latest release [here](benchmarks/re
230230- [ Attributes and configuration] ( #docs-attributes )
231231- [ CSV specifics] ( #docs-csv )
232232- [ Other functionalities] ( #docs-other )
233+ - [ Fluent Cell Mapping] ( #docs-mapping )
233234- [ FAQ] ( #docs-faq )
234235- [ Limitations] ( #docs-limitations )
235236
@@ -647,29 +648,8 @@ When queried, the resource will be converted back to `byte[]`. If you don't need
647648
648649![ image] ( https://user-images.githubusercontent.com/12729184/153702334-c3b834f4-6ae4-4ddf-bd4e-e5005d5d8c6a.png )
649650
650- #### 12. Merge same cells vertically
651651
652- This functionality merges cells vertically between the tags ` @merge ` and ` @endmerge ` .
653- You can use ` @mergelimit ` to limit boundaries of merging cells vertically.
654-
655- ``` csharp
656- var templater = MiniExcel .Templaters .GetOpenXmlTemplater ();
657- templater .MergeSameCells (mergedFilePath , templatePath );
658- ```
659-
660- File content before and after merge without merge limit:
661-
662- <img width =" 318 " alt =" Screenshot 2023-08-07 at 11 59 24 " src =" https://github.com/mini-software/MiniExcel/assets/38832863/49cc96b9-6c35-4bf3-8d43-a9752a15b22e " >
663-
664- <img width =" 318 " alt =" Screenshot 2023-08-07 at 11 59 57 " src =" https://github.com/mini-software/MiniExcel/assets/38832863/3fbd529b-3ae6-4bbe-b4d8-2793a5a58010 " >
665-
666- File content before and after merge with merge limit:
667-
668- <img width =" 346 " alt =" Screenshot 2023-08-08 at 18 21 00 " src =" https://github.com/mini-software/MiniExcel/assets/38832863/04049d28-84d5-4c2a-bcff-5847547df5e1 " >
669-
670- <img width =" 346 " alt =" Screenshot 2023-08-08 at 18 21 40 " src =" https://github.com/mini-software/MiniExcel/assets/38832863/f5cf8957-b0b0-4831-b8fc-8556299235c2 " >
671-
672- #### 13. Null values handling
652+ #### 12. Null values handling
673653
674654By default, null values will be treated as empty strings when exporting:
675655
@@ -718,7 +698,7 @@ exporter.Export("test.xlsx", value, configuration: config);
718698
719699Both properties work with ` null ` and ` DBNull ` values.
720700
721- #### 14 . Freeze Panes
701+ #### 13 . Freeze Panes
722702
723703MiniExcel allows you to freeze both rows and columns in place:
724704
@@ -985,35 +965,35 @@ var value = new Dictionary<string, object>()
985965var templater = MiniExcel .Templaters .GetOpenXmlTemplater ();
986966templater .ApplyTemplate (path , templatePath , value );
987967```
988- - With ` @group ` tag and with ` @header ` tag
968+ - Without ` @group ` tag
989969
990970Before:
991971
992- ![ before_with_header ] ( https://user-images.githubusercontent.com/38832863/218646717-21b9d57a-2be2-4e9a-801b-ae212231d2b4 .PNG )
972+ ![ without_group ] ( https://user-images.githubusercontent.com/38832863/218646975-f52a68eb-e031-43b5-abaa-03b67c052d1a .PNG )
993973
994974After:
995975
996- ![ after_with_header ] ( https://user-images.githubusercontent.com/38832863/218646721-58a7a340-7004-4bc2-af24-cffcb2c20737 .PNG )
976+ ![ without_group_after ] ( https://user-images.githubusercontent.com/38832863/218646974-4a3c0e07-7c66-4088-ad07-b4ad3695b7e1 .PNG )
997977
998978- With ` @group ` tag and without ` @header ` tag
999979
1000980Before:
1001981
1002982![ before_without_header] ( https://user-images.githubusercontent.com/38832863/218646873-b12417fa-801b-4890-8e96-669ed3b43902.PNG )
1003983
1004- After;
984+ After:
1005985
1006986![ after_without_header] ( https://user-images.githubusercontent.com/38832863/218646872-622461ba-342e-49ee-834f-b91ad9c2dac3.PNG )
1007987
1008- - Without ` @group ` tag
988+ - With both ` @group ` and ` @header ` tags
1009989
1010990Before:
1011991
1012- ![ without_group ] ( https://user-images.githubusercontent.com/38832863/218646975-f52a68eb-e031-43b5-abaa-03b67c052d1a .PNG )
992+ ![ before_with_header ] ( https://user-images.githubusercontent.com/38832863/218646717-21b9d57a-2be2-4e9a-801b-ae212231d2b4 .PNG )
1013993
1014994After:
1015995
1016- ![ without_group_after ] ( https://user-images.githubusercontent.com/38832863/218646974-4a3c0e07-7c66-4088-ad07-b4ad3695b7e1 .PNG )
996+ ![ after_with_header ] ( https://user-images.githubusercontent.com/38832863/218646721-58a7a340-7004-4bc2-af24-cffcb2c20737 .PNG )
1017997
1018998#### 7. If/ElseIf/Else Statements inside cell
1019999
@@ -1043,7 +1023,31 @@ After:
10431023
10441024![ if_after] ( https://user-images.githubusercontent.com/38832863/235360609-869bb960-d63d-45ae-8d64-9e8b0d0ab658.PNG )
10451025
1046- #### 8. DataTable as parameter
1026+
1027+ #### 8. Merge same cells vertically
1028+
1029+ This functionality merges cells vertically between the tags ` @merge ` and ` @endmerge ` .
1030+ You can use ` @mergelimit ` to limit boundaries of merging cells vertically.
1031+
1032+ ``` csharp
1033+ var templater = MiniExcel .Templaters .GetOpenXmlTemplater ();
1034+ templater .MergeSameCells (mergedFilePath , templatePath );
1035+ ```
1036+
1037+ File content before and after merge without merge limit:
1038+
1039+ <img width =" 318 " alt =" Screenshot 2023-08-07 at 11 59 24 " src =" https://github.com/mini-software/MiniExcel/assets/38832863/49cc96b9-6c35-4bf3-8d43-a9752a15b22e " >
1040+
1041+ <img width =" 318 " alt =" Screenshot 2023-08-07 at 11 59 57 " src =" https://github.com/mini-software/MiniExcel/assets/38832863/3fbd529b-3ae6-4bbe-b4d8-2793a5a58010 " >
1042+
1043+ File content before and after merge with merge limit:
1044+
1045+ <img width =" 346 " alt =" Screenshot 2023-08-08 at 18 21 00 " src =" https://github.com/mini-software/MiniExcel/assets/38832863/04049d28-84d5-4c2a-bcff-5847547df5e1 " >
1046+
1047+ <img width =" 346 " alt =" Screenshot 2023-08-08 at 18 21 40 " src =" https://github.com/mini-software/MiniExcel/assets/38832863/f5cf8957-b0b0-4831-b8fc-8556299235c2 " >
1048+
1049+
1050+ #### 9. DataTable as parameter
10471051
10481052``` csharp
10491053var managers = new DataTable ();
@@ -1063,7 +1067,8 @@ var value = new Dictionary<string, object>()
10631067var templater = MiniExcel .Templaters .GetOpenXmlTemplater ();
10641068templater .ApplyTemplate (path , templatePath , value );
10651069```
1066- #### 9. Formulas
1070+
1071+ #### 10. Formulas
10671072Prefix your formula with ` $ ` and use ` $enumrowstart ` and ` $enumrowend ` to mark references to the enumerable start and end rows:
10681073
10691074![ image] ( docs/images/template-formulas-1.png )
@@ -1081,7 +1086,7 @@ _Other examples_:
10811086| Range | ` $=MAX(C{{$enumrowstart}}:C{{$enumrowend}}) - MIN(C{{$enumrowstart}}:C{{$enumrowend}}) ` |
10821087
10831088
1084- #### 10 . Checking template parameter key
1089+ #### 11 . Checking template parameter key
10851090
10861091When a parameter key is missing it will be replaced with an empty string by default.
10871092You can change this behaviour to throw an exception by setting the ` IgnoreTemplateParameterMissing ` configuration property:
@@ -1295,7 +1300,142 @@ var exporter = MiniExcel.Exporters.GetOpenXmlExporter();
12951300exporter .Export (path , sheets , configuration : configuration );
12961301```
12971302
1298- ### CSV <a name =" docs-csv " />
1303+
1304+ ### Fluent Cell Mapping <a name =" docs-mapping " />
1305+
1306+ Since v2.0.0, MiniExcel supports a fluent API for precise cell-by-cell mapping, giving you complete control over Excel layout without relying on conventions or attributes.
1307+
1308+ > ⚠️ ** Important:** Compile mappings only once during application startup!
1309+
1310+ Mapping compilation is a one-time operation that generates optimized runtime code. Create a single ` MappingRegistry ` instance and configure all your mappings at startup. Reuse this registry throughout your application for optimal performance.
1311+
1312+ #### 1. Basic Property Mapping
1313+
1314+ Map properties to specific cells using the fluent configuration API:
1315+
1316+ ``` csharp
1317+ // Configure once at application startup
1318+ var registry = new MappingRegistry ();
1319+ registry .Configure <Person >(cfg =>
1320+ {
1321+ cfg .Property (p => p .Name ).ToCell (" A1" );
1322+ cfg .Property (p => p .Age ).ToCell (" B1" );
1323+ cfg .Property (p => p .Email ).ToCell (" C1" );
1324+ cfg .Property (p => p .Salary ).ToCell (" D1" ).WithFormat (" #,##0.00" );
1325+ cfg .Property (p => p .BirthDate ).ToCell (" E1" ).WithFormat (" yyyy-MM-dd" );
1326+ cfg .ToWorksheet (" Employees" );
1327+ });
1328+
1329+ var exporter = MiniExcel .Exporters .GetMappingExporter (registry );
1330+ await exporter .ExportAsync (stream , people );
1331+ ```
1332+
1333+ #### 2. Reading with Fluent Mappings
1334+
1335+ ``` csharp
1336+ // Configure once at startup
1337+ var registry = new MappingRegistry ();
1338+ registry .Configure <Person >(cfg =>
1339+ {
1340+ cfg .Property (p => p .Name ).ToCell (" A2" );
1341+ cfg .Property (p => p .Age ).ToCell (" B2" );
1342+ cfg .Property (p => p .Email ).ToCell (" C2" );
1343+ });
1344+
1345+ // Read data using the mapping
1346+ var importer = MiniExcel .Importers .GetMappingImporter (registry );
1347+ var people = importer .Query <Person >(stream ).ToList ();
1348+ ```
1349+
1350+ #### 3. Collection Mapping
1351+
1352+ Map collections to specific cell ranges (collections are laid out vertically by default):
1353+
1354+ ``` csharp
1355+ registry .Configure <Department >(cfg =>
1356+ {
1357+ cfg .Property (d => d .Name ).ToCell (" A1" );
1358+
1359+ // Simple collections (strings, numbers, etc.) - starts at A3 and goes down
1360+ cfg .Collection (d => d .PhoneNumbers ).StartAt (" A3" );
1361+
1362+ // Complex object collections - starts at C3 and goes down
1363+ cfg .Collection (d => d .Employees ).StartAt (" C3" );
1364+ });
1365+ ```
1366+
1367+ You can optionally add spacing between collection items:
1368+
1369+ ``` csharp
1370+ registry .Configure <Employee >(cfg =>
1371+ {
1372+ cfg .Property (e => e .Name ).ToCell (" A1" );
1373+ cfg .Collection (e => e .Skills ).StartAt (" B1" ).WithSpacing (1 ); // 1 row spacing between items
1374+ });
1375+ ```
1376+
1377+ #### 4. Formulas and Formatting
1378+
1379+ ``` csharp
1380+ registry .Configure <Product >(cfg =>
1381+ {
1382+ cfg .Property (p => p .Price ).ToCell (" B1" );
1383+ cfg .Property (p => p .Stock ).ToCell (" C1" );
1384+
1385+ // Add a formula for calculated values
1386+ cfg .Property (p => p .Price ).ToCell (" D1" ).WithFormula (" =B1*C1" );
1387+
1388+ // Apply custom number formatting
1389+ cfg .Property (p => p .Price ).ToCell (" E1" ).WithFormat (" $#,##0.00" );
1390+ });
1391+ ```
1392+
1393+ #### 5. Template Support
1394+
1395+ Apply mappings to existing Excel templates:
1396+
1397+ ``` csharp
1398+ registry .Configure <TestEntity >(cfg =>
1399+ {
1400+ cfg .Property (x => x .Name ).ToCell (" A3" );
1401+ cfg .Property (x => x .CreateDate ).ToCell (" B3" );
1402+ cfg .Property (x => x .VIP ).ToCell (" C3" );
1403+ cfg .Property (x => x .Points ).ToCell (" D3" );
1404+ });
1405+
1406+ var data = new TestEntity
1407+ {
1408+ Name = " Jack" ,
1409+ CreateDate = new DateTime (2021 , 01 , 01 ),
1410+ VIP = true ,
1411+ Points = 123
1412+ };
1413+
1414+ var termplater = MiniExcel .Templaters .GetMappingExporter (registry );
1415+ await termplater .ApplyTemplateAsync (outputPath , templatePath , new [] { data });
1416+ ```
1417+
1418+ #### 6. Advanced: Nested Collections with Item Mapping
1419+
1420+ Configure how items within a collection should be mapped:
1421+
1422+ ``` csharp
1423+ registry .Configure <Company >(cfg =>
1424+ {
1425+ cfg .Property (c => c .Name ).ToCell (" A1" );
1426+
1427+ cfg .Collection (c => c .Departments )
1428+ .StartAt (" A3" )
1429+ .WithItemMapping <Department >(deptCfg =>
1430+ {
1431+ deptCfg .Property (d => d .Name ).ToCell (" A3" );
1432+ deptCfg .Collection (d => d .Employees ).StartAt (" B3" );
1433+ });
1434+ });
1435+ ```
1436+
1437+
1438+ ### CSV Specifics <a name =" docs-csv " />
12991439
13001440> Unlike Excel queries, csv always maps values to ` string ` by default, unless you are querying to a strongly defined type.
13011441
0 commit comments