使用通用存储库和存储过程

Using Generic Repository and Stored Procedures

我正在开发一个现有应用程序,它首先使用通用回购模式和 EF6 数据库。 我正在调用一个存储过程,它 returns 是一个复杂类型,它不是我的实体模型中的现有实体,因此我不确定要提供什么类型。

这是从我的服务层调用我的 sp 的方式

_unitOfWork.Repository<Model>()
            .SqlQuery("sp_Get @FromDateTime, @ToDateTime, @CountyId",
                         new SqlParameter("FromDateTime", SqlDbType.DateTime) { Value = Request.FromDateTime },
                         new SqlParameter("ToDateTime", SqlDbType.DateTime) { Value = Request.TripToDateTime },
                         new SqlParameter("CountyId", SqlDbType.Int) { Value = Convert.ToInt32(Request.County) }
           ).ToList();

我是否在我的数据层中创建一个实体来映射到或什么是存储过程返回复杂类型的最佳方法。 如果是这样,是否需要自定义映射或者只是创建实体的情况 class

谢谢

如果您有一个包含这些字段的实体,您可以调用上面显示的 SqlQuery 方法,如果没有,那么我建议创建一个新的 class 来映射结果:

public class Result
{
    public int CountyId { get; set; }

    public DateTime FromDateTime { get; set; }

    public DateTime ToDateTime { get; set; }
}

我不知道在你的案例中 UnitOfWork 模式是如何实现的,但我假设你可以访问你的上下文。在您的 UnitOfWork class 中,您可以创建这样的通用方法:

public class UnitOfWork 
{
    private YourContext Context { get; set; }

    public DbRawSqlQuery<T> SQLQuery<T>(string sql, params object[] parameters)
    {
       return Context.Database.SqlQuery<T>(sql, parameters);
    }
}

这样,您就可以执行您的存储过程,如下所示:

var result= _unitOfWork.SqlQuery<Result>("sp_Get @FromDateTime, @ToDateTime, @CountyId",
                     new SqlParameter("FromDateTime", SqlDbType.DateTime) { Value = Request.FromDateTime },
                     new SqlParameter("ToDateTime", SqlDbType.DateTime) { Value = Request.TripToDateTime },
                     new SqlParameter("CountyId", SqlDbType.Int) { Value = Convert.ToInt32(Request.County) }
       ).ToList();

Repository Pattern 的目的是抽象出数据的存储和检索以保护您的客户端代码,例如业务层(在您的情况下为服务层)不需要了解有关数据如何持久化的任何信息。例如,SQL 语句只会存在于您的存储库 classes 中,而不会波及整个代码。

如果您将 SQL、存储过程名称和参数公开给您的客户端代码,您就不会从存储库模式中获益太多,而且事实上您根本不能真正将其称为存储库。您失去了能够独立于数据访问层模拟存储库和测试业务层的好处。这意味着需要集成测试(需要完整的数据库实例)来验证业务逻辑。

考虑重构,使您拥有一个 CountryRepository class,它具有 GetCountry(int CountryId, DateTime fromDate, DateTime toDate) 方法,returns 一个国家实体或类似方法。我想您会同意,与您问题中的代码相比,您的代码的可读性将大大提高。

public class CountryRepository
{
  public Country GetCountry(int CountryId, DateTime fromDate, DateTime toDate)
  {
    // EF or ADO.NET code here
  }
}

客户端代码将是例如

var c = unitOfWork.CountryRepository.GetCountry(1, DateTime.Now.AddYears(-1), DateTime.Now);

另请参阅此 SO question

    IQueryable<Cm_Customer> customerQuery = _uow.SqlQuery<Cm_Customer>(@" DECLARE @UserId INT = {0}
                                               EXEC Cm_GetCustomersByUserId @UserId", filter.UserId).AsQueryable();
    IQueryable<Cm_Customer> custs = customerQuery.IncludeMultiple(k => k.Cm_CustomerLocations,
                                           k => k.Cm_CustomerSalesmans,
                                           k => k.Cm_CustomerMachineparks,
                                           k => k.Cm_CustomerAuthenticators,
                                           k => k.Cm_CustomerInterviews,
                                           k => k.Cm_CustomerRequest,
                                           k => k.Cm_MachineparkRental).AsQueryable();
public virtual IEnumerable<T> GetWithRawSql(string query, params object[] parameters)
        {
            return DbSet.SqlQuery(query, parameters).ToList();
        }

界面

IEnumerable<T> GetWithRawSql(string query, params object[] parameters);