2013-02-27 11 views
7

Muszę zaktualizować dużą tabelę z ponad 270 polami aktualizacji.Zaktualizuj dużą tabelę (wiele kolumn). C# .NET

Jestem względnie nowy dla .NET i potrzebuję porady, co jest lepsze w tym przypadku: SqlCommand, jakiś rodzaj tablicy z mapą pamięci lub DataSet, a może istnieje jakiś rodzaj automatycznie generowanych obiektów z wykorzystaniem meta-danych z DB? Proszę pomóż.

Powód: Mam starą dużą aplikację Delphi7, której część jest odpowiedzialna za nasłuchiwanie na gnieździe niektórych pakietów, które są połączone z dużymi strukturami i, w ostatnim kroku, przechowywane w DB. Teraz przenoszę tę część do nowej usługi C# i przynajmniej muszę zachować tę samą logikę. Problem polega na tym, że struktura jest WIELKA (ponad 220 pól), a tabele, w których jest przechowywany, mają blisko 300 pól. Z mojej struktury 220 pól są odejmowane/obliczane inne ~ 50 pól i wszystkie powinny być aktualizowane w DB. Rzeczywisty kod Delphi jest brzydki mrówka wzrosła ona w ciągu kilku lat, jak sam stół, coś takiego:

'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) 

nie każdy dynamiczny SQL, etc .. Właściwie nie mogę zmienić strukturę DB .. tak, że muszę grać tylko w kodzie i nie jestem pewien, czy jest to konieczne do przetłumaczenia kodu. Tabela jest używana dla niektórych raportów i statystyk. Niektóre pola obliczane/odejmowane muszą radzić sobie z pewnymi stałymi w kodzie źródłowym.

stosowane dev-tools: MS SQL Server 2000, C# .net2.0, VS2008

+2

Dlaczego nie stosuje się procedury składowanej? To będzie dużo prostsze niż to. –

+0

SqlCommand. Chcesz tego po stronie serwera. – Stu

+0

Czy jesteś w stanie dodać nową bazę danych do bazy danych? – granadaCoder

Odpowiedz

2

Najprostsze rozwiązanie dotyczy tutaj, ponieważ sposób działania systemu db działa z ciągami. Tak więc, aby przekazać 270, 500, 1000 parametrów, wszystko, co robię, to przekazanie pojedynczego ciągu znaków, łańcuch zawierający 270 parametrów prawdopodobnie jest znacznie poniżej 2kb ... co w nowoczesnych komputerach ... przenosi 1 ... mieć karę wykonania. Tutaj jest rozwiązanie xml, ale to tylko jabłka i pomarańcze, nadal podajesz ciąg znaków, jednak do obsługi xml potrzebny byłby dodatkowy kod. Więc ... Twój architektura powinna wyglądać następująco:

  1. procedury składowanej na serwerze SQL z 270 parametrów wejściowych:

    Create Procedure sp_Example1 
    (@param1 [type], @param2 [type], @param3 [type], etc...) 
    AS 
    BEGIN 
    [SQL statements] 
    END 
    
  2. Obiekt komenda 270 parametrów:

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

Pamiętaj, że nadal wykonujesz dość intensywną operację, ale twój benchmark powinien być starą aplikacją. Jeśli jest trochę gorzej, nie martwiłbym się o to, ponieważ framework wymaga więcej narzutów obliczeniowych.

nie mam pojęcia, dlaczego to nie będzie sformatować kod ...

+0

Z serwerem SQL, ADO.NET, mam opcję, więc po co używać OLE DB? –

+0

@ Syn123, Co masz na myśli "sposób, w jaki działa ole db z ciągami"? Czy masz na myśli, że wszystkie wartości parametrów są przekazywane jako ciągi i są automatycznie odrzucane? Sprawdź, proszę, również to pytanie http://stackoverflow.com/questions/15135204/sql-server-why-field-val-almost-any-may-be-be-treated-as-quoted-string – ALZ

+0

połączenie z serwerem sql nadal używa ole db Wierzę, że to tylko wersja Microsoftu. Przeczytaj sekcję unicode: http://msdn.microsoft.com/en-us/library/ms810892.aspx. Dostawcy Ole db (ADO.NET) używają portu sql do wysyłania danych ciągów w jasnym tekście tam iz powrotem między serwerem sql a aplikacją. – RandomUs1r

1

OK. Ponieważ możesz dodać nową procedurę przechowywaną, sugerowałbym zapakowanie wszystkich wartości i przesłanie go jako XML do twojej procedury składowanej.

