加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

.net – EF Code First从IQueryable中删除批次?

发布时间:2021-02-25 14:10:46 所属栏目:MsSql教程 来源:网络整理
导读:我知道这在LINQ-to-SQL中是可行的,而且我看到了点点滴滴让我相信它在EF中是可能的.那里有扩展可以做这样的事情: var peopleQuery = Context.People.Where(p = p.Name == "Jim");peopleQuery.DeleteBatch(); DeleteBatch只是挑选了peopleQuery并创建了一个

我知道这在LINQ-to-SQL中是可行的,而且我看到了点点滴滴让我相信它在EF中是可能的.那里有扩展可以做这样的事情:

var peopleQuery = Context.People.Where(p => p.Name == "Jim");

peopleQuery.DeleteBatch();

DeleteBatch只是挑选了peopleQuery并创建了一个单独的SQL语句来删除所有相应的记录,然后直接执行查询,而不是将所有这些实体标记为删除并让它逐个执行.我以为我在下面的代码中找到了类似的东西,但它立即失败,因为实例无法转换为ObjectSet.有谁知道如何解决这个问题与EF Code First一起工作?或者知道在哪里有这样做的例子?

public static IQueryable<T> DeleteBatch<T>(this IQueryable<T> instance) where T : class
{
    ObjectSet<T> query = instance as ObjectSet<T>;
    ObjectContext context = query.Context;

    string sqlClause = GetClause<T>(instance);
    context.ExecuteStoreCommand("DELETE {0}",sqlClause);

    return instance;
}

public static string GetClause<T>(this IQueryable<T> clause) where T : class
{
    string snippet = "FROM [dbo].[";

    string sql = ((ObjectQuery<T>)clause).ToTraceString();
    string sqlFirstPart = sql.Substring(sql.IndexOf(snippet));

    sqlFirstPart = sqlFirstPart.Replace("AS [Extent1]","");
    sqlFirstPart = sqlFirstPart.Replace("[Extent1].","");

    return sqlFirstPart;
}

解决方法

实体框架不支持批处理操作.我喜欢代码解决问题的方式,但即使它完全符合您的要求(但对于ObjectContext API),这是一个错误的解决方案.

为什么是错误的解决方案?

它仅在某些情况下有效.它肯定不适用于任何高级映射解决方案,其中实体映射到多个表(实体拆分,TPT继承).我几乎可以肯定,由于查询的复杂性,您可以找到另一种无法工作的情况.

它使上下文和数据库不一致.这是针对DB执行的任何SQL的问题,但在这种情况下,SQL是隐藏的,而使用您的代码的另一个程序员可能会错过它.如果删除同时加载到上下文实例的任何记录,该实体将不会被标记为已删除并从上下文中删除(除非您将该代码添加到DeleteBatch方法 – 如果删除的记录实际映射,这将特别复杂到多个实体(表拆分)).

最重要的问题是修改EF生成的SQL查询以及您对该查询所做的假设.您期望EF将查询中使用的第一个表命名为Extent1.是的它现在真的使用该名称,但它是内部EF实现.它可以在EF的任何微小更新中改变.围绕任何API的内部构建自定义逻辑被认为是一种不好的做法.

因此,您必须使用SQL级别的查询,以便可以在@mreyeros显示时直接调用SQL查询,并避免此解决方案中的风险.您将不得不处理表和列的真实名称,但这是您可以控制的(您的映射可以定义它们).

如果您不认为这些风险很重要,您可以对代码进行小的更改,使其在DbContext API中起作用:

public static class DbContextExtensions
{
    public static void DeleteBatch<T>(this DbContext context,IQueryable<T> query) where T : class
    {
        string sqlClause = GetClause<T>(query);
        context.Database.ExecuteSqlCommand(String.Format("DELETE {0}",sqlClause));
    }

    private static string GetClause<T>(IQueryable<T> clause) where T : class
    {
        string snippet = "FROM [dbo].[";

        string sql = clause.ToString();
        string sqlFirstPart = sql.Substring(sql.IndexOf(snippet));

        sqlFirstPart = sqlFirstPart.Replace("AS [Extent1]","");
        sqlFirstPart = sqlFirstPart.Replace("[Extent1].","");

        return sqlFirstPart;
    }
}

现在,您将以这种方式调用批量删除:

context.DeleteBatch(context.People.Where(p => p.Name == "Jim"));

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读