在重写删除时,可以轻松地神奇地生成更新并插入存储过程

时间:2013-05-15 20:40:15

标签: entity-framework entity-framework-5

Acck我没有必要在当前版本之前的一段时间内为我的实体类创建一个特殊的存储过程。然后它在较小的桌子上。我创建了我的删除,非常好,但我忘了EF让你创建插入和更新。有人知道快速的方法吗?我有大约7-8个表,每个表需要大约30-50列,而不是期待打字。

2 个答案:

答案 0 :(得分:2)

在SSMS工具中创建CRUD存储过程非常棒(并且是许多功能之一)。 http://www.ssmstoolspack.com/

答案 1 :(得分:1)

  

然后是小桌子。我创建了删除,非常好,但我忘了 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列,而不是期待打字。< / p>

这里的重点是表明在使用EF时不需要编写存储过程来处理CRUD操作。

你要求快速做到这一点(甚至提到你不想输入它们)我的答案是:

更快的方法是不做任何程序!这很快,避免打字!:)

演示的代码已经处理了您的需求,无需任何存储过程。 :)

添加信息

如果您认为需要删除存储过程的原因是因为您想要删除相关实体而您认为EF无法处理此问题,那么这是一个不同的问题,我可能会告诉您一些可能的原因:

1)也许你因为FK引用而以错误告终,在这种情况下,请查看here

2)可能的错误造成的,因为当你与其他实体的关系移除一个实体,EF不会想要做fisically删除记录明白,你需要excplicity改变.ChangeState到已删除。

参加这个考试:

public static void StudentLeaves(string name)
{
    using (var context = new SchoolContext())
    {
        context.Students.Remove(context.Students.Single(s => s.Name == name));
        context.SaveChanges();
    }
}

上面的例子会删除这个学生吗?但是noow看看第二个例子

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

以下代码不会从数据库中删除学生,它只会 删除关系!

如果您正在使用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();
}