Acck 在当前版本之前,我已经有一段时间不用为我的实体类创建一个特殊的存储过程了。然后它在较小的桌子上。我创建了我的删除,很好,但我忘记了 EF 也会让你创建插入和更新。任何人都知道一个快速的方法来做到这一点?我有大约 7-8 张桌子,每张桌子大约有 30-50 列,我需要这样做,而不是期待打字。
2 回答
在 SSMS 工具中创建 CRUD 存储过程非常棒(也是众多功能之一)。http://www.ssmstoolspack.com/
然后它在较小的桌子上。我创建了我的删除,很好,但我忘记了 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 不需要它们 :)
任何人都知道一个快速的方法来做到这一点?我有大约 7-8 张桌子,每张桌子大约有 30-50 列,我需要这样做,而不是期待打字。
这里的重点是表明您在使用 EF 时不需要编写存储过程来处理 CRUD 操作。
您要求快速执行此操作(甚至提到您不想输入它们),我的回答是:
更快的方法是不做任何程序!这很快,避免打字!:)
演示的代码已经处理了您的要求,无需任何存储过程。:)
添加信息
如果您认为需要删除存储过程的原因是因为您想删除相关实体并且您认为 EF 无法处理这种情况,那么这是一个不同的问题,我可能会告诉您一些可能的原因:
1)可能因为FK引用而导致错误结束,在这种情况下,请看这里
2)可能是因为当您从与其他实体的关系中删除一个实体时导致错误,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();
}
}
上面的例子会删除这个学生,对吧?但是现在看第二个例子
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,它只会删除关系!
如果你使用 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();
}