【问题标题】:Using post to update existing records in a database使用 post 更新数据库中的现有记录
【发布时间】:2020-04-13 01:57:25
【问题描述】:

我正在编写一个在表中插入和更新记录的 API 控制器。我可以很容易地将新项目插入数据库,但我很难理解如何更新现有记录。我目前的解决方案是查询与请求具有相同 UserName 和 DeviceId 的记录数。如果计数 > 0,那么我们执行更新查询。否则,我们执行插入查询。但我不确定如何从 countQuery 返回记录数。另外,我宁愿不为此使用 patch 或 put 方法。我想要 post 方法中的所有逻辑。感谢您的帮助!

public BaseResponse Post([FromBody]PendingAttachmentRequest pending)
    {
        var datasource = "";
        var appVersion = "";
        var sessionId = "";
        var updateQuery = "UPDATE PendingAttachments SET PendingCount = @PendingCount,LastUpdated = @LastUpdated,DataSource = @DataSource WHERE DeviceId = @deviceId AND WHERE UserName = @userName";
        var countQuery = "SELECT count(*) PendingAttachments WHERE DeviceId = @DeviceId AND WHERE UserName = @UserName";
        MobileCompleteServer.Helpers.Connection.GetHeaderInfo(out sessionId, out datasource, out appVersion);
        using (var onbaseConnection = MobileCompleteServer.Helpers.Connection.Connect(sessionId, datasource))
        {
            var connectionString = System.Configuration.ConfigurationManager.AppSettings["ConnectionString"];
            try
            {
                using (SqlConnection sqlConnection = new SqlConnection(connectionString))
                {
                    sqlConnection.Open();
                    using (SqlCommand comm = new SqlCommand(countQuery, sqlConnection))
                    {
                        if (/*how to check if the result of countQuery is > 0*/)
                        {
                            using (SqlCommand sqlComm = new SqlCommand(updateQuery, sqlConnection))
                            {
                                sqlComm.CommandType = System.Data.CommandType.Text;
                                //replace that row with request body
                                sqlComm.Parameters.Add(new SqlParameter("@DataSource", pending.DataSource));
                                sqlComm.Parameters.Add(new SqlParameter("@LastUpdated", pending.LastUpdated));
                                sqlComm.Parameters.Add(new SqlParameter("@PendingCount", pending.PendingCount));
                                sqlComm.Parameters.Add(new SqlParameter("@DeviceId", pending.DeviceId));
                                sqlComm.Parameters.Add(new SqlParameter("@UserName", pending.UserName));
                            }
                        }
                        using (SqlCommand sqlCommand = new SqlCommand("sp_InsertPendingAttachments", sqlConnection))
                        {
                            sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
                            sqlCommand.Parameters.Add(new SqlParameter("@DataSource", pending.DataSource));
                            sqlCommand.Parameters.Add(new SqlParameter("@UserName", pending.UserName));
                            sqlCommand.Parameters.Add(new SqlParameter("@DeviceId", pending.DeviceId));
                            sqlCommand.Parameters.Add(new SqlParameter("@PendingCount", pending.PendingCount));
                            sqlCommand.Parameters.Add(new SqlParameter("@LastUpdated", pending.LastUpdated));
                            sqlCommand.ExecuteNonQuery();
                        }

                    }
                }
                return new BaseResponse();
            }
            catch (Exception e)
            {
                if (e.Message == Constants.SessionNotFound)
                {
                    return new BaseResponse
                    {
                        Exception = Constants.SessionNotFound,
                        ExceptionStackTrace = e.ToString()
                    };
                }
                else
                {
                    return new BaseResponse
                    {
                        Exception = Constants.PendingAttachmentError,
                        ExceptionStackTrace = e.ToString()
                    };
                }
            }
        }
    }

【问题讨论】:

  • 从技术上讲,可以使用 POST 更新记录。但在 REST 世界中,这是异端邪说。使用 PUT 和 PATCH。 PUT 替换所有值,PATCH 更新某些值。
  • 感谢您的信息。我想使用补丁,但在客户端我只能发送发布请求,因为我们不知道此时记录是否存在。如何在不从客户端发送补丁请求的情况下执行补丁方法?

标签: c# asp.net-web-api sqlcommand asp.net-apicontroller


【解决方案1】:

如果您不关心有多少记录,而只想检查表中是否至少存在一条记录,请使用“存在”。它肯定会提高查​​询性能。所以你只需要检查真假条件:https://docs.microsoft.com/en-us/sql/t-sql/language-elements/exists-transact-sql?view=sql-server-ver15

您还需要使用“ExecuteReader”/“ExecuteScalar”方法:Check if a record exists in the database

尝试使用存储库设计模式,它将您的数据访问逻辑和域逻辑分开,它还有助于使您的代码可测试。另外,您的方法一次做很多事情,因此违反了单一责任原则。

【讨论】:

  • 感谢您的反馈。快速提问。使用 ExecuteScalar 和 ExecuteReader 的方法有区别吗?
  • ExecuteScalar 是一个方便的函数,当您只需要一个 Cell 值(即一列和一行)时。当我们将 ExecuteScalar 用于具有多列和多行的 SELECT 语句时会发生什么?:答案是肯定的,我们可以使用它,但作为它的行为,它将返回第一个单元格,即第一行和第一列。 ExecuteReader 严格用于从 SQL 查询或存储过程(即 SELECT 操作)中获取记录。在您的情况下,如果您只使用“Exists”功能来改进您的查询,那么您可以使用 executescalar。
【解决方案2】:

您是否还没有一个方法为GET 端点提供deviceIduserName 作为参数?如果不创建它并调用该方法来检查是否存在,并且根据结果,您可以调用updateinsert 处理程序。这样一来,您的 API 将更加RESTful 和模块化,因此与业务逻辑的耦合更少并且更可测试。

【讨论】:

  • 您好,感谢您的回答。澄清一下,你是说我在 get 方法中调用 post 和 patch 方法?
  • 是的,但是,理想情况下,我会更进一步,创建一个存储库类,例如具有.Read()、.Insert()、.Update() 等方法的“DBAttachmentsRepository”。控制器方法应该只调用这些方法,而不是让数据库操作代码到处都是。这样您就可以从多个控制器方法调用 myDBAttachmentsRepository.Read(deviceId, userName)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多