2016-10-25 32 views
4

私のアプリケーションでは、複数のデータベーステーブル(外部キーで参照)からのデータを含むDataTableにGridControlをバインドします。SqlDataAdapterを使用したデータベースビューの更新

複数のデータベーステーブルを参照するコマンドでSqlDataAdapterを使用していたため、データの更新に問題がありました。私はエラーを取得した

Dynamic sql generation is not supported against multiple base tables

私はその後、私のGRIDCONTROLに特異的に結合することができることを一つの「表」の中に複数のテーブルを結合したビューを作成することによって、それを周りに動作するようにしようとしました。

適切なデータを適切なテーブルに追加していたビューで、「代わりに」トリガを使用してデータを挿入しました。プレーンなt-SQLでは、インサートは完全に機能します。私は自分のビューにデータを挿入することができ、それは適切なテーブルに挿入されています。私のSqlDataAdapterは1つの "テーブル"を更新し、残りの更新はトリガーによって行われているため、更新に問題はありません。

残念ながら、私はまだエラー

Dynamic sql generation is not supported against multiple base tables

を取得していますが、SqlDataAdapterオブジェクトは、まだ私が更新させていない理由を任意のアイデアを持っていても、それは今だけ1「テーブル」を更新しています思いました - か?

マイコード:

ビュー:

CREATE view [dbo].[v_TestTypeParameter_grid] 
as 
(
select t1.Id, t3.Name, t3.Description, t2.MinValue, t2.MaxValue, t4.Symbol 
from TestTypes as t1 join 
TestTypeParameters as t2 on t1.Id = t2.TestType join 
Parameters as t3 on t2.Parameter = t3.Id left join 
Units as t4 on t2.Unit = t4.Id 
) 

代わりのビューにトリガー:

CREATE TRIGGER [dbo].[tr_TestTypeParameterAdded] ON [dbo] [v_TestTypeParameter_grid] 
INSTEAD OF INSERT 
AS 
BEGIN 
    DECLARE 
    @TestTypeId int, 
    @ParameterId int, 
    @UnitId int, 
    @ParameterName varchar(100), 
    @MinValue decimal(18,2), 
    @MaxValue decimal(18,2), 
    @UnitSymbol varchar(100) 

    SELECT @TestTypeId = Id, @ParameterName = Name, @MinValue = MinValue, @MaxValue = MaxValue, @UnitSymbol = Symbol FROM Inserted; 
    SELECT @ParameterId = Id FROM Parameters WHERE Name = @ParameterName; 
    SELECT @UnitId = Id from Units WHERESymbol = @UnitSymbol; 

    INSERT INTO TestTypeParameters(TestType, Parameter, MinValue, MaxValue, Unit) VALUES(@TestTypeId, @ParameterId, @MinValue, @MaxValue, @UnitId); 
END 

マイ結合コード:

mvarParameterListAdapter = DBService.GetDataAdapter("select * from v_TestTypeParameter_grid where Id = " + mvarTestTypeId); 

mvarParameterTable = new DataTable(); 
mvarParameterListAdapter.Fill(mvarParameterTable); 
gcParameters.DataSource = mvarParameterTable; 
gcParameters.RefreshDataSource(); 

DBService.GetDataAdapter方法。

public static SqlDataAdapter GetDataAdapter(String command, DataTable parameters = null) 
    { 
     SqlConnection lvarConnection = GetConnection(); 

     SqlCommand lvarCommand = new SqlCommand(command, lvarConnection); 
     if (parameters != null && parameters.Rows.Count > 0) 
     { 
      foreach (DataRow lvarRow in parameters.Rows) 
      { 
       lvarCommand.Parameters.AddWithValue("@" + lvarRow[0], lvarRow[1]); 
      } 
     } 

     SqlDataAdapter lvarAdapter = new SqlDataAdapter(lvarCommand); 
     SqlCommandBuilder lvarCommandBuilder = new SqlCommandBuilder(lvarAdapter); 
     return lvarAdapter; 
    } 

アップデートコード:T-SQLで動作

try 
{ 
    mvarParameterListAdapter.Update(mvarParameterTable); 
} 
catch (Exception ex) 
{ 
    // Here, I'm getting the error 
} 

の挿入:

INSERT INTO v_TestTypeParameter_grid VALUES (2, 'Fe', 'Iron', 5.2, 7.9, '%') 

私は(別のデータで)このように動作し、いくつかのGridControlsを持っているので、私がしようとしていますSqlDataAdapterの代わりにselect、insert、update、deleteのコマンドを生成するのではなく、SqlCommandBuilderを使用してよりシンプルにしています。

ありがとうございます!

EDIT:

