追加パラメーターを持つLinq To Sqlでのストアドプロシージャの使用
-
07-07-2019 - |
質問
私は非常に大きな問題を抱えており、インターネット上で私の問題を抱えている他の人を見つけることができないようです。 StackOverflowが私を助けることを願っています...
ASP.NET MVCアプリケーションを記述しており、データストアとしてLinq To Sqlを使用したリポジトリコンセプトを使用しています。ビューから行を選択することに関して、すべてがうまく機能しています。そして、非常に基本的なビジネスルール制約をトラップします。ただし、削除、挿入、および更新のストアドプロシージャマッピングに問題があります。説明させてください:
私たちのDBAは、すべてのストアドプロシージャにビジネスロジックを組み込むことに多大な労力を費やしているので、最後に心配する必要はありません。確かに、私は基本的な検証を行いますが、彼はデータの整合性と競合する日付制約などを管理します。私が直面している問題は、すべてのストアドプロシージャ(およびすべて)に5つの追加パラメーター(挿入用に6 )私に情報を提供します。アイデアは、何かが壊れたときに、データベースから適切な情報をユーザーに促すことができるというものです。
例:
sp_AddCategory(
@userID INT,
@categoryName NVARCHAR(100),
@isActive BIT,
@errNumber INT OUTPUT,
@errMessage NVARCHAR(1000) OUTPUT,
@errDetailLogID INT OUTPUT,
@sqlErrNumber INT OUTPUT,
@sqlErrMessage NVARCHAR(1000) OUTPUT,
@newRowID INT OUTPUT)
上記のストアドプロシージャから、最初の3つのパラメーターは、「作成」に使用される唯一のパラメーターです。カテゴリレコード。残りのパラメーターは、メソッド内で何が起こったかを単に伝えるために使用されます。ストアドプロシージャ内でビジネスルールが破損している場合、ビジネスルールが破損しているときにSQL 'RAISEERROR'キーワードを使用しません。代わりに、彼はOUTPUTパラメーターを使用して、エラーに関する情報を返します。彼は、データベース内のすべてのストアドプロシージャに対して、更新と削除を含めてこれを行います。 「Get」呼び出しはすべて、カスタムビューを使用して実行されます。これらはすべてテストされており、データの品質を確保するためにさまざまなシナリオをすべてトラップするためのビジネスロジックを追加する必要がないため、仕事は簡単になります。
私が言ったように、私はLinq To Sqlを使用していますが、今は問題に直面しています。問題は、私の「カテゴリ」がモデルオブジェクトには、CategoryID、CategoryName、UserId、IsActiveという4つのプロパティがあります。挿入用のプロパティのマッピングを開始するためにデザイナーを開いたとき、モデルオブジェクトに追加しない限り、追加のパラメーターを説明するための(簡単な)方法が実際にはないことがわかりました。
理論的に私がしたいことはこれです:
// note: Repository Methods
public void AddCategory(Category category)
{
_dbContext.Categories.InsertOnSubmit(category);
}
public void Save()
{
_dbContext.SubmitChanges();
}
そして、CategoryControllerクラスから次のことを行うだけです:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
var category = new Category();
try
{
UpdateModel(category); // simple validation here...
_repository.AddCategory(category);
_repository.Save(); // should get error here!!
return RedirectToAction("Index");
}
catch
{
// manage friendly messages here somehow... (??)
// ...
return View(category);
}
}
Linq to Sqlを使用してこれを管理する最良の方法は何ですか?私は(個人的に)これらのすべての追加プロパティを各モデルオブジェクトに追加することは理にかなっているとは思いません...たとえば、「Get」にはエラーが発生することはなく、リポジトリメソッドからエラーが返されないようにしますGet呼び出しのオブジェクトのタイプですが、CUD呼び出しのオブジェクトの別のタイプを受け入れます。
更新:私の解決策! (2009年12月1日)
問題を解決するために私がしたことは次のとおりです。すべてのリポジトリで「Save()」メソッドを削除しました。代わりに、各リポジトリに「Update()」メソッドを追加し、各CUD(つまり、作成/更新/削除)呼び出しでデータを実際にデータベースにコミットします。
各ストアドプロシージャには同じパラメータがあることを知っていたので、それらを保持するクラスを作成しました。
public class MySprocArgs
{
private readonly string _methodName;
public int? Number;
public string Message;
public int? ErrorLogId;
public int? SqlErrorNumber;
public string SqlErrorMessage;
public int? NewRowId;
public MySprocArgs(string methodName)
{
if (string.IsNullOrEmpty(methodName))
throw new ArgumentNullException("methodName");
_methodName = methodName;
}
public string MethodName
{
get { return _methodName; }
}
}
また、コンストラクターでMySprocArgsを受け入れるMySprocExceptionを作成しました:
public class MySprocException : ApplicationException
{
private readonly MySprocArgs _args;
public MySprocException(MySprocArgs args) : base(args.Message)
{
_args = args;
}
public int? ErrorNumber
{
get { return _args.Number; }
}
public string ErrorMessage
{
get { return _args.Message; }
}
public int? ErrorLogId
{
get { return _args.ErrorLogId; }
}
public int? SqlErrorNumber
{
get { return _args.SqlErrorNumber; }
}
public string SqlErrorMessage
{
get { return _args.SqlErrorMessage; }
}
}
ここですべてがまとめられます...最初の問い合わせで始めた例を使用すると、「AddCategory()」メソッドは次のようになります。
public void AddCategory(Category category)
{
var args = new MySprocArgs("AddCategory");
var result = _dbContext.AddWidgetSproc(
category.CreatedByUserId,
category.Name,
category.IsActive,
ref args.Number, // <-- Notice use of 'args'
ref args.Message,
ref args.ErrorLogId,
ref args.SqlErrorNumber,
ref args.SqlErrorMessage,
ref args.NewRowId);
if (result == -1)
throw new MySprocException(args);
}
コントローラから、次の操作を実行します。
[HandleError(ExceptionType = typeof(MySprocException), View = "SprocError")]
public class MyController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Category category)
{
if (!ModelState.IsValid)
{
// manage friendly messages
return View(category);
}
_repository.AddCategory(category);
return RedirectToAction("Index");
}
}
新しい MySprocException
を管理する秘trickは、HandleError属性を使用して単純にトラップし、MySprocExceptionを理解するページにユーザーをリダイレクトすることです。
これが誰かの助けになることを願っています。 :)
解決
パラメータはデータベースのどのテーブルにも保持されないため、どのLINQクラスにも出力パラメータを追加できるとは思わない。
ただし、次の方法でLINQの出力パラメーターを処理できます。
デザイナーを使用して.dbmlを呼び出すストアドプロシージャを追加します。
コードでストアドプロシージャを呼び出す
using (YourDataContext context = new YourDataContext())
{
Nullable<int> errNumber = null;
String errMessage = null;
Nullable<int> errDetailLogID = null;
Nullable<int> sqlErrNumber = null;
String sqlErrMessage = null;
Nullable<int> newRowID = null;
Nullable<int> userID = 23;
Nullable<bool> isActive=true;
context.YourAddStoredProcedure(userID, "New Category", isActive, ref errNumber, ref errMessage, ref errDetailLogID, ref sqlErrNumber, ref sqlErrMessage, ref newRowID);
}
他のヒント
まだ試したことはありませんが、この記事を見ると、出力パラメーターを返すストアドプロシージャについて話されています。
基本的にストアドプロシージャをLINQ to SQLデザイナーにドラッグすると、作業が自動的に行われます。
dbContext.SubmitChanges();
はENTITY FRAMEWORKでのみ機能します。保存、更新、削除は、シングルストアドプロシージャまたは3つの異なるプロシージャを使用して機能することをお勧めします。