Отправка нулевого параметра в хранимую процедуру

У меня есть класс Subject. Это члены id_subject (int) и subjectName (string)

Их я создаю список

List<subject> listSubject = new List<subject>();
</subject></subject>

и отправить его в эту хранимую процедуру:

public bool AddNewNews(News news, List<subject> subject)
 {
 SqlParameter[] parameters = new SqlParameter[]
 {
 new SqlParameter ("@title",news.Title),
 new SqlParameter ("@text",news.Text),
 new SqlParameter ("@year",news.Year), 
 new SqlParameter ("@month",news.Month) , 
 new SqlParameter ("@day",news.Day) , 
 new SqlParameter ("@id_writer",news.Id_writer) ,
 new SqlParameter ("@id_subject1",subject[0]!=null? subject[0].Id_subject:null),
 new SqlParameter ("@id_subject2",subject[1]!=null? subject[1].Id_subject:null) ,
 new SqlParameter ("@id_subject3",subject[2]!=null? subject[2].Id_subject:null), 
 new SqlParameter ("@id_subject4",subject[3]!=null? subject[3].Id_subject:null),
 new SqlParameter ("@id_subject5",subject[4]!=null? subject[4].Id_subject:null)
 };

 return SqlDBHelper.ExecuteNonQuery("AddNewNews", CommandType.StoredProcedure, parameters);
}
</subject>

Первое: короткое, если не верно

Я отбрасываю их на объект и отправляю в хранимую процедуру

BEGIN TRANSACTION;

 DECLARE @last_id_news int

 BEGIN TRY
 insert into news (title, text, year, month, day, id_writer)
 values(@title, @text, @year, @month, @day, @id_writer)

 set @last_id_news = SCOPE_IDENTITY()

 if(@id_subject1 <> null)
 begin
 insert into news_subject (id_news, id_subject) 
 values (@last_id_news, @id_subject1)
 end

 if(@id_subject2 <> null)
 begin
 insert into news_subject (id_news, id_subject) 
 values (@last_id_news, @id_subject2)
 end

 if(@id_subject3 <> null)
 begin
 insert into news_subject (id_news, id_subject) 
 values (@last_id_news, @id_subject3)
 end

if(@id_subject4<>null)
begin
 insert into news_subject (id_news,id_subject) values (@last_id_news,@id_subject4)
end
if(@id_subject5<>null)
begin
 insert into news_subject (id_news,id_subject) values (@last_id_news,@id_subject5)
end

 COMMIT TRANSACTION;
END TRY
BEGIN CATCH

ROLLBACK TRANSACTION;
END CATCH;

RETURN

Почему это не работает?

2 ответа

Как уже отмечалось в комментариях и ответе, DBNull - это раздражающее требование здесь; вы можете использовать оператор null-coalescing, чтобы сделать его достаточно читаемым:

new SqlParameter ("@id_subject1",((object)subject[0]) ?? DBNull.Value),
 new SqlParameter ("@id_subject2",((object)subject[1]) ?? DBNull.Value),
 new SqlParameter ("@id_subject3",((object)subject[2]) ?? DBNull.Value),
 new SqlParameter ("@id_subject4",((object)subject[3]) ?? DBNull.Value),
 new SqlParameter ("@id_subject5",((object)subject[4]) ?? DBNull.Value),

Или лучше: возможно, ваш метод ExecuteNonQuery мог бы перебирать параметры и проверять, является ли .Value == null, заменив его DBNull.Value если он есть.

Альтернативно, рассмотрите инструмент типа "dapper", который сделает все это для вас удобно:

connection.Execute("AddNewNews", new {
 title = news.Title,
 //...
 id_writer = news.Id_writer,
 id_subject1 = subject[0],
 //...
 id_subject5 = subject[4],
}, commandType: CommandType.StoredProcedure);

который затем полностью параметризуется нулями, обрабатываемыми соответствующим образом.

licensed under cc by-sa 3.0 with attribution.