12

Mam najpierw projekt aplikacji internetowej MVC z kodem Entity Framework. W tym projekcie zamierzam użyć ogólnych repozytoriów i wzorów jednostek pracy. Ponadto chcę użyć procedur przechowywanych do uzyskania listy przez i metod get-list.Jak mogę użyć procedury składowanej + repozytorium + wzorce jednostek pracy w Entity Framework?

Jak korzystać z procedur składowanych z wzorami ogólnych repozytoriów i jednostek pracy?

+0

Podejście kodu pierwszego nie obsługuje za pomocą procedur przechowywanych jeszcze - to funkcja, która będzie przychodzić w Entity Framework V6, który ma być wydany w tym roku –

+0

@marc_s: Aby być precyzyjnym, nie obsługuje * mapowania * procedur składowanych na metody .NET. * Używanie * ich i zawijanie wywołania do 'SqlQuery' (z nazwą SP jako parametrem) do metody repozytorium jest możliwe (http://msdn.microsoft.com/en-US/data/jj592907). Nie jest to doskonały sposób, ale możliwy ... – Slauma

+0

@Slauma - Właściwie myślę, że masz na myśli to, że nie obsługuje mapowania modelu EF do procedur przechowywanych. Jest to rozwiązywane w wersji 6. Możesz zmapować przechowywany proc na obiekcie i możesz odwzorować ten sproc na metodę (tj. Owinąć ją). Ale to przede wszystkim ręczny proces w kodzie. –

Odpowiedz

20

do swojej rodzajowego repozytorium dodać

public IEnumerable<T> ExecWithStoreProcedure(string query, params object[] parameters) 
{ 
     return _context.Database.SqlQuery<T>(query, parameters); 
} 

I wtedy można nazwać to z każdym unitofwork/repozytorium jak

IEnumerable<Products> products = 
      _unitOfWork.ProductRepository.ExecWithStoreProcedure(
      "spGetProducts @bigCategoryId", 
      new SqlParameter("bigCategoryId", SqlDbType.BigInt) { Value = categoryId } 
    ); 
+0

dziękuję za odpowiedź, ale pytanie w drugiej części twojej odpowiedzi implementujemy metodę ExecWithStoreProcedure w repozytorium genetycznym, myślę, że używając jednostki pracy muszę to powiedzieć _unitOfWork.ProductRepository.ExecWithStoreProcedure (nasze zapytanie, parametry []); jeśli myślę źle peleas powiedzieć mi –

+0

Niestety masz rację, powinno być '_unitOfWork.ProductRepository.ExecWithStoreProcedure' T będzie pochodzić z' ProductRepository: GenericRepository ' – sunil

+5

Ale co, jeśli masz SP, że nie zwraca podmiotowi twoje mapy repozytorium? Na przykład mój SP może zwrócić dane, które łączy tabele lub po prostu zwraca wartość całkowitą zwaną "Wynik".W tym scenariuszu użycie powyższego przykładu z jednostką produktu byłoby niewystarczające i złamałoby zasadę podziału na interfejsy. Jakieś pomysły? –

7

Opracowanie na odpowiedź przez @sunil i mojego komentarza na nim, stworzyłem klasa przeznaczona specjalnie do obsługi procedur przechowywanych. Jak wspomniałem w swoim komentarzu, jeśli spodziewasz się, że inny model będzie pochodził z SP niż ten określony w twoim repozytorium, masz problemy. Ponadto, jeśli chcesz tylko uruchomić SP, to łamiesz ISP. Poniżej znajduje się moje rozwiązanie. Nie jest to definitywne i może być łatwo rozszerzone lub zmienione w zależności od potrzeb.

public class ProcedureManager : IProcedureManager 
{ 
    internal DbContext Context; 

    public ProcedureManager(DbContext context) 
    { 
     Context = context; 
    } 

    //When you expect a model back (async) 
    public async Task<IList<T>> ExecWithStoreProcedureAsync<T>(string query, params object[] parameters) 
    { 
     return await Context.Database.SqlQuery<T>(query, parameters).ToListAsync(); 
    } 

    //When you expect a model back 
    public IEnumerable<T> ExecWithStoreProcedure<T>(string query) 
    { 
     return Context.Database.SqlQuery<T>(query); 
    } 

    // Fire and forget (async) 
    public async Task ExecuteWithStoreProcedureAsync(string query, params object[] parameters) 
    { 
     await Context.Database.ExecuteSqlCommandAsync(query, parameters); 
    } 

    // Fire and forget 
    public void ExecuteWithStoreProcedure(string query, params object[] parameters) 
    { 
     Context.Database.ExecuteSqlCommand(query, parameters); 
    } 
} 
1

Dla Generic Repository Dodaj to:

public IEnumerable<TEntity> GetdataFromSqlcommand(string command, System.Data.SqlClient.SqlParameter[] parameter) 
    { 
     StringBuilder strBuilder = new StringBuilder(); 
     strBuilder.Append($"EXECUTE {command}"); 
     strBuilder.Append(string.Join(",", parameter.ToList().Select(s => $" @{s.ParameterName}"))); 

     return Context.Set<TEntity>().FromSql(strBuilder.ToString(), parameter); 
    } 

A wystarczy wysłać zapisaną nazwę procedury i szereg parametrów:

public IEnumerable<MainData> GetMainData(Param query) 
{ 
    var param1 = new SqlParameter("param1", query.param1); 
    var param2 = new SqlParameter("param2", query.param2); 
    return GetdataFromSqlcommand("StoredProcedurename", parameter: new[] { param1, param2 }).ToList(); 
} 
0

to działało w moim przypadku

IQueryable<Cm_Customer> customerQuery = _uow.SqlQuery<Cm_Customer>(@" DECLARE @UserId INT = {0} 
               EXEC Cm_GetCustomersByUserId @UserId", filter.UserId).AsQueryable(); 

i unito Metoda fwork

public IEnumerable<TEntity> SqlQuery<TEntity>(string sql, params object[] parms) 
{ 
    return _context.Database.SqlQuery<TEntity>(sql, parms); 
}