2013-02-27 49 views
7

我必須更新一個包含270多個更新字段的大表。更新大表(很多專欄)。 C#.NET

我對.NET相對陌生,需要提醒一下,在這種情況下最好使用什麼:SqlCommand,某種內存映射表或DataSet,或者它可能存在某種使用元數據的自動生成對象D B?請幫忙。

原因: 我有一箇舊的大Delphi7應用程序,其中的一部分是負責監聽一些數據包封送到大型結構,並在最後一步,存儲在數據庫中。現在我將這部分移植到新的C#服務中,至少實際上我必須保留相同的邏輯。 問題是結構很大(超過220個字段),存儲它的表格有近300個字段。從我的220字段的結構中扣除/計算其他約50個字段,並且全部應該在數據庫中更新。 實際Delphi代碼是醜陋的螞蟻就增長了好幾年如表本身,這樣的事情:

'UPDATE TABLE_NAME ' + 
    ' MSG_TYPE = ' + IntToStr(integer(RecvSruct.MSG_TYPE)) + ' ' + 
    ' ,SomeFLOATfield = ' + FloatToStr(RecvSruct.SomeFLOATfield) + ' ' + 
    ... //and other over 270 fileds here 
'WHERE ID = ' + IntToStr(obj.ID) 

沒有任何動態SQL等。 其實我不能改變DB結構..所以,我要玩僅在代碼中,我不確定是否有針對性地翻譯代碼。表格用於某些報告和統計。一些計算/扣除的字段必須處理源代碼中的一些常量。

使用開發工具: MS SQL Server 2000中,C#.net2.0,VS2008

+2

爲什麼不使用存儲過程?這將是一個比這更簡單的地獄。 – 2013-02-27 22:23:36

+0

SqlCommand。你想要所有的服務器端。 – Stu 2013-02-27 22:26:01

+0

您是否可以將新的存儲過程添加到數據庫? – granadaCoder 2013-02-27 22:26:49

回答

2

最簡單的解決方案適用於此,因爲ole db的工作方式是字符串。所以,要傳遞270,500,1000個參數,我所做的只是傳遞一個字符串,一個包含270個參數的字符串可能遠遠低於2kb ......這在現代計算中...繼承了1 ...不有性能損失。這裏有一個xml解決方案,但這只是蘋果和桔子,你仍然在傳遞字符串,但是需要額外的代碼來處理xml。所以......你的架構應該是這樣的:

  1. 與270個的輸入參數的SQL服務器上

    存儲過程:

    Create Procedure sp_Example1 
    (@param1 [type], @param2 [type], @param3 [type], etc...) 
    AS 
    BEGIN 
    [SQL statements] 
    END 
    
  2. 270個參數的命令對象:

    SqlCommand cmd = new SqlCommand("sp_Example1", [sqlconnectionstring]); 
    cmd.Parameters.Add(New SqlParameter("@param1", param1.value)); 
    cmd.Parameters.Add(New SqlParameter("@param2", param2.value)); 
    cmd.Parameters.Add(New SqlParameter("@param3", param3.value)); 
    

請記住,你仍然在做一個非常密集的操作,但你的基準應該是舊的應用程序。如果情況有點惡化,我不會擔心,因爲框架需要更多的計算開銷。

我不知道爲什麼它不會格式化代碼...

+0

使用SQL服務器,ADO.NET我想要一個選項,那麼爲什麼要使用OLE DB? – 2013-02-27 23:00:56

+0

@ Syn123,你是什麼意思「ole db的工作方式是用字符串」? 你的意思是說所有的參數值都是以字符串的形式傳遞的,並且自動被鑄造出來? 請檢查,這個問題太http://stackoverflow.com/questions/15135204/sql-server-why-field-value-of-almost-any-type-may-be-treated-as-quoted-string – ALZ 2013-02-28 12:56:34

+0

SQL服務器連接仍然使用ole db我相信,它只是微軟的版本。閱讀http://msdn.microsoft.com/en-us/library/ms810892.aspx的unicode部分。 Ole數據庫提供程序(ADO.NET)使用sql端口在SQL Server和應用程序之間來回傳送明文字符串數據。 – RandomUs1r 2013-02-28 15:37:56

1

確定。由於您可以添加新的存儲過程,因此我建議將所有值打包並將其作爲XML傳送到您的存儲過程。

