2016-10-25 12 views
4

내 응용 프로그램에서는 GridTree를 여러 데이터베이스 테이블 (외래 키로 참조)의 데이터가 포함 된 DataTable에 바인딩하려고합니다.SqlDataAdapter를 사용하여 데이터베이스 뷰 업데이트

여러 데이터베이스 테이블을 참조하는 명령에서 SqlDataAdapter를 사용했기 때문에 데이터를 업데이트하는 데 문제가있었습니다.

Dynamic sql generation is not supported against multiple base tables

내가 그때 내 GridControl에 바인딩 할 수있는 일 "테이블"로 여러 테이블을 결합 된 뷰를 생성하여 그것을 주변에 작업을 시도 : 나는 오류가 발생했습니다.

적절한 데이터를 적절한 테이블에 추가하는 뷰에서 "대신"트리거를 사용하여 데이터를 삽입했습니다. 일반 t-SQL에서는 삽입이 완벽하게 작동합니다. 내보기에 데이터를 삽입 할 수 있으며 적절한 테이블에 삽입되고 있습니다. 내 "SqlDataAdapter"는 하나의 "테이블"을 업데이트하고 나머지 업데이트는 트리거에 의해 수행되므로 업데이트하는 데 문제가 없어야합니다. 보기 -

불행하게도, 난 여전히도 지금 단 하나의 "표"를 업데이트의 사상, 당신은 SqlDataAdapter를 여전히 나에게 업데이 트를 두지 않을 이유 어떤 생각을 가지고 있습니까 오류

Dynamic sql generation is not supported against multiple base tables

는 무엇입니까?

내 코드 :

뷰 :

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에서 작동 :

내가 (다른 데이터와) 같은 일을 여러 GridControls을 가지고 있기 때문에
INSERT INTO v_TestTypeParameter_grid VALUES (2, 'Fe', 'Iron', 5.2, 7.9, '%') 

, 내가 노력하고 있어요 대신 SqlDataAdapter에 대한 select, insert, update 및 delete 명령을 생성하지 말고 대신 SqlCommandBuilder를 사용하여 간단하게 유지합니다.

감사합니다.

편집 : 클리어 (희망) 할 것들

:

gcParameters

이 내가 작업하고있는 GridControl입니다. 칼럼 이름에 대해 용서해주세요, 폴란드어입니다. Identyfikator = 아이디, 로 비슷 = 이름, OPIS = 설명, 최소 = MINVALUE, Maksimum = MAXVALUE, Jednostka = 단위 지금은

, 나는 (단지이 "로 비슷가 포함되어 GridControl 다른 행을 추가하고 이름) "및"Opis (설명) "필드가 있습니다.

"Identyfikator (Id)"필드에 매개 변수를 추가하려는 TestType의 ID와 다른 필드를 기본값으로 채 웁니다. 새 행이 내 GridControl에 바인딩 된 DataTable에 자동으로 추가되고 사용자가 "저장"을 클릭하면 SqlDataAdapter.Update() 메서드를 사용하여 해당 변경 내용을 데이터베이스에 푸시합니다. 이것은 내가 오류를 얻고있는 곳입니다 :

Dynamic sql generation is not supported against multiple base tables

내가 성취하고자하는 바를 분명히하고 그것을 어떻게하려고 하는지를 희망하기를 바랍니다.

편집 :

나는이 문제에 대한 해결책을 찾을 수 있었다. 내 대답은 아래에서 확인할 수 있습니다.

+0

귀하의 주요 결함이 있습니다.삽입 된 행이 하나만 있다고 가정합니다. 이것은 SQL Server 트리거가 작동하는 방식이 아닙니다. 작동 당 한 번씩 발사됩니다. 이를 단일 세트 기반 삽입으로 작성하고 해당 스칼라 변수를 제거해야합니다. 삽입에서 매개 변수 및 단위로의 간단한 조인처럼 보이는 것이 트리거 문제를 해결합니다. 매개 변수가있는 쿼리에 대해서도 필사적으로 읽어야합니다. 당신이 게시 한 것은 SQL injection에 취약합니다. –

+1

@SeanLange SQL 트리거가 작업 당 한 번 실행된다는 것을 알고 있습니다. 업데이트를 가능한 한 깨끗하게 처리하는 방법을 찾기 위해 시간을 보냈기 때문에 업데이트가 작동 하는지를보고 싶었던 테스트 버전입니다. 또한 매개 변수화 된 쿼리가 무엇인지 알 수 있으며 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 

그것은보기가 유일한 내 대상 테이블의 행을 ID를 포함하는 것이 중요합니다 : 그것은 다음과 같이 보입니다. 그런 다음

, 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 

내 트리거 (예, 나는 그들이 기반 설정해야합니다 알고)이 모습

나는 또한 변해야했다. 전자 방식 나는 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"); 

나는 그것이 다른 (더 나은) 방식으로 수행 될 수 있다는 것을 거의 확신하지만 그것을 해결하기 위해 좀 시간이 걸렸습니다 때문에 나는 그것을 공유 할 내가 나오지 않았어 어떤 해결책도 온라인에서 찾을 수 없습니다.

더 나은 방법에 대해 알고 싶다면 언제든지 말씀해주십시오.

즐기십시오!