12

私はEntity Frameworkコードを持つMVC Webアプリケーションプロジェクトを最初に持っています。このプロジェクトでは、ジェネリックリポジトリと作業単位パターンを使用します。私はまた、get-listメソッドでリストを取得するためのストアドプロシージャを使用したいと思います。Entity Frameworkでストアドプロシージャ+リポジトリ+作業単位のパターンを使用するにはどうすればよいですか?

ジェネリックリポジトリと作業単位パターンでストアドプロシージャを使用するにはどうすればよいですか?あなたの一般的なリポジトリが

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

を追加して、あなたは私が作成し、@sunilによって答え、その上に私のコメントにエラボレーション

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

は、コードの最初のアプローチは、まだストアドプロシージャを使用してサポートしていません - それはアウト –

+0

@marc_s今年後半ことになってEntity Frameworkのバージョン6に来るということだ機能です。正確には、 *マッピング*ストアドプロシージャを.NETメソッドに対応していません。 *それらを使用し、 'SqlQuery'(パラメータとしてSP名を持つ)の呼び出しをリポジトリメソッドにラップすることは可能です(http://msdn.microsoft.com/en-US/data/jj592907)。完璧な方法ではありませんが、可能です。 – Slauma

+0

@Slauma - 実際には、EFモデルをストアドプロシージャにマッピングすることをサポートしていないと思います。これはv6で取り上げられています。ストアドプロシージャをオブジェクトにマップすることができ、そのsprocをメソッドにマップすることができます(つまり、ラップします)。しかし、これは主に最初のコードの手作業です。 –

答えて

20

特にストアドプロシージャを処理するためのクラスです。私のコメントで述べたように、あなたのリポジトリで指定されたものとは異なるモデルがSPから戻ってくることを期待している場合は、問題があります。また、SPを実行したいだけなら、あなたはISPを壊すでしょう。以下は私の解決策です。決して確定的なものではなく、お客様のニーズに合わせて簡単に拡張または変更することができます。

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); 
    } 
} 
+0

あなたの答えはありがたいですが、答えの2番目のセクションの質問私たちはgenricリポジトリでExecWithStoreProcedureのメソッドを実装しています。私はこれを言う必要がある作業ユニットを使うと思います_unitOfWork.ProductRepository.ExecWithStoreProcedure(私たちのクエリ、parametrs []); GenericRepository ' –

+0

は申し訳ありませんが、私を言うあなたは正しい、それは ' _unitOfWork.ProductRepository.ExecWithStoreProcedure' TはProductRepository 'から来るべきだと思う場合あなたのリポジトリは?たとえば、私のSPはテーブルを結合するデータを返すか、単に「Result」という整数値を返します。そのシナリオでは、Productエンティティで上記の例を使用することは不十分であり、Interface Segregation Principleを破ります。何か案は? – sunil

+5

しかし、どのような場合は、エンティティを返さないSPを持っている:私は間違ってpeleasが –

7

ような任意のUnitOfWork /リポジトリでそれを呼び出すことができますへ

1

一般的なリポジトリは、この追加の場合:

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

をそして、あなただけのストアドプロシージャの名前とパラメータの配列を送信する必要があります。これは私の場合で働いている

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

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

と単位fwork方法

public IEnumerable<TEntity> SqlQuery<TEntity>(string sql, params object[] parms) 
{ 
    return _context.Database.SqlQuery<TEntity>(sql, parms); 
} 
関連する問題