2016-10-25 107 views
4

在我的應用程序中,我想將GridControl綁定到包含來自多個數據庫表(使用外鍵引用)的數據的DataTable。使用SqlDataAdapter更新數據庫視圖

我在更新數據時遇到問題,因爲我在引用多個數據庫表的命令上使用了SqlDataAdapter。我正在錯誤:

Dynamic sql generation is not supported against multiple base tables

我試圖通過創建在多個表組合成一個「表」,我可以再綁定到我的GridControl視圖圍繞解決它。

插入數據是通過在視圖中使用「而不是」觸發器來完成的,在該視圖中我正在向適當的表中添加適當的數據。在普通的t-sql中,完美地插入工作。我可以將數據插入到我的視圖中,並將其插入適當的表格中。我的SqlDataAdapter應該沒有問題更新,因爲它正在更新一個「表」,其餘更新由觸發器完成。

不幸的是,我仍然得到錯誤

Dynamic sql generation is not supported against multiple base tables

你有任何想法,爲什麼SqlDataAdapter的還是沒有讓我更新,甚至認爲它現在只更新一「表」 - 有何看法?

我的代碼:

的視圖:

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; 
    } 

更新代碼:

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

插入,在T-SQL的工作原理:

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

因爲我有幾個GridControls認爲這樣的工作(使用不同的數據),我想爲了不爲SqlDataAdapter自己生成select,insert,update和delete命令,而不是使用SqlCommandBuilder來簡化它。

謝謝!

編輯:

(希望)把事情說清楚:

gcParameters

這是我工作的GridControl。原諒我的列名,他們用波蘭語。 Identyfikator =標識, 由... =名稱, OPIS =描述, 最小= MINVALUE, Maksimum = MaxValue的, Jednostka =單位

現在,我加入另一行GridControl只包含「由...(名稱)「和」Opis(描述)「字段。

我使用TestType的Id填充「Identyfikator(Id)」字段,我想用它們的默認值添加參數到其他字段。新行被自動添加到綁定到我的GridControl的DataTable,並且在用戶單擊「Save」後,我想使用SqlDataAdapter.Update()方法將這些更改推送到數據庫。這是我得到錯誤的地方:

Dynamic sql generation is not supported against multiple base tables

我希望它明確了我想要達到的目標以及如何實現目標。

編輯:

我設法找到解決這個問題的辦法。你可以在我的答案下面查看它。

+0

你有一個主要的缺陷。你認爲只有一行插入。這不是SQL服務器觸發器的工作原理。他們每次手術一次。你需要把它寫成一個基於單個集合的插入,並去除這些標量變量。看起來像從插入到參數和單位的簡單連接將解決觸發問題。你也迫切需要閱讀有關參數化查詢。你發佈的內容很容易被sql注入。 –

+1

@SeanLange我知道每個操作都會觸發一次sql觸發器,這是一個測試版本,我只想查看更新是否能夠正常工作,因爲我花了數小時試圖找到儘可能乾淨的更新方法。我也知道參數化查詢是什麼,正如你可以在GetDataAdapter方法中看到的那樣,有可能使用參數,但它又是一個測試版本。 –

+0

在你的文章中,你會談論更新,但在代碼中沒有看到單個更新語句。你還提到了其他觸發器的更新。當我們沒有全部信息時,確實很難提供幫助。你能發表更多的細節,以便我們看到問題出在哪裏? –

回答

0

我終於設法完成了該項目的這一部分。我也找到了解決我的問題的方法。

首先,我創建了一個模仿我的GridControl的視圖。它看起來是這樣的:

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,使排在我的唯一目標表(在這種情況下:TestTypeId和參數標識)。

然後,因爲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"); 

我幾乎確信它可以在不同的(更好)的方式來完成的,但我想分享它,因爲我花了一些時間來修復它,我不能在線找不到任何解決方案。

如果您對如何使其更好有任何意見,請隨時發表評論。

享受!