You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core中Dapper自定义映射配置的正确初始化方式

问题描述

我在付费在线课程的作业中开发了一个三层架构的小程序,近期将表现层从控制台替换为ASP.NET Core。数据层中我为Dapper编写了自定义映射类:

namespace CarRental.Data.Managers
{
    public class DapperConfigurationManager
    {
        // METHODS

        public void ConfigureGuidToStringMapping()
        {
            SqlMapper.AddTypeHandler(new GuidToStringTypeHandler());
            SqlMapper.RemoveTypeMap(typeof(Guid));
        }

        public void SetCustomMappingForEntities()
        {
            CustomPropertyTypeMap carMap = new CustomPropertyTypeMap(typeof(Car), PropertyInformation);
            CustomPropertyTypeMap customerMap = new CustomPropertyTypeMap(typeof(CustomerTemp), PropertyInformation);
            CustomPropertyTypeMap dealMap = new CustomPropertyTypeMap(typeof(Deal), PropertyInformation);
            CustomPropertyTypeMap inspectionMap = new CustomPropertyTypeMap(typeof(Inspection), PropertyInformation);
            CustomPropertyTypeMap repairMap = new CustomPropertyTypeMap(typeof(Repair), PropertyInformation);
            CustomPropertyTypeMap mechanicMap = new CustomPropertyTypeMap(typeof(Mechanic), PropertyInformation);

            SqlMapper.SetTypeMap(typeof(Car), carMap);
            SqlMapper.SetTypeMap(typeof(CustomerTemp), customerMap);
            SqlMapper.SetTypeMap(typeof(Deal), dealMap);
            SqlMapper.SetTypeMap(typeof(Inspection), inspectionMap);
            SqlMapper.SetTypeMap(typeof(Repair), repairMap);
            SqlMapper.SetTypeMap(typeof(Mechanic), mechanicMap);
        }

        public static PropertyInfo PropertyInformation(Type type, string attribName)
        {
            // BECAUSE THE METHOD IS STRONGLY TYPED, I CANNOT MOVE IT IN FROM THE OUTSIDE.
            Dictionary<string, string> columnProperties = new Dictionary<string, string>
            {
                { "carCarId", "CarId" },
                { "carVinCode", "VinCode" },
                { "carNumberPlate", "NumberPlate" },
                { "carBrand", "Brand" },
                { "carModel", "Model" },
                { "carPrice", "Price" },
                { "carNumberOfSeats", "NumberOfSeats" },
                { "carNumberOfDoors", "NumberOfDoors" },
                { "carMileage", "Mileage" },
                { "carMaxFuelCapacity", "MaxFuelCapacity" },
                { "carCurrentFuel", "CurrentFuel" },
                { "carYear", "Year" },
                { "carIsFitForUse", "IsFitForUse" },
                { "carEngine", "Engine" },
                { "carTransmission", "Transmission" },
                { "carInterior", "Interior" },
                { "carWheels", "Wheels" },
                { "carLights", "Lights" },
                { "carSignal", "Signal" },
                { "carColor", "Color" },
                { "carStatusId", "Status" },
                { "userIdNumber", "IdNumber" },
                { "userFirstName", "FirstName" },
                { "userLastName", "LastName" },
                { "userDateOfBirth", "DateOfBirth" },
                { "userUserName", "UserName" },
                { "userPassword", "Password" },
                { "userPassportNumber", "PassportNumber" },
                { "userDrivingLicenseNumber", "DrivingLicenseNumber" },
                { "userBasicDiscount", "BasicDiscount" },
                { "userCategory", "Category" },
                { "dealId", "Id" },
                { "dealCarId", "CarId" },
                { "dealVinCode", "VinCode" },
                { "dealCustomerId", "CustomerId" },
                { "dealPrice", "Price" },
                { "dealDealType", "DealType" },
                { "dealName", "Name" },
                { "inspectionInspectionId", "InspectionId" },
                { "inspectionCarId", "CarId" },
                { "inspectionInspectorId", "InspectorId" },
                { "inspectionInspectionDate", "InspectionDate" },
                { "inspectionStatusId", "Result" },
                { "repairId", "Id" },
                { "repairDate", "Date" },
                { "repairCarId", "CarId" },
                { "repairMechanicId", "MechanicId" },
                { "repairIsSuccessfull", "IsSuccessfull" },
                { "repairTotalCost", "TotalCost" },
                { "repairTechnicalInfo", "TechnicalInfo" },
                { "mechanId", "Id" },
                { "mechanName", "Name" },
                { "mechanSurename", "Surename" },
                { "mechanYear", "Year" }
            };

            if (columnProperties.ContainsKey(attribName))
            {
                return type.GetProperty(columnProperties[attribName]);
            }

            return type.GetProperty(attribName);
        }
    }
}

