Hur ser den XML ut som du stoppar in?
Sedan en liten följdfråga. ;)
Om datatypen är XML - varför stoppar du in datan som en sträng och inte som XML?
13 svar · 807 visningar · startad av aleborg
Jag har en klass som ser ut ungefär så här:
[Serializable]
[XmlRootAttribute("Basket", Namespace = "")]
public class Basket
{
private int
userid = 0;
....
[XmlElement( ElementName = "UserID" )]
public int UserID
{
get { return id; }
set { id = value; }
}
....
}
Den här klassen sparar jag i en MS SQL 2005 databas, fältet den sparas i är av typen xml. För att konvertera klassen har jag följande kod:
public static bool Add(Basket basket)
{
XmlSerializer mySerializer = new XmlSerializer(typeof(Basket));
StringWriter basketCollXML = new StringWriter();
mySerializer.Serialize(basketCollXML, basket);
DBAccess db = new DBAccess();
db.Parameters.Add(new SqlParameter( "@basket", basketCollXML.ToString() ));
int result = db.ExecuteNonQuery( "sp_Basket_Add" );
if( result > 0 )
return true;
else
return false;
}
Så långt fungerar allt som det ska, problemet uppstår när jag ska konvertera tillbaka:
public static GenericCollection<Basket> Get ()
{
GenericCollection<Basket> usrC = new GenericCollection<Basket>();
DBAccess db = new DBAccess();
SqlDataReader dr = (SqlDataReader)db.ExecuteReader("sp_Basket_Get");
if (dr.HasRows)
{
while (dr.Read())
{
XmlSerializer mySerializer = new XmlSerializer(typeof(GenericCollection<BasketItem>));
StringReader basketCollXML = new StringReader(dr["Basket"].ToString());
Basket bsk = (Basket)mySerializer.Deserialize(basketCollXML);
bsk.ID = Convert.ToInt32(dr["ID"]);
usrC.Add(bsk);
}
}
else
return new GenericCollection<Basket>();
return usrC;
}
ger felet:
System.InvalidOperationException: There is an error in XML document (1, 2). ---> System.InvalidOperationException: <Basket xmlns=''> was not expected.
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderGenericCollection1.Read7_GenericCollection()
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)
Vad har jag missat? Känns som om jag missat nått i min klass och dess xmlattribut.
Hur ser den XML ut som du stoppar in?
Sedan en liten följdfråga. ;)
Om datatypen är XML - varför stoppar du in datan som en sträng och inte som XML?
Första raden ser ut så här(för mycket och för känslig info att lägga ut allt):
<Basket xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://kundwebb.aleborg.se">
Orsaken till att jag stoppar in en sträng är ren lathet, har inte orkat kolla upp än vilken datatyp i .NET som ska användas för att skicka in, basketCollXML fick jag fel på när jag stoppade in utan att gjort den till sträng.
Jag har testat med och utan namespace.
LOL
Rätt bra om man försöker deserialize till samma typ av objekt :e
XmlSerializer mySerializer = new XmlSerializer(typeof(GenericCollection<BasketItem>));
ska vara
XmlSerializer mySerializer = new XmlSerializer(typeof(Basket));
ibland är man ju blind :e
Jag har 2 påpekande som jag gärna delar med mig av.
Först:
Om du inte måste kunna läsa ut informationen från databasen så föreslår jag att du serializerar ner det som binary istället för XML, klart mycket bättre ur prestanda synpunkt.
Så nu till den viktiga punkten:
Tänk dig för när du gör som du gör, för om du börjar ändra runt i din C# klass och ändrar i den så kommer du ha en XML serialization som inte matchar din klass det kan ge dig problem när du sedan vill deserializera tillbaka information till ett objekt. Nu har jag för mig att .NET 2.0 är lite mer förlåtande än vad .NET 1.1 va med att deserializera till objekt som inte riktigt matchade XML datan.
Been there, done that. Slutade med att jag byggde en konverterapplikation som plockade upp XML datan kontrollerade vilken version som den vara serializerade med och sedan konverterade jag till rätt version och serializerade tillbaka till nuvarande version av min klassen, jobbigt men det fungerade :)
- M
Har du nått förslag på hur man annars ska göra det?
Det jag gör är att jag sparar ner en beställning som sen ska behandlas av av vårt ekonomisystem på följande sätt:
1. kunden lägger beställningen via webben
2. en windows-service ligger o lyssnar och hämtar nya ordrar var 30:e sekund
3. servicen skapar fakturor, skriver ut dem på skrivare och mailar iväg dem vid behov
4. när fakturan väl är skapad så sparas samtliga beställda domäner på samma sätt, en hel "domän-klass" sparas i databasen. servicen kontrollerar även var 30:e sekund efter nya domäner som är betalda och beställer alla betalda domäner.
att spara all den här infon i en "order"-tabell samt en "domän"-tabell skulle kräva många timmars arbete samt gigantiska tabeller(antalet fält skulle bli många), nått som jag helst vill undvika. Har sett att man kan sätta en hel del xml-attribut, isnullable osv, man kan inte göra nya objekt i en klass "optional" eller dylikt, så om vissa fält inte matchar så bryr sig inte systemet?
Nu finns det iofs aldrig nån risk att ordrar finns kvar nån längre stund och är inkompatibla men däremot domäner kan ligga på vänt i upp till en månad!
att spara all den här infon i en "order"-tabell samt en "domän"-tabell skulle kräva många timmars arbete samt gigantiska tabeller(antalet fält skulle bli många), nått som jag helst vill undvika
Jag hade nog gjort en order tabell och en domän tabell ändå, detta är information som du garanterat kommer att vilja använda dig av vid senare tillfällen. Det gör det då mycket enklara att söka ut den information som du behöver om du byggt en korrekt databasmodell.
Lite nyfiken på vad du menar med gigantiska tabeller, hur många fält kan varje tabell innehålla egentligten, mycket att av den information som läggs i din ordertabell samt domäntabell måste ju vara information som du redan har, eller ändå vill ha i en databas. Eller har jag inte riktigt förstått vad det är man beställer...
- M
Får väl sätta mig och göra tabellerna :(
Beror vad man anser med stora men vi pratar närmare hundra kolumner, det som läggs i en order delas upp på flera tabeller efter att ordern behandlas, vi pratar omm dubbla uppsättningar kontaktuppgifter(kontakt + faktureringsuppgifter), Information om domän, ägare osv(kan i vissa fall vara helt annorlunda än kontaktuppgifterna), info om den beställda tjänsten(server, period osv) m.m. så det blir en hel del.
Får väl sätta mig och göra tabellerna
Gör dem inte för att jag säger det, gör dem för att du själv vill ha dem så, eller gör som du tänkt från början.
vi pratar omm dubbla uppsättningar kontaktuppgifter
Är inte det information som du redan har, har du inte redan en kunddatabas, så det bara blir ett ID i din orderdatabas?
Information om domän, ägare osv
Är inte det information som du är intresserad av att kunda söka igenom på ett effektivt sätt. Kunda plocka fram alla domäner som en kund har? Plocka fram domäner som går ut om en månad? Plocka fram ägarne till den specifik domän?
info om den beställda tjänsten
Samma sak här, har du inte redan alla tjänster i en databas, så det bara blir en ny tabell som binder ihop en order, kund och tjänst med en tidsperiod.
Om du inte i förväg har all den här information lagrad i en databas så förstår jag att du tycker att det bli mycket jobb, men tänk istället på hur mycket jobb det blir längre fram när du inser hur värdefullt det hade varit att ha en ordentligt databas med all information sparad på ett korrekt sätt.
Om du redan har det mesta av informationen sparad på en korrekt databasmodell så blir det inte så mycket information som måste tillföras till din databas för att du skall kunna hanterar en ny funktion (så som order) i din applikation. Jag menar om du redan har en databas som har alla dina kunder och alla din tjänster och allt du vill är att dina kunder skall kunna beställa din tjänster är att skapa en order tabell som lagrar information om vilken kund som beställt vilken tjänst...
- M
En order läggs via webbsidan och sparas, en service går sen igenom samtliga nya ordrar(som just nu sparas i XML-format) och lägger in det i rätt tabeller, därefter raderas ordern. Så max tid som ordern ligger på det här sättet är 30 sekunder innan systemet tar hand om den. Innan kunden har ett kundnummer så är det svårt att spara kundens tjänster m.m. Men allt sparas fast det kan inte göras direkt.
Det är som sagt värre med domäner som sparas efter att ordern har blivit processad, även dom i XML-format, dom ligger på plats tills dess att fakturan är betald, vilket kan ta upp till en månad.
Varför vill du ta bort ordern, jag skulle varit glad över att ha en orderhistorik. Jag förstår inte riktigt hur logiken fungerar men det är ju inte mitt problem :).
Men det verkar lite omständigt att först lägga ner ordern och sedan låta en services processa den, varför inte processa ordern direkt från websidan, efter att kunden har matat in alla uppgifter om sig själv. Det betyder att du har ett kundnummer på kunden innnan order är lagd, vilket då underlättar att spara kundens tjänster...
Generellt så kan man säga att ingen information som tillförs en databas skall med automatik tas bort, alltså bör man låta sådan information som order ligga kvar och "skräpa" i databasen ett tag iallafall, kanske 5 år. Innan den tas bort.
- M
Gladh skrev:
Varför vill du ta bort ordern, jag skulle varit glad över att ha en orderhistorik. Jag förstår inte riktigt hur logiken fungerar men det är ju inte mitt problem :).
Vi ser ändå när ordern har skapats, fakturan innehåller alla tjänster kunden beställde samt att allt läggs upp som tjänster tillhörande kundens konto, tjänsten innehåller datum då den skapades, dvs beställdes.
Gladh skrev:
Men det verkar lite omständigt att först lägga ner ordern och sedan låta en services processa den, varför inte processa ordern direkt från websidan, efter att kunden har matat in alla uppgifter om sig själv. Det betyder att du har ett kundnummer på kunden innnan order är lagd, vilket då underlättar att spara kundens tjänster...
- M
Vi har det så idag men det är omöjligt, för mycket problem uppstår. Det tar för lång tid att göra allt vilket medför att kunden ofta klickar flera gånger på "Slutför"...
Vad som händer är följande:
1. Kunden skapas i Mamut(vårt ekonomiprogram), ett kundnummer returneras och kunden sparas i vår databas. Mamut tar 1-5 sekunder på sig för detta.
2. Webbkonton läggs upp på våra servrar, vilket kan vara en tidskrävande process. Info om kontot och dess tjänster sparas i vår databas. Servern kan ta 1-3 sekunder på sig innan den returnerar ett svar.
3. 1-2 fakturor skapas i Mamut(beroende på om kunden valt att få separata fakturor för webbpaket och domäner), Mamut returnerar fakturanumret och fakturan samt dess orderrader sparas i vår databas. Mamut tar 1-5 sekunder på sig att utföra detta.
Lägg ihop dom sekunderna så ser du att det tar på tok för lång tid att bearbeta online, dessutom gör tjänsten en hel del andra saker, som t ex skickar ut påminnelser, beställer betalda domäner, skriver ut och mailar fakturorna m.m.
Tyvärr är Mamut segt, vilket vi inte kan göra nått åt.
Vår logik för användare ser ut så här:
Användare
|--Adresser
| |--Kontakt
| |--Faktura
|
|--Konton
| |--Kontonamn
| | |--Tjänster (typ av tjänst, server m.m.)
|
|--Fakturor
| |--Fakturanummer
| | |--Fakturader
| |--Betalda fakturor
|
|--Nyhetsbrev
| |--Prenumeration
Vi sparar all info vi kan, och kan få ut allt om kunden, när beställning gjordes m.m. därför känns det onödigt att dessutom spara ordern i sin helhet.
Sjävklart är det att föredra att göra allt direkt, men det är inte så enkelt tyvärr, i vilket annat fall som helst skulle jag göra så men här behöver ordern processas ganska rejält först.
Vi sparar all info vi kan, och kan få ut allt om kunden, när beställning gjordes m.m. därför känns det onödigt att dessutom spara ordern i sin helhet.
Om du redan har all information om kunden och beställningar så finns det ju ingen anledning att spara ner den igen. Så fall skulle jag valt din lösning med att serializera ner ett objekt (om du ändå aldrig tänker använda den datan, utan har den någon annanstans).
Det gör det enkelt för dig, men som sagt, du kan få problem om du har 2 olika versioner av din Order klass som serializeras ner, så tänk till en extra gång när du bestämer hur din order klass ser ut.
- M
Gladh skrev:
Det gör det enkelt för dig, men som sagt, du kan få problem om du har 2 olika versioner av din Order klass som serializeras ner, så tänk till en extra gång när du bestämer hur din order klass ser ut.
- M
tror inte att det kjommer att hända iofs eftersom den körs var 30:e sekund.
Men däremot kommer jag ändra domänklassen.