に(たぶん)、物事を明確にする:

gcParameters

これは私が働いているGRIDCONTROLです。列名を私に許してください、彼らはポーランド語です。 Identyfikator =同上、 Nazwa =名前、 OPIS =説明、 最小= MinValueプロパティ、 Maksimum = MaxValueを、 Jednostka =単位

今のところ、私は唯一の「Nazwaを(含まれていることをGRIDCONTROLに別の行を追加してい名前)」および「Opis(Description)」フィールドがあります。

"Identyfikator(Id)"フィールドに、パラメータを追加するTestTypeのIDと他のフィールドのデフォルト値を入力します。新しい行は、GridControlにバインドされているDataTableに自動的に追加され、ユーザーが[保存]をクリックすると、SqlDataAdapter.Update()メソッドを使用してその変更をデータベースにプッシュします。ここでエラーが発生しています:

私が達成したいことと、それをどうしようとしているのかを明確にしたいと思っています。

編集:

この問題の解決策を見つけることができました。あなたは私の答えでそれをチェックすることができます。

+0

あなたには大きな欠陥があります。挿入された行は1つしかないと仮定します。これは、SQL Serverのトリガーの仕組みではありません。 1回の操作で1回発射されます。これを単一のセットベースの挿入として記述し、それらのスカラー変数を取り除く必要があります。挿入されてからパラメータとユニットへの単純な結合のように見えるトリガーの問題を修正します。また、パラメータ化されたクエリについても読んでおく必要があります。あなたが投稿したものは、SQLインジェクションに脆弱です。 –

+1

@SeanLange SQLトリガーは操作ごとに1回起動することを知っています。できるだけクリーンで更新を行う方法を見つけようと数時間を費やしていたので、更新が正常に機能しているかどうかを確認したいテストバージョンです。私はまた、どのようなパラメータ化されたクエリがあるか知っていますし、GetDataAdapterメソッドで見ることができるように、パラメータを使用する可能性がありますが、やはりテスト版です。 –

+0

あなたの記事では更新について話していますが、このコードのどこにでも単一の更新ステートメントは表示されません。また、更新を行っている他のトリガーについても触れています。私たちがすべての情報を持っていないと、本当に助けが難しいです。問題がどこにあるかわかるように詳細を投稿できますか? –

答えて

0

私は最終的にプロジェクトのその部分を終了することができました。私はまた、私の問題に対する解決策を見つけました。

まず、GridControlを模倣したビューを作成しました。 (:TestTypeIdとParameterIdこのケースでは)

CREATE VIEW [dbo].[v_TestTypeParameter_grid] 
AS 
SELECT t1.Id, t3.Name, t3.Description, t2.MinValue, t2.MaxValue, t2.Unit as Unit, 
t3.Id AS ParameterId 
FROM    
dbo.TestTypes AS t1 INNER JOIN 
    dbo.TestTypeParameters AS t2 ON t1.Id = t2.TestType INNER JOIN 
    dbo.Parameters AS t3 ON t2.Parameter = t3.Id 

それは、ビューはユニークな私の先テーブル内の行を作るのIdsが含まれていることが重要です。それは次のようになります。その後

、SQLはまだ私には、挿入、更新または理由

Dynamic sql generation is not supported against multiple base tables

エラーの行を削除することができないからです。

私のビュー(挿入、更新、削除用)にINSTEAD OFトリガーを作成してスキップしました。

挿入を::

CREATE TRIGGER [dbo].[tr_TestTypeParameterAdded] ON [dbo].[v_TestTypeParameter_grid] 
INSTEAD OF INSERT 
AS 
BEGIN 
    DECLARE 
    @TestTypeId int, 
    @ParameterId int, 
    @UnitId int, 
    @ParameterName varchar(100), 
    @MinValue decimal(18,2), 
    @MaxValue decimal(18,2), 
    @UnitSymbol varchar(100) 

    SELECT @TestTypeId = Id, @ParameterName = Name, @MinValue = MinValue, @MaxValue = MaxValue, @UnitId = Unit from Inserted; 
    SELECT @ParameterId = Id from Parameters where Name = @ParameterName; 

    insert into TestTypeParameters(TestType, Parameter, MinValue, MaxValue, Unit) values (@TestTypeId, @ParameterId, @MinValue, @MaxValue, @UnitId); 
END 

更新:

