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

时间:2015-01-15 22:20:26

标签: c# entity-framework stored-procedures ddd-repositories

我正在开发一个现有的应用程序,首先使用Generic Repo模式和EF6数据库。 我正在调用一个存储过程,它返回一个复杂类型,它不是我实体模型中的现有实体,因此我不确定要给出的类型。

这是我从服务层调用我的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();

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

的情况

谢谢

4 个答案:

答案 0 :(得分:15)

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

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

    public DateTime FromDateTime { get; set; }

    public DateTime ToDateTime { get; set; }
}

我不知道如何在您的情况下实现UnitOfWork模式,但我认为您可以访问您的Context。在UnitOfWork课程中,您可以创建如下通用方法:

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();

答案 1 :(得分:10)

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

如果您将SQL,存储过程名称和参数公开给您的客户端代码,那么您从Repository Pattern中获得的好处并不多,如果您实际上根本无法将其称为存储库。您失去了能够模拟存储库并独立于数据访问层测试业务层的好处。这意味着需要集成测试(需要完整的数据库实例)来验证业务逻辑。

考虑重新分解,以便您拥有一个CountryRepository类,该类具有返回Country实体或类似的GetCountry(int CountryId,DateTime fromDate,DateTime toDate)方法。我认为您同意,与您问题中的代码相比,您的代码的可读性会得到很大提高。

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

答案 2 :(得分:0)

    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();

答案 3 :(得分:-1)

public virtual IEnumerable<T> GetWithRawSql(string query, params object[] parameters)
        {
            return DbSet.SqlQuery(query, parameters).ToList();
        }

接口

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