你可以找到一個有點例子在這裏: http://granadacoder.wordpress.com/2009/01/27/bulk-insert-example-using-an-idatareader-to-strong-dataset-to-sql-server-xml/

好消息,那比如我是老年人和編碼到SQL Server 2000(帶OPENXML)。

..

這將是比發送降300個參數的存儲過程,恕我直言更好。

另一個好處是,如果您有超過1行的數據,那麼您也可以將其下載。

......

的吧 「要點」:

首先,你可以得到2000 「酒吧」 數據庫在這裏:

http://www.microsoft.com/en-us/download/details.aspx?id=23654

現在加入這個存儲過程:

/* USP */

DROP PROCEDURE dbo.uspTitleUpsert 
GO 





CREATE PROCEDURE dbo.uspTitleUpsert (
    @xml_doc TEXT , 
    @numberRowsAffected int output --return 
) 

AS 

SET NOCOUNT ON 

DECLARE @hdoc INT -- handle to XML doc 

DECLARE @errorTracker int -- used to "remember" the @@ERROR 

DECLARE @updateRowCount int 
DECLARE @insertRowCount int 


--Create an internal representation of the XML document.  
EXEC sp_xml_preparedocument @hdoc OUTPUT, @XML_Doc  



-- build a table (variable table) to store the xml-based result set 
DECLARE @titleupdate TABLE ( 
    identityid int IDENTITY (1,1) , 

title_id varchar(6) , 
title varchar(80) , 
type varchar(32) , 
pub_id varchar(32) , 
price money , 
advance money , 
royalty varchar(32) , 
ytd_sales varchar(32) , 
notes TEXT , 
pubdate datetime 
) 




--the next call will take the info IN the @hdoc(with is the holder for @xml_doc), and put it IN a variableTable 
INSERT @titleupdate 
    (
     title_id , 
     title , 
     type , 
     pub_id , 
     price , 
     advance , 
     royalty , 
     ytd_sales , 
     notes , 
     pubdate 
    ) 
SELECT 
    title_id , 
    title , 
    type , 
    pub_id , 
    price , 
    advance , 
    royalty , 
    ytd_sales , 
    notes , 
    getdate() /*dbo.udf_convert_xml_date_to_datetime (pubdate)*/ 
FROM 
    -- use the correct XPath .. the second arg ("2" here) distinquishes 
    -- between textnode or an attribute, most times with 
    --.NET typed datasets, its a "2" 
    --This xpath MUST match the syntax of the DataSet 
OPENXML (@hdoc, '/TitlesDS/Titles', 2) WITH ( 

    title_id varchar(6) , 
    title varchar(80) , 
    type varchar(32) , 
    pub_id varchar(32) , 
    price money , 
    advance money , 
    royalty varchar(32) , 
    ytd_sales varchar(32) , 
    notes TEXT , 
    pubdate varchar(32) 

) 


EXEC sp_xml_removedocument @hdoc 



select * from @titleupdate 



SET NOCOUNT OFF 




Update 
    dbo.titles 
set 
    title = vart.title , 
    type = vart.type , 
    pub_id = vart.pub_id , 
    price = vart.price , 
    advance = vart.advance , 
    royalty = vart.royalty , 
    ytd_sales = vart.ytd_sales , 
    notes = vart.notes , 
    pubdate = vart.pubdate 
FROM 
    @titleupdate vart , dbo.titles realTable 
WHERE 
    (rtrim(upper(realTable.title_id))) = ltrim(rtrim(upper(vart.title_id))) 
    and 
    exists 
    (
     select null from dbo.titles innerRealTable where (rtrim(upper(innerRealTable.title_id))) = ltrim(rtrim(upper(vart.title_id))) 
    ) 


Select @updateRowCount = @@ROWCOUNT 

INSERT INTO dbo.titles 
    (
     title_id , 
     title , 
     type , 
     pub_id , 
     price , 
     advance , 
     royalty , 
     ytd_sales , 
     notes , 
     pubdate 
    ) 
Select 
    title_id , 
    title , 
    type , 
    pub_id , 
    price , 
    advance , 
    royalty , 
    ytd_sales , 
    notes , 
    pubdate 
FROM 
    @titleupdate tu 