CREATE TRIGGER [dbo].[tr_TestTypeParameterUpdated] ON [dbo].[v_TestTypeParameter_grid] 
INSTEAD OF UPDATE 
AS 
BEGIN 
    DECLARE 
    @TestTypeId int, 
    @ParameterId int, 
    @UnitId int, 
    @MinValue decimal(18,2), 
    @MaxValue decimal(18,2) 

    select * from inserted 
    SELECT @TestTypeId = Id, @MinValue = MinValue, @MaxValue = MaxValue, @UnitId = Unit, @ParameterId = ParameterId from Inserted; 

    update TestTypeParameters set MinValue = @MinValue, MaxValue = @MaxValue, Unit = @UnitId where TestType = @TestTypeId and Parameter = @ParameterId; 
END 

削除:

CREATE TRIGGER [dbo].[tr_TestTypeParameterDeleted] ON [dbo].[v_TestTypeParameter_grid] 
INSTEAD OF DELETE 
AS 
BEGIN 
    DECLARE 
    @TestTypeId int, 
    @ParameterId int, 
    @UnitId int, 
    @ParameterName varchar(100), 
    @MinValue decimal(18,2), 
    @MaxValue decimal(18,2), 
    @UnitSymbol varchar(100) 

    SELECT @TestTypeId = Id, @ParameterName = Name, @MinValue = MinValue, @MaxValue = MaxValue, @UnitId = Unit, @ParameterId = ParameterId from deleted; 

    delete from TestTypeParameters where TestType = @TestTypeId and Parameter = @ParameterId; 
END 

私のトリガーは(はい、私は彼らが基づいて設定する必要があります知っている)、このように見えました

私も変えなければなりませんでしたE方法私はSqlDataAdaptersを作成:

SqlCommand lvarInsert = 
    new SqlCommand(
     "insert into v_TestTypeParameter_grid values (@Id, @Name, @Description, @MinValue, @MaxValue, @Unit, @ParameterId)", DBService.Connection); 
mvarParameterListAdapter.InsertCommand = lvarInsert; 
lvarInsert.Parameters.Add("@Id", SqlDbType.Int, 5, "Id"); 
lvarInsert.Parameters.Add("@Name", SqlDbType.NVarChar, 5, "Name"); 
lvarInsert.Parameters.Add("@Description", SqlDbType.NVarChar, 5, "Description"); 
lvarInsert.Parameters.Add("@MinValue", SqlDbType.Decimal, 5, "MinValue"); 
lvarInsert.Parameters.Add("@MaxValue", SqlDbType.Decimal, 5, "MaxValue"); 
lvarInsert.Parameters.Add("@Unit", SqlDbType.Int, 5, "Unit"); 
lvarInsert.Parameters.Add("@ParameterId", SqlDbType.Int, 5, "ParameterId"); 

SqlCommand lvarSelect = new SqlCommand("select * from v_TestTypeParameter_grid where Id = " + mvarTestTypeId, DBService.Connection); 
mvarParameterListAdapter.SelectCommand = lvarSelect; 

SqlCommand lvarUpdate = 
new SqlCommand(
"update v_TestTypeParameter_grid set Id = @Id, ParameterId = @ParameterId, Name = @Name, Description = @Description, MinValue = @MinValue, MaxValue = @MaxValue, Unit = @Unit where Id = @Id and ParameterId = @ParameterId", DBService.Connection); 
mvarParameterListAdapter.UpdateCommand = lvarUpdate; 
lvarUpdate.Parameters.Add("@Id", SqlDbType.Int, 5, "Id"); 
lvarUpdate.Parameters.Add("@ParameterId", SqlDbType.Int, 5, "ParameterId"); 
lvarUpdate.Parameters.Add("@Name", SqlDbType.NVarChar, 5, "Name"); 
lvarUpdate.Parameters.Add("@Description", SqlDbType.NVarChar, 5, "Description"); 
lvarUpdate.Parameters.Add("@MinValue", SqlDbType.Decimal, 5, "MinValue"); 
lvarUpdate.Parameters.Add("@MaxValue", SqlDbType.Decimal, 5, "MaxValue"); 
lvarUpdate.Parameters.Add("@Unit", SqlDbType.Int, 5, "Unit"); 

SqlCommand lvarDelete =new SqlCommand(
"delete from v_TestTypeParameter_grid where Id = @Id and ParameterId = @ParameterId", DBService.Connection); 
mvarParameterListAdapter.DeleteCommand = lvarDelete; 
lvarDelete.Parameters.Add("@Id", SqlDbType.Int, 5, "Id"); 
lvarDelete.Parameters.Add("@ParameterId", SqlDbType.Int, 5, "ParameterId"); 

私は、それが異なる(より良い)方法で行うことができることをほぼ確信しているが、それはそれを修正するために私にいくつかの時間がかかったので、私はそれを共有したいと私はcouldnオンラインで解決策を見つけることはできません。

改善の方法についてご意見がありましたら、お気軽にコメントしてください。

お楽しみください!

関連する問題