我正在尝试更新 Access 文件 (.accdb) 中的记录。我正在尝试使用 .net OleDbCommand 和 OleDbParameters。我还尝试使用通用模型并将所有命令和参数存储在 System.Data.Common 抽象等效项中,以便我可以轻松切换到 SQL Server(我确实打算这样做)
所以这里是实际使用的命令
编辑 2/2/2013 - 晚上 9:10 command.ExecuteNonQuery 在名为 ExecuteNonQuery() 的方法中 connectionString 和命令在 DataAccess 类构造函数中定义
public class DataAccess
{
private string connectionString;
private DbConnection connection;
private DbCommand command;
private DbDataReader reader;
private DataTable data;
public DataAccess()
{
connectionString = ConfigurationSettings.AppSettings["ConnectionString"];
switch (ConfigurationSettings.AppSettings["DataBaseType"])
{
case "oledb":
connection = new OleDbConnection(connectionString);
command = new OleDbCommand(string.Empty, (OleDbConnection)connection);
break;
case "SQL":
connection = new SqlConnection(connectionString);
command = new SqlCommand(string.Empty, (SqlConnection)connection);
break;
default:
break;
}
}
public void ExecuteNonQuery(string SQL, params DbParameter[] parameters)
{
command.CommandType = CommandType.Text;
command.CommandText = SQL;
command.Parameters.AddRange(parameters);
try
{
command.Connection.Open();
try
{
command.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
command.Connection.Close();
}
}
catch (Exception ex)
{
throw ex;
}
}
public DbParameter NewParameter(string name, object value)
{
DbParameter param;
switch (ConfigurationSettings.AppSettings["DataBaseType"])
{
case "oledb":
param = new OleDbParameter(name, value);
break;
case "SQL":
param = new SqlParameter(name, value);
break;
default:
param = null;
break;
}
return param;
}
这些是 App.Config 文件中的属性
<add key="DataBaseType" value="oledb"/>
<add key="ConnectionString" value="Provider=Microsoft.ACE.OLEDB.12.0;Data Source=data.accdb"/>
现在的问题是,当在更新语句中使用参数时,更新永远不会发生,也永远不会抛出错误。这是它的代码。
编辑 2/2/2013 - 晚上 9:10 函数 DataAccess.NewParameter 在第一个代码块中
DALayer.ExecuteNonQuery("UPDATE TileTypes SET Title = @Title, Picture = @Picture, Color = @Color WHERE ID = @ID",
DALayer.NewParameter("@Title", titleTextBox.Text.Trim()),
DALayer.NewParameter("@Picture", typePictureBox.ImageLocation),
DALayer.NewParameter("@Color", colorButton.BackColor.ToArgb()),
DALayer.NewParameter("@ID", id));
我已将查询复制到 access 中,并将所有参数名称替换为正在传递的实际数据,这工作正常。我尝试将 SQL 文本中的所有参数替换为 ?字符无效。我试过将所有表名和列名括在方括号 [] 中也没有效果。
- ID 是一个自动编号字段
- 标题是一个文本字段
- 图片是文本字段
- Color 是一个长整型字段
这是直接从 Visual Studio 监 window 口中的参数复制的一些示例数据:
- “编辑”(标题)
- -1(颜色)
- “data\images\Edit_000000.jpg”(图片)
- 740(身份证)
该 ID 确实存在于数据库中,并且在执行查询后未更改。
编辑 2/2/2013 - 晚上 9:10 我不确定如何检查哪个数据库实际上正在更新,我唯一能想到的是使用相同的连接字符串和连接对象我用相同的 ExecuteNonquery 方法做了一个插入语句并且它在我正在查看的数据库中工作.更新语句像这样工作得很好(没有参数):
DALayer.ExecuteNonQuery("UPDATE TileTypes SET Title = '" + titleTextBox.Text +
"', Color = " + colorButton.BackColor.ToArgb() + ", Picture = '" +
imageLocation + "' WHERE ID = " + id);
编辑 2/2/2013 - 晚上 9:41 我已经使用 everything.exe 在我的计算机上搜索我计算机上的所有 data.accdb 文件,除了原始文件之外,我没有发现任何实际的 .accdb 文件,但我确实找到了这些 .lnk 文件,我不相信他们可以改变这个过程,但我还是要提一下
数据.accdb.LNK
最佳答案
您尝试做的是我过去做过的事情,但允许连接到 OleDB(例如 Access、Visual FoxPro 等)、SQL-Server、SyBase SQLAnywhere,也许我的实现可能对您有所帮助。首先,您将用于连接的每个元素都在一个公共(public)接口(interface)上工作,例如 IDbConnection、IDbCommand、IDbParameter 等。
我发布的以下是我最初构建这种多数据库连接类型的一小部分。我已经剥离了一堆,并没有实际测试这个剥离的版本,但它应该是你运行的一个很好的基准。
前提是基线“MyConnection”几乎像一个抽象,但具有属性和一些“通用”方法,这些方法将存在于 EITHER 子类定义下。由此可见,每一个函数和参数类型都是基于“I”接口(interface),而不是特定的。但是,每个派生对象都将创建自己的专有类型。这消除了“案例”一切的需要。希望这对您的数据 Access 层开发有所帮助。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
// for OleDB (Access, VFP, etc)
using System.Data.OleDb;
// for SQL-Server
using System.Data.SqlClient;
namespace DataMgmt
{
public class MyConnection
{
// no matter the connection to server, it will require some "handle"
// that is of type "IDbConnection"
protected IDbConnection sqlConnectionHandle;
// when querying, ANY query could have an exception that needs to have
// possible further review for handling
public Exception LastException
{ get; protected set; }
// When calling an execute command (select, insert, update, delete),
// they all can return how many rows affected
public int RowsAffectedByQuery
{ get; protected set; }
// different databases could have different connection strings. Make
// virtual and throw exception so sub-classed must return proper formatted.
public virtual string GetConnectionString()
{ throw new Exception("GetConnectionString() method must be overridden."); }
// each has its own "IDbConnection" type too
protected virtual IDbConnection SQLConnectionHandle()
{ return sqlConnectionHandle; }
public virtual IDbCommand GetSQLDbCommand()
{ throw new Exception("GetSQLDbCommand() method must be overridden."); }
// generic routine to get a data parameter...
public virtual IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ throw new Exception("AddDbParmSpecificValue() method must be overwritten per specific connection."); }
// generic "Connection" since they are all based on IDbCommand...
public override bool SQLConnect()
{
// pre-blank exception in case remnant from previous activity
LastException = null;
if (sqlConnectionHandle.State != System.Data.ConnectionState.Open)
try
{
// if not open, always make sure we get updated connection string
// if ever changed by some other "unknown" condition...
sqlConnectionHandle.ConnectionString = GetConnectionString();
sqlConnectionHandle.Open();
}
catch (Exception ex)
{
// Preserve in generic sqlException" property for analysis OUTSIDE this function
LastException = ex;
}
// if NOT connected, display message to user and set error code and exception
if (sqlConnectionHandle.State != System.Data.ConnectionState.Open)
LastException = new Exception("Unable to open database connection.");
// return if it IS successful at opening the connection (or was already open)
return sqlConnectionHandle.State == System.Data.ConnectionState.Open;
}
// likewise disconnect could be common
public void SQLDisconnect()
{
if (sqlConnectionHandle != null)
if (sqlConnectionHandle.State == ConnectionState.Open)
sqlConnectionHandle.Close();
}
public bool SqlExecNonQuery( IDbCommand SQLCmd, DataTable oTbl)
{
// pre-clear exception
LastException = null;
// fill the table...
SQLConnect();
try
{
RowsAffectedByQuery = SQLCmd.ExecuteNonQuery();
}
catch (Exception e)
{
LastException = e;
throw e;
}
finally
{
SQLDisconnect();
}
// Its all ok if no exception error
return LastException == null;
}
}
// Now, build your connection manager per specific type
public class MyAccessConnection : MyConnection
{
public MyAccessConnection()
{ sqlConnectionHandle = new OleDbConnection(); }
public override string GetConnectionString()
{ return "Your Connection String from AppSettings.. any changes if OleDb vs SQL"; }
public override IDbCommand GetSQLDbCommand()
{ return new OleDbCommand( "", (OleDbConnection)sqlConnectionHandle ); }
public override IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ return new OleDbParameter( ParmName, UnknownValue ); }
}
public class MySQLConnection : MyConnection
{
public MySQLConnection()
{ sqlConnectionHandle = new SqlConnection(); }
public override string GetConnectionString()
{ return "Your Connection String from AppSettings... any alterations needed??? "; }
public override IDbCommand GetSQLDbCommand()
{ return new SqlCommand ("", (SqlConnection)sqlConnectionHandle); }
public override IDbDataParameter AddDbParmSpecificValue(string ParmName, object UnknownValue)
{ return new SqlParameter(ParmName, UnknownValue); }
}
// Now to implement... pick one... Access or SQL-Server for derivation...
public class MyDataLayer : MyAccessConnection
{
public void SomeSQLCall()
{
IDbCommand sqlcmd = GetSQLDbCommand();
sqlcmd.CommandText = "UPDATE TileTypes SET Title = @Title, "
+ "Picture = @Picture, "
+ "Color = @Color "
+ "WHERE ID = @ID";
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "@Title", titleTextBox.Text.Trim() ));
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "@Picture", typePictureBox.ImageLocation) );
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "@Color", colorButton.BackColor.ToArgb()) );
sqlcmd.Parameters.Add( AddDbParmSpecificValue( "@ID", id));
if( SqlExecNonQuery(sqlcmd))
// Good to go
DoSomethingWithTheData;
else
// Notify of whatever error thrown....
}
}
}
所以.. 如您所见,我的最后一个类专门派生自 EITHER Access 或 SQL。然后,我可以创建我的方法来获取数据、调用更新等等。获取 SQL 命令(它返回正确的类型并自动附加到其相应的“连接句柄”对象,准备文本,添加您的参数,然后执行它。
关于c# - 参数化更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14668473/