我尝试在Program.cs中按如下方式实现初始化:

namespace CarRental.WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // TO CONFIGURE ORM FOR Car-CLASS.
            var carServiceManager = new ServiceManager();
            carServiceManager.InitializeManagment();
            carServiceManager.SupplementData.DapperConfigs.ConfigureGuidToStringMapping();
            carServiceManager.SupplementData.DapperConfigs.SetCustomMappingForEntities();

            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.
            builder.Services.AddControllers();
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();
            builder.Services.AddTransient<ServiceManager>(x => new ServiceManager());

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();
            app.UseAuthorization();
            app.MapControllers();
            app.Run();
        }
    }
}

但老师指出该实现存在问题(手动创建的ServiceManager实例可能长期存活等),却未告知正确方案。我仅具备C#基础,不清楚在ASP.NET Core中如何正确初始化该Dapper自定义映射,作业即将截止,且没有该映射无法从远程数据库获取数据。另外,默认模板中大量使用var导致我难以理解代码类型。

请问在ASP.NET Core中正确实现Dapper自定义映射配置初始化的方式是什么?


解决方案

核心思路

Dapper的自定义映射(类型处理器、类型映射)是全局生效的,只需要在应用启动时执行一次即可,不需要依赖ServiceManager的实例,也不需要放到DI容器里重复创建。

步骤1:简化初始化逻辑,脱离ServiceManager

把Dapper的配置逻辑独立出来,不需要依赖ServiceManager。可以直接在DapperConfigurationManager里添加一个静态方法,一键完成所有配置:

namespace CarRental.Data.Managers
{
    public class DapperConfigurationManager
    {
        // 新增静态方法,一键完成所有Dapper配置
        public static void InitializeAllDapperConfigurations()
        {
            ConfigureGuidToStringMappingStatic();
            SetCustomMappingForEntitiesStatic();
        }

        private static void ConfigureGuidToStringMappingStatic()
        {
            SqlMapper.AddTypeHandler(new GuidToStringTypeHandler());
            SqlMapper.RemoveTypeMap(typeof(Guid));
        }

        private static void SetCustomMappingForEntitiesStatic()
        {
            CustomPropertyTypeMap carMap = new CustomPropertyTypeMap(typeof(Car), PropertyInformation);
            CustomPropertyTypeMap customerMap = new CustomPropertyTypeMap(typeof(CustomerTemp), PropertyInformation);
            CustomPropertyTypeMap dealMap = new CustomPropertyTypeMap(typeof(Deal), PropertyInformation);
            CustomPropertyTypeMap inspectionMap = new CustomPropertyTypeMap(typeof(Inspection), PropertyInformation);
            CustomPropertyTypeMap repairMap = new CustomPropertyTypeMap(typeof(Repair), PropertyInformation);
            CustomPropertyTypeMap mechanicMap = new CustomPropertyTypeMap(typeof(Mechanic), PropertyInformation);

            SqlMapper.SetTypeMap(typeof(Car), carMap);
            SqlMapper.SetTypeMap(typeof(CustomerTemp), customerMap);
            SqlMapper.SetTypeMap(typeof(Deal), dealMap);
            SqlMapper.SetTypeMap(typeof(Inspection), inspectionMap);
            SqlMapper.SetTypeMap(typeof(Repair), repairMap);
            SqlMapper.SetTypeMap(typeof(Mechanic), mechanicMap);
        }

