使用 C# 中的 OleDB 更新表行

Det*_*yne 1 c#

我正在开发一个发票管理应用程序,该应用程序从 Access 数据库(现代 .accdb 格式)中提取信息并获取数据工作正常,但是当我尝试更新它时(遵循一些教程,或者我应该说答案,没有任何作用..这段代码有什么问题,它......应该可以工作。

    public int UpdateDBBill(Bill bill)
    {
        using (var connection = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\BC.accdb"))
        using (var command = connection.CreateCommand())
        {
            connection.Open();

            command.CommandType = CommandType.Text;
            command.CommandText = "UPDATE Bills SET Payer = @Payer, Category = @Category, Recipient = @Recipient, Currency = @Currency, Amount = @Amount, IBANOfRecipient = @IBANOfRecipient, Model = @Model, ReferenceNumber = @ReferenceNumber, Description = @Description, DueDate = @DueDate, ForMonth = @ForMonth, Paid = @Paid, DatePaid = @DatePaid WHERE Id = @Id";

            command.Parameters.AddWithValue("@Payer", bill.Payer);
            command.Parameters.AddWithValue("@Category", bill.Category);
            command.Parameters.AddWithValue("@Recipient", bill.Recipient);
            command.Parameters.AddWithValue("@Currency", bill.Currency);
            command.Parameters.AddWithValue("@Amount", bill.amount);
            command.Parameters.AddWithValue("@IBANOfRecipient", bill.IBANOfRecipient);
            command.Parameters.AddWithValue("@Model", bill.Model);
            command.Parameters.AddWithValue("@ReferenceNumber", bill.ReferenceNumber);
            command.Parameters.AddWithValue("@Description", bill.Description);
            command.Parameters.AddWithValue("@DueDate", bill.DueDate);
            command.Parameters.AddWithValue("@ForMonth", bill.ForMonth);
            command.Parameters.AddWithValue("@Paid", bill.Paid);
            command.Parameters.AddWithValue("@DatePaid", bill.DatePaid);
            command.Parameters.AddWithValue("@Id", bill.Id);

            try
            {
                return command.ExecuteNonQuery();
            }
            catch
            {
                return -1;//for error
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

回答:

    public int UpdateDBBill(Bill bill)
    {
        using (var connection = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\BC.accdb"))
        using (var command = connection.CreateCommand())
        {
            connection.Open();

            command.CommandType = CommandType.Text;

            command.CommandText = "UPDATE Bills SET Payer = @Payer, Category = @Category, Recipient = @Recipient, [Currency] = @Currency, Amount = @Amount, IBANOfRecipient = @IBANOfRecipient, [Model] = @Model, ReferenceNumber = @ReferenceNumber, DueDate = @DueDate, ForMonth = @ForMonth, Paid = @Paid, DatePaid = @DatePaid WHERE Id = @Id";
            command.Parameters.Add("@Payer", OleDbType.VarChar).Value = bill.Payer;
            command.Parameters.Add("@Category", OleDbType.VarChar).Value = bill.Category;
            command.Parameters.Add("@Recipient", OleDbType.VarChar).Value = bill.Recipient;
            command.Parameters.Add("@Currency", OleDbType.VarChar).Value = bill.Currency;
            command.Parameters.Add("@Amount", OleDbType.VarChar).Value = bill.GetAmount();
            command.Parameters.Add("@IBANOfRecipient", OleDbType.VarChar).Value = bill.IBANOfRecipient;
            command.Parameters.Add("@Model", OleDbType.VarChar).Value = bill.Model;
            command.Parameters.Add("@ReferenceNumber", OleDbType.VarChar).Value = bill.ReferenceNumber;
            command.Parameters.Add("@DueDate", OleDbType.Date).Value = bill.DueDate.Date;
            command.Parameters.Add("@ForMonth", OleDbType.Date).Value = bill.ForMonth.Date;
            command.Parameters.Add("@Paid", OleDbType.Boolean).Value = bill.Paid;
            command.Parameters.Add("@DatePaid", OleDbType.Date).Value = bill.DatePaid.Date;
            command.Parameters.Add("@Id", OleDbType.Integer).Value = bill.Id;

            try
            {
                int Rows = command.ExecuteNonQuery();
                return Rows;
            }
            catch
            {
                return -1;//for error
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Ste*_*eve 5

对于 OleDb,参数的位置很重要。
OleDb 不会将参数的占位符与参数的名称相关联,而是遵循严格的位置顺序。因此,您的查询是正确的,但是当您将参数添加到集合时,您应该遵循参数占位符的顺序。

command.CommandType = CommandType.Text;
command.CommandText = "UPDATE Bills SET ([Payer] = @Payer, [Category] = @Category, ...) WHERE Id = @Id";
command.Parameters.AddWithValue("@Payer", bill.Payer);
command.Parameters.AddWithValue("@Category", bill.Category);
....
command.Parameters.AddWithValue("@Id", bill.Id);
Run Code Online (Sandbox Code Playgroud)

使用 Access,您可以像为它的大表兄弟 Sql Server 一样命名参数,尽管 OleDb 文档说您应该使用问号作为参数占位符,但是当 OleDb 提供程序将值与占位符相关联时,这些名称会被简单地忽略。

作为旁注,请考虑 AddWithValue 是一种方便但危险的方法。参数类型由传递的值提取,有时这可能会创建“数据类型不匹配异常”或错误的转换(特别是如果您将日期或小数作为字符串传递给 AddWithValue)

请参阅我们可以停止使用 AddWithValue 了吗?

编辑 在聊天中经过长时间的调试会话后,最终问题在不带括号的货币字段中确定。货币是 Access 中的保留字,应该用方括号括起来。这最初并不明显,因为 OP 提出的第一个查询是用方括号正确键入的,但是无论出于何种原因,方括号从查询中消失了。不使用 AddWithValue 的建议是为了避免从日期到字符串然后再返回到字符串的不必要转换......

command.CommandText = "UPDATE Bills SET ([Payer] = @Payer, [Category] = @Category, ...) WHERE Id = @Id";
command.Parameters.Add("@Payer", OleDbType.VarWChar).Value = bill.Payer;
command.Parameters.Add("@Category", OleDbType.VarWChar).Value = bill.Category;
....
command.Parameters.Add("@DueDate", OleDbType.Date).Value = bill.DueDate.Date;
....
command.Parameters.Add("@Id", OleDbType.Integer).Value = bill.Id;
Run Code Online (Sandbox Code Playgroud)