Acck 現在のバージョンの前に、エンティティ クラス用の特別なストアド プロシージャをしばらく作成する必要はありませんでした。そして、それは小さなテーブルにありました。削除を作成しましたが、EF では挿入と更新も作成する必要があることを忘れていました。これを行う簡単な方法を知っている人はいますか?タイピングを楽しみにせずに、これを行う必要があるそれぞれに約30〜50列の約7〜8個のテーブルがあります。
2 に答える
そして、それは小さなテーブルにありました。削除を作成しましたが、EF では挿入と更新も作成する必要があることを忘れていました
この質問で EntityFramework 5.0 にタグを付けたので、なぜ削除のためにストアド プロシージャを生成する必要があるのか よくわかりません。
すべての CRUD (作成、読み取り、削除、更新) は DbContext で行われ、そのための手順を記述する必要はありません。よく整理されたデータベース (PK、FK、適切なインデックスを含む) がある場合は、EF のビューをコンパイルしてさらに良い結果を得ることができるため、ストアド プロシージャを用意する必要はありません。
サンプル コードを参照してください。
DbContext context = new YourContext();
public bool Delete<TEntity>(TEntity entity) where TEntity : class
{
var set = context.Set<TEntity>();
set.Attach(entity);
return true;
}
public bool Add<TEntity>(TEntity entity) where TEntity : class
{
var set = context.Set<TEntity>();
set.Add(entity);
return true;
}
このアプローチを使用する必要さえありません。次の例のように、DbContext.Set を直接使用できます。
void Run()
{
using (DbContext context = new MyContext())
{
//Create a new person to insert
var newItem = new Person() { Name = "Mike"} ;
var set = context.Set<Person>();
set.Add(newItem);
// Returns a record from database with PK = "John"
var itemToDelete = set.Find("John");
set.Remove(itemToDelete);
// This will add the new record, and delete "John" from the Database
context.SaveChanges();
}
}
ご覧のとおり、CRUD のストアド プロシージャは必要ありません。
データベースに関連する他のものにはストアドプロシージャを使用します.EFでは必要ありません:)
これを行う簡単な方法を知っている人はいますか?タイピングを楽しみにせずに、これを行う必要があるそれぞれに約30〜50列の約7〜8個のテーブルがあります。
ここでの要点は、EF を使用する場合、CRUD 操作を処理するためにストアド プロシージャを記述する必要がないことを示すことでした。
あなたはこれを行う簡単な方法を求めました(そして、それらを入力したくないとさえ言いました)私の答えは次のとおりです。
手っ取り早い方法は、何も手続きをしないことです!これは高速で、入力を避けることができます! :)
示されているコードは、ストアド プロシージャを必要とせずに要件を既に処理しています。:)
追加情報
ストアド プロシージャを削除する必要があると考える理由が、関連するエンティティを削除したいためであり、EF がこの状況を処理しないと考えている場合、これは別の問題であり、いくつかの考えられる原因を教えてくれるかもしれません。
1) FK 参照のためにエラーで終了する場合があります。この場合は、こちらをご覧ください。
2)他のエンティティとの関係から1つのエンティティを削除するときに、EFがレコードを物理的に削除したいことを理解できないため、.ChangeStateを削除済みに明示的に変更する必要があるため、エラーが発生する可能性があります。
次の例を見てください。
public static void StudentLeaves(string name)
{
using (var context = new SchoolContext())
{
context.Students.Remove(context.Students.Single(s => s.Name == name));
context.SaveChanges();
}
}
上記の例は、この生徒を削除しますよね? しかし、今2番目の例を見てください
public static void StudantLeaveParticularSchool(string schoolName, string name)
{
using (var context = new SchoolContext())
{
var school = context.Schools.Single(a => a.Nome == schoolName);
school .Students.Remove(context.Students.Single(a => a.Nome == name));
context.SaveChanges();
}
}
次のコードは、 Student を Database から削除するのではなく、関係を削除するだけです!
CodeFirst を使用している場合は、次のように、DeleteCascade を使用することを明示的に指定できます。
modelBuilder
.Entity()
.HasRequired(s => s.Schools)
.WithMany(r => r.Students)
.WillCascadeOnDelete();
更新しました:
ストアド プロシージャを作成する "魔法の" 方法に興味がある方のために、その方法を説明しますが、もう一度言います: ベスト プラクティスで EF を使用している場合は、その必要はありません。 EF を使用して最初に開発を始めたとき、これが必要だと思ったので、数百のストアド プロシージャを瞬く間に生成するいくつかの T4 ファイルを作成しました。しかし、しばらくして、これは EF を使用する場合の正しいアプローチではないことが判明したため、手順を削除し、T4 をプロジェクトから除外したことで、事態ははるかに簡単になりました。
プロシージャを作成するには、T4 ファイルを作成する必要があります。T4 の詳細については、こちら ( http://msdn.microsoft.com/en-us/library/vstudio/bb126247.aspx )を参照してください。
私たちが作成した DELETE 作成 T4 テンプレートをお見せします (これを実行するには、他のベース .tt ファイルが必要になるため、これはサンプルであることを覚えておいてください)。
<#@ template language="C#" debug="true" #>
<#@ output extension=".sql" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.XML" #>
<#@ assembly name="Microsoft.SqlServer.ConnectionInfo" #>
<#@ assembly name="Microsoft.SqlServer.Smo" #>
<#@ assembly name="Microsoft.SqlServer.Management.Sdk.Sfc" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="Microsoft.SqlServer.Management.Smo" #>
<#@ import namespace="Microsoft.SqlServer.Management.Common" #>
<#@ import namespace="System.Runtime.Remoting.Messaging" #>
-- Winsys Solutions
-- Stored Procedure de delete para a tabela <#= this.SchemaName #>.<#= this.TableName #>
CREATE PROCEDURE <#= this.SchemaName #>.<#= this.TableName.Replace("TBWS4_", "PRWS4_") #>_Delete
<# WriteParameterDeclarations(this.Table); #>
AS
BEGIN
DELETE FROM
<#= this.SchemaName #>.<#= this.TableName #>
WHERE
<# WriteWhereClause(this.Table); #>
END
GO
<#@ include file="CommonSqlHelper.tt" #>
<#+
/// <summary>
/// Writes stored procedure parameter declarations for all columns in the
/// primary key and all TIMESTAMP columns of the specified table.
/// </summary>
void WriteParameterDeclarations(Table table)
{
PushIndent(" ");
int parameterIndex = 0;
foreach(Column column in table.Columns)
{
if (column.InPrimaryKey || column.DataType.SqlDataType == SqlDataType.Timestamp)
{
if (parameterIndex > 0)
WriteLine(",");
Write("@{0} {1}", column.Name, GetDataTypeDeclaration(column.DataType));
parameterIndex++;
}
}
PopIndent();
}
#>
<#+
string TableName
{
get { return (string) CallContext.GetData("DeleteStoredProcedure.TableName"); }
}
string SchemaName
{
get { return (string) CallContext.GetData("DeleteStoredProcedure.SchemaName"); }
}
Table Table
{
get { return (Table) CallContext.GetData("DeleteStoredProcedure.Table"); }
}
#>
ヘルパー メソッドは次のとおりです。
/// <summary>
/// Returns a string that contains T-SQL declaration for the specified data
/// type. For string data types this includes maximum length, for numeric
/// data types this includes scale and precision.
/// </summary>
string GetDataTypeDeclaration(DataType dataType)
{
string result = dataType.Name;
switch(dataType.SqlDataType)
{
case SqlDataType.Binary:
case SqlDataType.Char:
case SqlDataType.NChar:
case SqlDataType.NVarChar:
case SqlDataType.VarBinary:
case SqlDataType.VarChar:
result += string.Format("({0})", dataType.MaximumLength);
break;
case SqlDataType.NVarCharMax:
case SqlDataType.VarBinaryMax:
case SqlDataType.VarCharMax:
result += "(max)";
break;
case SqlDataType.Decimal:
case SqlDataType.Numeric:
result += string.Format("({0}, {1})", dataType.NumericPrecision, dataType.NumericScale);
break;
}
return result;
}
/// <summary>
/// Generates where clause for UPDATE and DELETE statements for the specified
/// table.
/// </summary>
void WriteWhereClause(Table table, bool includeAllColumns = false)
{
PushIndent(" ");
int whereIndex = 0;
foreach(Column column in table.Columns)
{
if (column.InPrimaryKey || column.DataType.SqlDataType == SqlDataType.Timestamp || includeAllColumns)
{
if (whereIndex > 0)
WriteLine(" AND");
if (includeAllColumns)
Write("({0} = @{0} OR @{0} IS NULL)", column.Name);
else
Write("{0} = @{0}", column.Name);
whereIndex++;
}
}
PopIndent();
}