WHERE 
    not exists 
    (
     select null from dbo.titles innerRealTable where (rtrim(upper(innerRealTable.title_id))) = ltrim(rtrim(upper(tu.title_id))) 
    ) 

Select @insertRowCount = @@ROWCOUNT 

print '/@insertRowCount/' 
select @insertRowCount 
print '' 

print '/@updateRowCount/' 
select @updateRowCount 
print '' 


select @numberRowsAffected = @insertRowCount + @updateRowCount 



--select * from titles 

SET NOCOUNT OFF 


GO 




--GRANT EXECUTE on dbo.uspTitleUpsert TO pubsuser 



GO 

/*實施例的使用*/

EXEC dbo.uspTitleUpsert 
' 
<TitlesDS> 
    <Titles> 
     <title_id>PN3333</title_id> 
     <title>Peanut Cooking</title> 
     <type>trad_cook</type> 
     <pub_id>0877</pub_id> 
     <price>3.33</price> 
     <advance>4444.00</advance> 
     <royalty>1</royalty> 
     <ytd_sales>33</ytd_sales> 
     <notes>Peanut Cooking Notes</notes> 
     <pubdate></pubdate> 
    </Titles> 

    <Titles> 
     <title_id>SSMS4444</title_id> 
     <title>Sql Server Management Studio</title> 
     <type>programming</type> 
     <pub_id>0877</pub_id> 
     <price>13.33</price> 
     <advance>5444.00</advance> 
     <royalty>2</royalty> 
     <ytd_sales>33</ytd_sales> 
     <notes>Sql Server Management Studio Notes</notes> 
     <pubdate></pubdate> 
    </Titles> 

</TitlesDS> 
' 
, 0 
+0

非常感謝 - 我會分析這種可能性,並在這裏寫下我的結果。至少再次感謝這(OPENXML)對我來說仍然是未知領域。 它與SQL Server 2000完全兼容嗎? – ALZ 2013-02-27 22:54:42

+0

是的,OPENXML在Sql Server 2000中被「烘烤」到TSQL功能中。2005和更高版本用一些稍微不同的語法取代了OPENXML,但它們保留了OPENXML以實現向後兼容性。底線,Sql Server 2000中的OPENXML不是voo doo,它在您的使用中。 – granadaCoder 2013-02-28 09:14:44

0
  1. 您可以拆分表到新表,然後創建具有相同名稱的意見,舊錶它連接,開關,鑄件等,到新錶轉換成舊的結構爲報告。

  2. 如果您確實使用了命令(如在您發佈的Delphi代碼中),請使用參數來防止SQL注入。

  3. 對於當前使用的數據庫結構,您已經使用了開箱即用的ORM,因爲您有許多要映射的列。您可以創建POCO類作爲類型安全模型,然後使用數據符號或自定義屬性來簡化映射,然後根據屬性即時創建SQL命令。

0

沒有特別的兔子拉出.NET帽子的這一個我害怕。

由於「知道」周圍的複雜性不足,只有一些完全獨立的字段發生了變化,並且只爲他們構建了更新語句,所以您被塞滿了。

即使知道這會更好地存儲,因爲blob並不能真正幫助你。無論如何,這可能不是真的。

參數化的查詢或存儲過程在代碼中會看起來有點整齊,但可以在delphi中完成。

沒有辦法從這裏說出它應該如何完成,但一個可能有里程的想法是隱藏當前的表格而不是一小部分功能。

例如,如果你要重命名它,然後用當前名稱創建一個視圖。沒有任何東西可以閱讀,並且(可能寫入很多代碼)會注意到。 如果您只能通過視圖和某些存儲過程訪問原始表格,那麼您可以開始刪除結構。

代碼(無sql)只能在應用程序和表之間插入ORM樣式訪問。 這是一個應該基於你的技能組合和應用程序組合的決定。

除非您可以並且準備將所有應用程序與此表的具體實現分離開來,否則您只是在打磨糞便。沒有意義花費寶貴的資源。

+0

此表中沒有任何Image字段,但在另一種情況/表中,我必須更新二進制(BLOB)字段 - 此處SP無用嗎? – ALZ 2013-02-27 23:08:14

+0

當然不是sp可能非常有用,它可以在你使用它的任何地方隱藏這個垃圾表。和ORM一樣,它不會做的是以任何方式使當前的表格設計變得更好。 – 2013-02-28 21:10:15