使用 SqlDataAdapter 更新数据库视图
Updating database view using SqlDataAdapter
在我的应用程序中,我想将 GridControl 绑定到包含来自多个数据库 table 的数据的数据表(使用外键引用)。
我在更新数据时遇到问题,因为我在引用多个数据库 table 的命令上使用 SqlDataAdapter。我收到错误:
Dynamic sql generation is not supported against multiple base tables
我试图通过创建一个将多个 table 组合成一个 "table" 的视图来解决这个问题,然后我可以将其绑定到我的 GridControl。
插入数据是在视图上使用 "instead of" 触发器完成的,我在其中向适当的 table 添加了适当的数据。在普通的 t-sql 中,插入可以完美地工作。我可以将数据插入到我的视图中,并且它被插入到适当的 table。我的 SqlDataAdapter 更新应该没有问题,因为它正在更新一个 "table" 并且其余更新由触发器完成。
不幸的是,我仍然遇到错误
Dynamic sql generation is not supported against multiple base tables
你知道为什么 SqlDataAdapter 仍然不让我更新,即使它现在只更新一个 "table" - 视图吗?
我的代码:
观点:
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, '%')
因为我有几个像这样工作的 GridControl(使用不同的数据),我试图不生成 select,我自己为 SqlDataAdapter 插入、更新和删除命令,而不是那样,我正在使用SqlCommandBuilder 使其更简单。
谢谢!
编辑:
为了(希望)把事情弄清楚:
这是我正在处理的 GridControl。请原谅我的列名,它们是波兰语的。
Identyfikator = Id,
纳兹瓦 = 名字,
Opis = 描述,
最小值 = 最小值,
最大值 = 最大值,
Jednostka = 单位
现在,我正在向 GridControl 添加另一行,其中仅包含 "Nazwa (Name)" 和 "Opis (Description)" 字段。
我正在 "Identyfikator(Id)" 字段中填入我要添加参数的 TestType 的 ID,并在其他字段中填入默认值。新行会自动添加到绑定到我的 GridControl 的数据表中,并且在用户单击 "Save" 后,我想使用 SqlDataAdapter.Update() 方法将这些更改推送到数据库。这是我收到错误的地方:
Dynamic sql generation is not supported against multiple base tables
我希望它清楚地说明了我想要实现的目标以及我正在努力实现的目标。
编辑:
我设法找到了解决这个问题的办法。你可以在我下面的回答中查看。
我终于设法完成了项目的那一部分。我也找到了解决问题的方法。
首先,我创建了一个模仿我的 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
重要的是视图包含使我的目标中的行 table 唯一的 ID(在本例中:TestTypeId 和 ParameterId)。
然后,因为 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
我还必须更改创建 SqlDataAdapter 的方式:
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");
我几乎可以肯定它可以用不同的(更好的)方式完成,但我想分享它,因为我花了一些时间来修复它并且我在网上找不到任何解决方案。
如果您对如何让它变得更好有任何想法,请随时发表评论。
尽情享受吧!
在我的应用程序中,我想将 GridControl 绑定到包含来自多个数据库 table 的数据的数据表(使用外键引用)。
我在更新数据时遇到问题,因为我在引用多个数据库 table 的命令上使用 SqlDataAdapter。我收到错误:
Dynamic sql generation is not supported against multiple base tables
我试图通过创建一个将多个 table 组合成一个 "table" 的视图来解决这个问题,然后我可以将其绑定到我的 GridControl。
插入数据是在视图上使用 "instead of" 触发器完成的,我在其中向适当的 table 添加了适当的数据。在普通的 t-sql 中,插入可以完美地工作。我可以将数据插入到我的视图中,并且它被插入到适当的 table。我的 SqlDataAdapter 更新应该没有问题,因为它正在更新一个 "table" 并且其余更新由触发器完成。
不幸的是,我仍然遇到错误
Dynamic sql generation is not supported against multiple base tables
你知道为什么 SqlDataAdapter 仍然不让我更新,即使它现在只更新一个 "table" - 视图吗?
我的代码:
观点:
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, '%')
因为我有几个像这样工作的 GridControl(使用不同的数据),我试图不生成 select,我自己为 SqlDataAdapter 插入、更新和删除命令,而不是那样,我正在使用SqlCommandBuilder 使其更简单。
谢谢!
编辑:
为了(希望)把事情弄清楚:
这是我正在处理的 GridControl。请原谅我的列名,它们是波兰语的。 Identyfikator = Id, 纳兹瓦 = 名字, Opis = 描述, 最小值 = 最小值, 最大值 = 最大值, Jednostka = 单位
现在,我正在向 GridControl 添加另一行,其中仅包含 "Nazwa (Name)" 和 "Opis (Description)" 字段。
我正在 "Identyfikator(Id)" 字段中填入我要添加参数的 TestType 的 ID,并在其他字段中填入默认值。新行会自动添加到绑定到我的 GridControl 的数据表中,并且在用户单击 "Save" 后,我想使用 SqlDataAdapter.Update() 方法将这些更改推送到数据库。这是我收到错误的地方:
Dynamic sql generation is not supported against multiple base tables
我希望它清楚地说明了我想要实现的目标以及我正在努力实现的目标。
编辑:
我设法找到了解决这个问题的办法。你可以在我下面的回答中查看。
我终于设法完成了项目的那一部分。我也找到了解决问题的方法。
首先,我创建了一个模仿我的 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
重要的是视图包含使我的目标中的行 table 唯一的 ID(在本例中:TestTypeId 和 ParameterId)。
然后,因为 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
我还必须更改创建 SqlDataAdapter 的方式:
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");
我几乎可以肯定它可以用不同的(更好的)方式完成,但我想分享它,因为我花了一些时间来修复它并且我在网上找不到任何解决方案。
如果您对如何让它变得更好有任何想法,请随时发表评论。
尽情享受吧!