        public static PropertyInfo PropertyInformation(Type type, string attribName)
        {
            // 原有的字典映射内容保持不变
            Dictionary<string, string> columnProperties = new Dictionary<string, string>
            {
                { "carCarId", "CarId" },
                { "carVinCode", "VinCode" },
                { "carNumberPlate", "NumberPlate" },
                { "carBrand", "Brand" },
                { "carModel", "Model" },
                { "carPrice", "Price" },
                { "carNumberOfSeats", "NumberOfSeats" },
                { "carNumberOfDoors", "NumberOfDoors" },
                { "carMileage", "Mileage" },
                { "carMaxFuelCapacity", "MaxFuelCapacity" },
                { "carCurrentFuel", "CurrentFuel" },
                { "carYear", "Year" },
                { "carIsFitForUse", "IsFitForUse" },
                { "carEngine", "Engine" },
                { "carTransmission", "Transmission" },
                { "carInterior", "Interior" },
                { "carWheels", "Wheels" },
                { "carLights", "Lights" },
                { "carSignal", "Signal" },
                { "carColor", "Color" },
                { "carStatusId", "Status" },
                { "userIdNumber", "IdNumber" },
                { "userFirstName", "FirstName" },
                { "userLastName", "LastName" },
                { "userDateOfBirth", "DateOfBirth" },
                { "userUserName", "UserName" },
                { "userPassword", "Password" },
                { "userPassportNumber", "PassportNumber" },
                { "userDrivingLicenseNumber", "DrivingLicenseNumber" },
                { "userBasicDiscount", "BasicDiscount" },
                { "userCategory", "Category" },
                { "dealId", "Id" },
                { "dealCarId", "CarId" },
                { "dealVinCode", "VinCode" },
                { "dealCustomerId", "CustomerId" },
                { "dealPrice", "Price" },
                { "dealDealType", "DealType" },
                { "dealName", "Name" },
                { "inspectionInspectionId", "InspectionId" },
                { "inspectionCarId", "CarId" },
                { "inspectionInspectorId", "InspectorId" },
                { "inspectionInspectionDate", "InspectionDate" },
                { "inspectionStatusId", "Result" },
                { "repairId", "Id" },
                { "repairDate", "Date" },
                { "repairCarId", "CarId" },
                { "repairMechanicId", "MechanicId" },
                { "repairIsSuccessfull", "IsSuccessfull" },
                { "repairTotalCost", "TotalCost" },
                { "repairTechnicalInfo", "TechnicalInfo" },
                { "mechanId", "Id" },
                { "mechanName", "Name" },
                { "mechanSurename", "Surename" },
                { "mechanYear", "Year" }
            };

            if (columnProperties.ContainsKey(attribName))
            {
                return type.GetProperty(columnProperties[attribName]);
            }

            return type.GetProperty(attribName);
        }
    }
}

步骤2:在Program.cs中正确初始化

在应用启动的最开始(构建WebApplication之前)执行Dapper的全局配置,不需要手动创建ServiceManager,同时把var替换为具体类型方便理解:

namespace CarRental.WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // 第一步:初始化Dapper全局映射,仅执行一次
            CarRental.Data.Managers.DapperConfigurationManager.InitializeAllDapperConfigurations();

            // 第二步:构建Web应用(替换var为具体类型)
            WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

            // 添加服务到DI容器
            builder.Services.AddControllers();
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();
            // 正确注册ServiceManager到DI容器,框架会自动管理其生命周期
            builder.Services.AddTransient<ServiceManager>();

            WebApplication app = builder.Build();

            // 配置HTTP请求管道
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();
            app.UseAuthorization();
            app.MapControllers();
            app.Run();
        }
    }
}

为什么原来的实现有问题?

  1. 手动创建ServiceManager实例后,又在DI容器中注册了新的实例,导致存在两个独立的对象,浪费资源且可能引发状态不一致。
  2. Dapper的映射是全局配置,不需要依赖ServiceManager的生命周期,手动创建实例完全没必要,还可能因为实例长期存活导致内存占用问题。

内容的提问来源于stack exchange,提问作者Yaroslav Parkhomenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 21:37:02