如何使EF使用字符串concat构建更新SQL

本文关键字:concat 构建 更新 SQL 字符串 何使 EF | 更新日期: 2023-09-27 18:14:25

. NET MVC 4/EF 5 web应用程序的数据库,我有一个表的评论列,我想连接新的评论。在传统的T-SQL中,我会这样写:

UPDATE MyTable SET Comments = 'Hi' + CHAR(13)+CHAR(10) + Comments WHERE ID = 2

我发现使用EF的方法linq (uow +存储库模式——我很遗憾),我必须首先查询Comments的当前值,并将我的新注释添加到它:

StringBuilder displayComment = new StringBuilder();
var item = uow.MyRepos.Where(i => i.ID == 2);
item.Comments = displayComment.Append("Hi")
                              .Append(Environment.NewLine)
                              .Append(item.Comments)
                              .ToString();
uow.Save();

是否有任何方法可以在不需要查询DB的情况下编写此更新?我想让EF以某种方式生成上面的t-sql。评论可能很长,我不在乎它包含什么。性能是一个问题。

如何使EF使用字符串concat构建更新SQL

标准更新设置字段,我假设您需要保留该功能,否则您将无法编辑以前的注释。这意味着你有一个特殊的更新情况。我会在MyTable的存储库中添加一个方法来运行您想要的sql:

public int PrependComment(int id, String comment)
{
   String sql = "UPDATE MyTable SET Comments = {0} + 
      CHAR(13)+CHAR(10) + Comments WHERE ID = {1}";
   return dbContext.Database.ExecuteSqlCommand(sql, comment, id);
}

我认为你唯一可以玩的是使用DbCommandInterceptor。您可以拦截每个非查询执行的命令(更新、删除、插入),并在实际执行命令之前修改命令文本。这里的代码只是为了理解如何做到这一点。您可以重构它以方便使用:

public class PrependTextInterceptor : DbCommandInterceptor
{        
    const string table = "MyTable";
    const string column = "Comments";
    public override void NonQueryExecuting(DbCommand command, System.Data.Entity.Infrastructure.Interception.DbCommandInterceptionContext<int> interceptionContext)
    {
        command.CommandText = Regex.Replace(command.CommandText, 
                              string.Format(@"(?i:(?<=^UPDATE '[.+']'.'[{0}']'r'nSET .* '[{1}'] = ).+?(?=(,|'r'n)))", table, column), "$& + " + column);            
        base.NonQueryExecuting(command, interceptionContext);            
    }
}
//Usage
DbInterception.Add(new PrependTextInterceptor());
//after this every time you set the Comments property 
//it will be understood as prepending    
item.Comments = displayComment.Append("Hi")
                              .Append(Environment.NewLine).ToString();

只是一个注意,如果你加载你的item正常,它的Comments属性也应该加载。因此,您失去了在前置之前不首先加载它的好处。我认为你需要使用Attach,你只需要知道ID能够更新它而不加载它(就像通过查询context.Set<MyTable>().Single(e => e.ID == 2), Comments那么应该是肯定加载)。