C# 使用SqlDataAdapter更新数据库视图

C# 使用SqlDataAdapter更新数据库视图,c#,sql-server,database,sqldataadapter,gridcontrol,C#,Sql Server,Database,Sqldataadapter,Gridcontrol,在我的应用程序中,我希望将GridControl绑定到包含来自多个数据库表(用外键引用)的数据的DataTable 我在更新数据时遇到问题,因为我在引用多个数据库表的命令上使用SqlDataAdapter。我得到了一个错误: 对多个基表不支持动态sql生成 我试图通过创建一个视图来解决这个问题,该视图将多个表组合成一个“表”,然后可以绑定到GridControl 插入数据是在视图上使用“而不是”触发器完成的,在该视图中,我正在将适当的数据添加到适当的表中。在普通的t-sql中,插入可以完美地工作

在我的应用程序中,我希望将GridControl绑定到包含来自多个数据库表(用外键引用)的数据的DataTable

我在更新数据时遇到问题,因为我在引用多个数据库表的命令上使用SqlDataAdapter。我得到了一个错误:

对多个基表不支持动态sql生成

我试图通过创建一个视图来解决这个问题,该视图将多个表组合成一个“表”,然后可以绑定到GridControl

插入数据是在视图上使用“而不是”触发器完成的,在该视图中,我正在将适当的数据添加到适当的表中。在普通的t-sql中,插入可以完美地工作。我可以将数据插入到视图中,并将其插入到相应的表中。我的SqlDataAdapter在更新时应该没有问题,因为它正在更新一个“表”,其余的更新是由触发器完成的

不幸的是,我仍然得到错误

对多个基表不支持动态sql生成

你知道为什么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, '%')
因为我有几个GridControl是这样工作的(使用不同的数据),所以我试图自己不为SqlDataAdapter生成select、insert、update和delete命令,而是使用SqlCommandBuilder使其更简单

谢谢

编辑:

为了(希望)把事情弄清楚:

这是我正在处理的GridControl。请原谅我的列名,它们是波兰语的。 identifikator=Id, Nazwa=名称, Opis=描述, 最小值=最小值, Maksimum=最大值, Jednostka=单位

现在,我正在向GridControl添加另一行,该行只包含“Nazwa(名称)”和“Opis(描述)”字段

我正在用要添加参数的TestType的Id填充“identifikator(Id)”字段,并用其默认值填充其他字段。新行将自动添加到绑定到我的GridControl的DataTable中,在用户单击“保存”后,我希望使用SqlDataAdapter.Update()方法将这些更改推送到数据库中。这就是我得到错误的地方:

对多个基表不支持动态sql生成

我希望它清楚地表明了我想要实现什么,以及我是如何努力做到这一点的

编辑:


我设法找到了解决这个问题的办法。你可以在下面我的答案中查看。

我终于完成了项目的那一部分。我也找到了解决问题的办法

首先,我创建了一个模仿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
视图包含使目标表中的行唯一的ID(在本例中为TestTypeId和ParameterId),这一点很重要

然后,因为SQL仍然不允许我插入、更新或删除行,因为

对多个基表不支持动态sql生成

错误

我跳过了它,在我的视图上创建了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
我还必须改变创建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");
我几乎可以肯定它可以用一种不同的(更好的)方式来完成,但我想分享一下,因为我花了一些时间来修复它,而且我在网上找不到任何解决方案

如果你对如何改进有任何想法,请随时发表评论


享受吧

你的电脑有一个很大的缺陷。您假定在“插入”中只有一行。sql server触发器不是这样工作的。他们每次行动射击一次。您需要将其编写为基于单个集合的插入,并去掉这些标量变量。似乎插入到参数和单元的简单连接可以解决触发问题。您还迫切需要了解参数化查询。您发布的内容易受sql注入攻击。@SeanLange我知道sql会在每次操作中触发一次fire,这是一个测试版本,我只是想看看更新是否有效,因为我花了几个小时试图找到一种尽可能干净地进行更新的方法。我也知道什么是参数化查询,正如您在GetDataAdapter方法中看到的,可以使用参数,但这只是一个测试版本。在您的帖子中,您谈到了更新,但我在代码中没有看到任何更新语句。您还提到了其他执行更新的触发器。当我们没有所有的信息时,真的很难提供帮助。您能发布更多详细信息以便我们了解问题所在吗?@SeanLange我说的是SqlDataAdapter更新,您可以在“更新代码:”部分的第三行看到。我想在用户编辑绑定到GridControl的mvarParameterTable后更新v_TestTypeParameter_网格视图。我想把重点放在至少插入添加到DataTable中的数据以使其工作。在我能够处理插入数据之后,我将以同样的方式更新和删除它。我将在一分钟内编辑我的帖子,以显示我如何显示数据以及我希望如何编辑数据。希望它能把事情弄清楚。