3

アクセスファイル(.accdb)のレコードを更新しようとしています。.netOleDbCommandとOleDbParametersを使用しようとしています。また、汎用モデルを使用して、すべてのコマンドとパラメーターをSystem.Data.Commonの同等の抽象概念に格納し、SQL Serverに簡単に切り替えることができるようにしようとしています(これを行う予定です)。

これが実際に使用されているコマンドです

EDIT 2/2/2013-9:10 pmコマンド.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"/>

ここで問題となるのは、updateステートメントでパラメーターを使用する場合、更新が行われることはなく、エラーがスローされることもありません。これがそのコードです。

2013年2月2日編集-9:10pm 関数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はオートナンバーフィールドです
  • タイトルはテキストフィールドです
  • 画像はテキストフィールドです
  • 色は長整数フィールドです

これは、VisualStudioの監視ウィンドウのパラメーターから直接コピーされたデータの例です。

  • 「編集」(タイトル)
  • -1(カラー)
  • "data \ images \ Edit_000000.jpg"(画像)
  • 740(id)

そのIDはデータベースに存在し、クエリの実行後も変更されていません。

編集2/2/2013-9:10pm 実際に更新されているデータベースを確認する方法がわかりません。考えられる唯一のことは、同じ接続文字列と接続オブジェクトを使用して、同じExecuteNonqueryで挿入ステートメントを実行したことです。メソッドとそれは私が見ていたデータベースで動作しました。そして、updateステートメントは次のようにうまく機能します(パラメーターなし):

DALayer.ExecuteNonQuery("UPDATE TileTypes SET Title = '" + titleTextBox.Text + 
"', Color = " + colorButton.BackColor.ToArgb() + ", Picture = '" + 
imageLocation + "' WHERE ID = " + id);

編集2/2/2013-9:41pm 私はeverything.exeを使用して、コンピューター上のすべてのdata.accdbファイルを検索しました。元のファイル以外に、実際の.accdbファイルは見つかりませんでしたが、これらの.lnkは見つかりました。ファイル、私は彼らがこのプロセスを変更した可能性があるとは思わないが、とにかくそれについて言及する

data.accdb.LNK

4

1 に答える 1

0

あなたがやろうとしていることは、私も過去にやったことですが、OleDB(Access、Visual FoxProなど)、SQL-Server、SyBase SQLAnywhere、そしておそらく私の実装があなたを助けるかもしれません。まず、接続に使用する各要素は、IDbConnection、IDbCommand、IDbParameterなどの共通のインターフェイスで機能します。

以下に投稿するのは、このようなマルチデータベース接続タイプを最初に構築した方法の一部です。私はたくさんを取り除いて、実際にこの取り除いたバージョンをテストしませんでした、しかしそれはあなたが実行するための良いベースラインであるはずです。

前提は、ほぼ抽象のようなベースライン「MyConnection」ですが、いずれかのサブクラス化された定義の下に存在するプロパティといくつかの「一般的な」メソッドがあります。このことから、各関数とパラメータタイプは、特定ではなく「インターフェイス」に基づいています。ただし、派生のそれぞれは、独自の適切なタイプを作成します。これにより、すべてを「ケース」にする必要がなくなります。これがデータアクセス層の開発に役立つことを願っています。

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....

        }
    }
}

ご覧のとおり、私の最後のクラスは、具体的にはAccessまたはSQLのいずれかから派生しています。次に、データを取得したり、更新を呼び出したりするためのメソッドを作成できます。SQLコマンドを取得します(適切なタイプを返し、対応する「接続ハンドル」オブジェクトに自動的にアタッチされ、テキストを準備し、パラメーターを追加して、実行します。

于 2013-02-04T02:16:45.733 に答える