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

如何在Jason Taylor的Clean Architecture中调用存储过程?

在Jason Taylor的Clean Architecture中调用存储过程的实现方案

结合NorthwindTraders的架构分层设计,调用存储过程需要遵循依赖倒置原则,将具体实现放在Infrastructure层,Core层定义抽象接口,以下是具体步骤:

1. 在Core层定义抽象接口

在Core层的接口目录下,针对业务需求定义包含存储过程调用逻辑的抽象方法,同时定义用于接收存储过程返回数据的DTO(需放在Core层的DTO目录下):

// Core/Interfaces/IOrderRepository.cs
using Core.Dtos;
using System.Collections.Generic;
using System.Threading.Tasks;

public interface IOrderRepository
{
    Task<IEnumerable<OrderStatsDto>> GetOrderStatsAsync(DateTime startDate, DateTime endDate);
}

// Core/Dtos/OrderStatsDto.cs
public class OrderStatsDto
{
    public int OrderCount { get; set; }
    public decimal TotalRevenue { get; set; }
    public string Category { get; set; }
}

2. 在Infrastructure层实现接口并调用存储过程

Infrastructure层负责数据访问,通过EF Core的FromSqlRaw(有返回值)或ExecuteSqlRawAsync(无返回值)方法调用存储过程,同时利用参数化查询避免SQL注入:

// Infrastructure/Persistence/Repositories/OrderRepository.cs
using Core.Dtos;
using Core.Interfaces;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading.Tasks;

public class OrderRepository : IOrderRepository
{
    private readonly NorthwindDbContext _context;

    public OrderRepository(NorthwindDbContext context)
    {
        _context = context;
    }

    public async Task<IEnumerable<OrderStatsDto>> GetOrderStatsAsync(DateTime startDate, DateTime endDate)
    {
        // 定义参数,确保类型匹配
        var startParam = new SqlParameter("@StartDate", startDate);
        var endParam = new SqlParameter("@EndDate", endDate);

        // 调用存储过程,映射到DTO
        return await _context.Set<OrderStatsDto>()
            .FromSqlRaw("EXEC GetOrderStatsByDateRange @StartDate, @EndDate", startParam, endParam)
            .ToListAsync();
    }

    // 示例:执行无返回值的存储过程
    public async Task UpdateOrderStatusAsync(int orderId, string newStatus)
    {
        var orderIdParam = new SqlParameter("@OrderId", orderId);
        var statusParam = new SqlParameter("@NewStatus", newStatus);

        await _context.Database.ExecuteSqlRawAsync("EXEC UpdateOrderStatus @OrderId, @NewStatus", orderIdParam, statusParam);
    }
}

如果返回的DTO不是EF Core实体,需要在DbContext中配置为无键实体:

// Infrastructure/Persistence/NorthwindDbContext.cs
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 配置无键实体,用于存储过程返回结果映射
    modelBuilder.Entity<OrderStatsDto>().HasNoKey();
    
    // 其他实体配置...
}

3. 注册依赖注入

在Infrastructure层的DependencyInjection类中,将实现类与Core层的接口绑定:

// Infrastructure/DependencyInjection.cs
using Core.Interfaces;
using Infrastructure.Persistence.Repositories;
using Microsoft.Extensions.DependencyInjection;

public static class DependencyInjection
{
    public static IServiceCollection AddInfrastructure(this IServiceCollection services)
    {
        // 注册DbContext...
        
        // 注册仓储实现
        services.AddScoped<IOrderRepository, OrderRepository>();
        
        return services;
    }
}

4. 在Application层调用

通过MediatR的查询/命令处理器注入Core层接口,调用存储过程逻辑:

// Application/Orders/Queries/GetOrderStats/GetOrderStatsQuery.cs
using Core.Dtos;
using Core.Interfaces;
using MediatR;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

public class GetOrderStatsQuery : IRequest<IEnumerable<OrderStatsDto>>
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}

public class GetOrderStatsQueryHandler : IRequestHandler<GetOrderStatsQuery, IEnumerable<OrderStatsDto>>
{
    private readonly IOrderRepository _orderRepository;

    public GetOrderStatsQueryHandler(IOrderRepository orderRepository)
    {
        _orderRepository = orderRepository;
    }

    public async Task<IEnumerable<OrderStatsDto>> Handle(GetOrderStatsQuery request, CancellationToken cancellationToken)
    {
        return await _orderRepository.GetOrderStatsAsync(request.StartDate, request.EndDate);
    }
}

关键注意事项

  • 始终使用参数化查询,禁止直接拼接SQL字符串,避免SQL注入风险。
  • 存储过程的参数名称、类型需与代码中的参数严格匹配。
  • 若存储过程返回多个结果集,可使用_context.Database.ExecuteSqlRawAsync结合SqlDataReader手动处理。

内容的提问来源于stack exchange,提问作者Aman Rohilla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 13:18:27