2016-10-25 5 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 самостоятельно, вместо этого я использую SqlCommandBuilder, чтобы упростить его.

Спасибо!

EDIT:

К (надеюсь) сделать вещи ясно:

gcParameters

Это GridControl я работаю. Простите меня за имена колонок, они на польском языке. Identyfikator = Id, Nazwa = Имя, Opis = Описание, Минимум = MinValue, Maksimum = MaxValue, Jednostka = Unit

На данный момент, я добавляю еще одну строку в GridControl, который содержит только «Nazwa (Name) "и" Opis (Описание) ".

Я заполняю поле «Identyfikator (Id)» с идентификатором TestType, которое я хочу добавить к параметрам и другим полям с их значениями по умолчанию. Новая строка автоматически добавляется в DataTable, привязанный к моему GridControl, и после того, как пользователь нажимает «Сохранить», я хочу направить эти изменения в базу данных с помощью метода SqlDataAdapter.Update(). Это где я получаю сообщение об ошибке:

Dynamic sql generation is not supported against multiple base tables

Я надеюсь, что это ясно дал понять, что я хочу достичь и как я пытаюсь это сделать.

EDIT:

мне удалось найти решение этой проблемы. Вы можете проверить это в моем ответе ниже.

+0

У вас ОСНОВНАЯ ошибка.Вы предполагаете, что вставляется только одна строка. Это НЕ, как работают SQL-серверы. Они срабатывают один раз за операцию. Вам нужно написать это как единый набор, основанный на вставке, и избавиться от этих скалярных переменных. Похоже, что простое соединение из вставленных в Parameters and Units будет исправлять проблему с триггером. Вам также крайне необходимо прочитать о параметризованных запросах. То, что вы опубликовали, уязвимо для 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 

Очень важно, что представление содержит идентификаторы, которые делают строки в моей таблице назначения уникальной (в данном случае: 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 

Update:

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"); 

Я почти уверен, что это может быть сделано в другой (лучше) способом, но я хочу поделиться им, так как он мне потребовалось некоторое время, чтобы исправить это, и я не мог Не найти решение в Интернете.

Если у вас есть идеи о том, как сделать его лучше, не стесняйтесь комментировать.

Наслаждайтесь!

 Смежные вопросы

  • Нет связанных вопросов^_^