można znaleźć kinda przykładem: http://granadacoder.wordpress.com/2009/01/27/bulk-insert-example-using-an-idatareader-to-strong-dataset-to-sql-server-xml/

Dobrą wiadomością, że przykład mam jest starszy i kodowane do SQL Server 2000 (z OPENXML).

..

To byłoby lepsze niż wysyłanie w dół 300 parametrów do procedury przechowywanej, IMHO.

Inną zaletą, jeśli masz więcej niż jeden wiersz danych, możesz również wysłać to w dół.

......

W "Istota" o tym:

Po pierwsze, można uzyskać "puby" 2000 Baza tutaj:

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

Teraz dodaj ten procedura składowana:

/* 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 

/* Przykład użycia */

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

wielkie dzięki - przeanalizuję tę możliwość i napiszę tutaj mój wynik. Jeszcze raz dziękuję za to, że ten (OPENXML) wciąż jest dla mnie nieznanym obszarem. Czy jest w pełni zgodny z SQL Server 2000? – ALZ

+0

Tak, OPENXML jest "zapakowany" do funkcjonalności TSQL z Sql Server 2000. 2005 i wyżej zastępuje OPENXML z nieco inną składnią, ale zachowują OPENXML dla kompatybilności wstecznej. Bottomline, OPENXML w Sql Server 2000 nie jest voo doo, jest tam do użytku. – granadaCoder

0
  1. Można podzielić tabel do nowych tabel, a następnie utworzyć widoki o tej samej nazwie jak stare stoły, która łączy, przełączniki, odlewów itp, aby przekształcić nowych tabel do starych struktur raporty.

  2. Jeśli używasz poleceń (jak w opublikowanym przez ciebie kodzie Delphi), użyj parametrów, aby zapobiec iniekcji SQL.

  3. Przy obecnej strukturze DB używasz out of the box ORM może być męczące, ponieważ masz mnóstwo kolumn do mapowania. Można utworzyć klasy POCO jako bezpieczny model typu, a następnie użyć notacji danych lub atrybutów niestandardowych, aby uprościć odwzorowanie, a następnie utworzyć polecenia SQL w locie z atrybutów.

0

Brak szczególnych królika wyciągnąć z kapelusza NET ten obawiam się.

Bez zawiłości związanych z "poznaniem" zmieniły się tylko niektóre całkowicie niezależne pola i budując oświadczenie aktualizacyjne tylko dla nich, jesteś wypchany.

Nawet świadomość, że zostałoby lepiej zapisane jako blob, tak naprawdę nie pomaga. Prawdopodobnie nie jest to prawda w żadnym wypadku.

Sparametryzowana kwerenda lub procedura składowana wyglądałaby trochę lepiej w kodzie, ale i tak można to było zrobić w delphi.

Nie ma sposobu, aby powiedzieć, jak to zrobić, ale jeden pomysł, który może mieć przebieg, ukrywa bieżący stół przed wszystkim, ale niewielkim zestawem funkcji.

Na przykład, jeśli chcesz zmienić nazwę, a następnie utwórz widok z bieżącą nazwą. Żadna z rzeczy, które czytają i (być może sporo kodu, który do niej pisze) nie zauważy. Jeśli dojdziesz do punktu, w którym surowy stolik jest dostępny tylko za pomocą widoku i niektórych procedur przechowywanych, możesz rozpocząć hakowanie struktury.

Kod (bez sql) służy tylko do wstawiania dostępu do stylu ORM pomiędzy aplikacjami i tabelą. To decyzja, która powinna być oparta na zestawie umiejętności i kombinacji aplikacji bardziej niż cokolwiek innego.

Jeśli nie jesteś w stanie oddzielić wszystkich aplikacji od konkretnej implementacji, jaką jest ta tabela, to po prostu polerujesz kał. Nie ma sensu wydawanie na to cennych zasobów.

+0

brak jakichkolwiek pól obrazu przedstawiono w tej tabeli, ale w innych przypadkach/tabelach muszę zaktualizować pola binarne (BLOB) - czy tutaj SP jest nieprzydatne? – ALZ

+0

Z pewnością nie sp może być bardzo przydatny, to ukryłoby to tabelę bzdur z aplikacji wszędzie tam, gdzie go używałeś. Podobnie jak ORM, to, czego nie zrobi, sprawi, że obecny projekt tabeli będzie w jakikolwiek sposób dobry. –