Использование общего репозитория и хранимых процедур

Я работаю над существующим приложением, которое сначала использует шаблон 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();

Должен ли я создать сущность в своем слое данных для сопоставления или каков наилучший подход для хранимых процедур, возвращающих сложные типы. Если да, то нужно ли настраиваемое отображение или это просто случай создания класса Entity?

благодарю вас

4 ответа

Решение

Если у вас есть объект с этими полями, вы можете вызвать метод SqlQuery, как показано выше, если нет, то я предлагаю создать новый класс для сопоставления результата:

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

    public DateTime FromDateTime { get; set; }

    public DateTime ToDateTime { get; set; }
}

Я не знаю, как реализован шаблон UnitOfWork в вашем случае, но я предполагаю, что у вас есть доступ к вашему контексту. В вашем 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();

Цель шаблона репозитория состоит в том, чтобы абстрагироваться от хранения и извлечения данных, чтобы защитить ваш клиентский код, например бизнес-уровень (сервисный уровень в вашем случае), от необходимости знать что-либо о том, как данные сохраняются. Например, операторы SQL будут существовать только внутри ваших классов репозитория и не будут колебаться в вашем коде.

Если вы предоставляете SQL-код, имена и параметры хранимых процедур вашему клиентскому коду, вы не получите большой пользы от шаблона репозитория, а в действительности вы вообще не можете назвать его репозиторием. Вы теряете возможность смоделировать хранилище и тестировать свой бизнес-уровень независимо от уровня доступа к данным. Это означает, что интеграционные тесты (требующие полного экземпляра базы данных) необходимы для проверки бизнес-логики.

Подумайте о перефакторинге, чтобы у вас был класс CountryRepository, у которого есть метод GetCountry(int CountryId, DateTime fromDate, DateTime toDate), который возвращает сущность Country или аналогичный. Я думаю, вы согласитесь, что читаемость вашего кода будет значительно улучшена по сравнению с кодом в вашем вопросе.

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

Смотрите также этот вопрос

Мой метод

    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);
Другие вопросы по тегам