Excel 匯入資料庫是企業應用常見功能。傳統做法:Excel → DataTable → List<T> → 資料庫。雖然通用 ExcelUtil 基類常提供 GetEntityListFromFile<T>(string fileName) 方法,但多為機械式一對一欄位對應,缺乏彈性,實務上常遇到以下挑戰:
public interface IExcelImporter<T> where T : class, new()
{
ImportResult<T> Import(Stream excelStream, ImportContext context);
}
public class ImportContext
{
public Dictionary<string, string> ColumnAliasMap { get; set; } // 欄位別名對應
public List<IColumnResolver> ColumnResolvers { get; set; } // 自定義欄位解析器
public List<IDataValidator<T>> Validators { get; set; } // 資料驗證器鏈
}
public interface IColumnResolver
{
bool CanResolve(string columnName, PropertyInfo targetProperty);
object ResolveValue(string rawValue, ImportContext context, PropertyInfo targetProperty);
}
public interface IDataValidator<T>
{
ValidationResult Validate(T entity, int rowIndex);
}
ColumnAliasMap 將多個 Excel 欄名映射至同一實體屬性,解析時優先嘗試別名匹配。IColumnResolver,例如 ForeignKeyResolver 可根據某欄值查詢資料庫並回填多個屬性。var importer = new ExcelImporter<ProductImportDto>();
var context = new ImportContext
{
ColumnAliasMap = new Dictionary<string, string>
{
{ "產品編號", "ProductId" },
{ "ID", "ProductId" },
{ "品名", "ProductName" }
},
ColumnResolvers = new List<IColumnResolver>
{
new ForeignKeyResolver("CategoryId", "CategoryName",
id => categoryService.GetNameById(id))
},
Validators = new List<IDataValidator<ProductImportDto>>
{
new RequiredFieldValidator<ProductImportDto>(d => d.ProductId),
new DuplicateValidator<ProductImportDto>(d => d.ProductId),
new BusinessRuleValidator<ProductImportDto>(d =>
d.Price > 0, "價格必須大於零")
}
};
var result = importer.Import(excelStream, context);
if (result.HasErrors)
{
// 輸出錯誤報表或顯示前端
ExportErrorReport(result.Errors);
}
else
{
productService.BulkInsert(result.Entities);
}
透過「配置驅動 + 策略模式 + 管道驗證」架構,將 Excel 匯入從僵化的欄位對應升級為可應對複雜業務場景的通用引擎,大幅降低維護成本並提升系統健壯性。