Newsgroup: it.comp.lang.visual-basic
Titolo: Trasferimento dati DB --> dataset --> XML --> dataset -->DB

Salve a tutti.
Ho la necessità di estrarre dei dati da un database in formato XML, 
trasferirli ad altro pc e quindi inserirli nel db di questo.
Fino all'ultimo passo non ho incontrato problemi, sono riuscito ad 
ottenere il mio dataset con tutti i dati all'interno.
Poi però non sono riuscito in alcun modo a fargli usare il dataset per 
l'aggiornamento del database.
Questo è il codice che utilizzo per la lettura.
     Public Sub SetXML(ByVal sXML As String)
         Dim Data As New DataSet
         Dim stringReader As New StringReader(sXML)
         Dim xmlReader As New XmlTextReader(stringReader)
         Dim xmlDoc As New XmlDocument
         Dim dataAdapter As IDbDataAdapter
         Dim sTableName As String
         xmlDoc.LoadXml(sXML)
         sTableName = 
xmlDoc.DocumentElement.Name
()
         Data.ReadXmlSchema("schema.xsc")
         Data.ReadXml(xmlReader)
         xmlReader.Close()
         stringReader.Close()
         dataAdapter = GetDataAdapter("SELECT * FROM " & sTableName)
         dataAdapter.Update(Data)
     End Sub
     Private Function GetDataAdapter(ByVal sSelectQuery As String) As 
IDbDataAdapter
         Dim myAdapter As IDbDataAdapter
         Dim myCommand As IDbCommand = myConn.CreateCommand
         myCommand.CommandText = sSelectQuery
         Select Case myConn.Database.ToUpper
             Case "TESTDB"
                 myAdapter = New AsaDataAdapter(myCommand)
                 Dim myCmdBuilder As AsaCommandBuilder = New 
AsaCommandBuilder(myAdapter)
             Case Else : Throw New UnknownDBException
         End Select
         Return myAdapter
     End Function
Il codice non da errori, viene eseguito correttamente, ma nel db non 
viene inserito alcunché.
Qualcuno ha qualche idea di dove sbaglio?

nel dataAdapter devi assegnare le property : InsertCommand, DeleteCommand, 
UpdateCommand
se usi OleDB sono di tipo OleDbCommand in cui definisci le singole query per 
l'inserimento, l'eliminazione e l'aggiornamento dei record presenti nel tuo 
dataset.
Poi il dataAdapter a secondo dello stato in cui si trova una riga nel 
DataSet utilizza il comando necessario. 

 UpdateCommand
Non ho assegnato le suddette property poiché faccio uso dell'oggetto
DBCommandBuider che le crea automaticamente, se il problema fosse quello
avrei un runtime error sull'update.

 ha scritto nel messaggio 
news:7924733.Qyuq9iEDWA@samuele...

Perchè non usi direttamente i metodi WriteXML e ReadXML degli oggetti 
DataSet (e nel 2.0 anche sulle singole DataTable).
Fa già tutto lui, salva anche lo stato delle singole righe.
Io l'ho usato su PocketPC per salvarmi in locale lo stato di tabelle 
scaricate da sqlserver e funziona.
Ciao 

 scaricate da sqlserver e funziona.
Ma in locale salvavi su db?
Potresti mostrarmi qualche riga di codice?

 Potresti mostrarmi qualche riga di codice?
No, io leggevo dal DB una datatable, facevo una WriteXml della datatable su 
disco in modo da avere i dati sempre a disposizione anche senza connessione 
di rete.
Lavoravo con questi dati con ReadXml e WriteXml in modo da simulare la 
presenza del DB sul dispositivo, ma in realtà leggevo e scrivevo su disco in 
XML.
Poi quando avevo finito di modificare/cancellare/inserire dati attendevo la 
connessione al DB e ributtavo dentro tutto nel modo classico.
In pratica l'XML mi serviva solo per serializzare/deserializzare i dati, 
tutte le operazioni su di essi avvenivano nel modo standard (tranne gli 
statement SQL che ovviamente non possono essere fatte direttamente sul file 
XML).
Queste sono le sub che mi ero fatto io, considera che erano scritte per 
PocketPC con il compact framework 1.0 e quindi può darsi che possano essere 
ottimizzate o leggermente modificate.
La classe che contiene queste sub è
Public Class DSqlDataSet
    Inherits System.Data.DataSet
Tanto per capire il senso dei "Me"
Public Sub Serialize(ByVal tableName As String, ByVal path As String)
Dim ds As New DataSet
If Not path.EndsWith("\") Then path += "\"
Dim stream As New System.Xml.XmlTextWriter(path + strCName + "." + tableName 
+ ".xml", System.Text.Encoding.ASCII)
ds.Tables.Add(Me.Tables(tableName).Clone)
ds.Tables(0).BeginLoadData()
For Each dr As DataRow In Me.Tables(tableName).Rows
ds.Tables(0).ImportRow(dr)
Next
ds.Tables(0).EndLoadData()
ds.WriteXml(stream, XmlWriteMode.WriteSchema)
stream.Close()
End Sub
Public Sub Serialize(ByVal tableName As String)
Me.Serialize(tableName, DATA_PATH)
End Sub
Public Sub DeleteSerialized(ByVal tableName As String, ByVal path As String)
Try
If Not path.EndsWith("\") Then path += "\"
System.IO.File.Delete(path + strCName + "." + tableName + ".xml")
Catch ex As Exception
End Try
End Sub
Private Sub _DeserializeFile(ByVal tableFileName As String, ByVal ds As 
DataSet)
Dim stream As New System.xml.XmlTextReader(tableFileName)
ds.ReadXml(stream)
stream.Close()
End Sub
''' -----------------------------------------------------------------------------
''' <summary>
''' Carica da disco struttura e dati della tabella con nome 'tableName'
''' </summary>
''' <param name="tableName">
''' Nome della tabella da deserializzare
''' </param>
''' <remarks>
''' La tabella viene salvata su disco come
''' 'DirectoryDati\NomeDatabase.tableName.xml'
''' </remarks>
''' <returns>
''' True se la deserializzazione ha esito positivo
''' False se il file da deserializzare non esiste
''' </returns>
''' -----------------------------------------------------------------------------
Public Function Deserialize(ByVal tableName As String) As Boolean
Return Me.Deserialize(tableName, DATA_PATH)
End Function
''' -----------------------------------------------------------------------------
''' <summary>
''' Carica da disco struttura e dati della tabella con nome 'tableName'
''' </summary>
''' <param name="tableName">
''' Nome della tabella da deserializzare
''' </param>
''' <remarks>
''' La tabella viene salvata su disco come
''' 'path\NomeDatabase.tableName.xml'
''' </remarks>
''' <returns>
''' True se la deserializzazione ha esito positivo
''' False se il file da deserializzare non esiste
''' </returns>
''' -----------------------------------------------------------------------------
Public Function Deserialize(ByVal tableName As String, ByVal path As String) 
As Boolean
Dim ds As New DataSet
Dim dt As DataTable
Dim strFile As String
If Not path.EndsWith("\") Then path += "\"
strFile = path + strCName + "." + tableName + ".xml"
If System.IO.File.Exists(strFile) Then
_DeserializeFile(strFile, ds)
If Me.Tables.Contains(tableName) Then
Me.Tables.Remove(tableName)
End If
dt = ds.Tables(0)
ds.Tables.RemoveAt(0)
Me.Tables.Add(dt)
Return True
Else
Return False
End If
End Function
Public Sub Serialize()
Dim files As String()
files = System.IO.Directory.GetFiles(DATA_PATH, strCName + ".*.xml")
For Each f As String In files
System.IO.File.Delete(f)
Next
For Each t As DataTable In Me.Tables
Me.Serialize(t.TableName)
Next
End Sub
Public Sub Deserialize()
Dim ds As New DataSet
Dim dt As DataTable
Dim files As String()
files = System.IO.Directory.GetFiles(DATA_PATH, strCName + ".*.xml")
Me.Tables.Clear()
For Each t As String In files
_DeserializeFile(t, ds)
dt = ds.Tables(0)
ds.Tables.RemoveAt(0)
Me.Tables.Add(dt)
Next
End Sub

 essere ottimizzate o leggermente modificate.
Purtroppo in questo codice non si vede la parte che mi interessa di più,
ovvero quella in cui il dataset viene trasferito sul db.

 ovvero quella in cui il dataset viene trasferito sul db.
Perchè il trasferimento avviene nel solito modo: 
DataAdapter.Update(DataTable).
Una volta che ti sei riletto i dati con ReadXml tutto viene riportato nel db 
in base allo stato di ogni riga.
Fai un po' di debug e vedi se le righe interessate sono effettivamente 
marcate come modificate.
Ciao 

 avrei un runtime error sull'update.
non č detto che si verifichino per forza errori. Io evito sempre di usare i 
comandi di default, mi creo i comandi specificando per esteso le query da 
adottare fornendo tutti i parametri necessari al commad. Facendo cosě vedo 
che funziona tutto senza problemi. Io la tecnica dell'xml l'ho adottata per 
i palmari. Trasferisco il database in formato XML, il palmare fa quello che 
deve fare, e poi al ritorno, un programma demone percepisce le modifiche 
prodotte da ActiveSync e le riversa dal formato XML al database effettivo.
In genere il comando di default per l'inserimento di nuovi campi dovrebbe 
andare bene...perň non č detto che il programmatore microsoft abbia pensato 
proprio a tutte le evenienze. Probabilmente in qualche passaggio del codice 
hai alterato lo stato delle DataRow nelle tabelle, per caso ha richiamato 
qualche "AcceptChange" nei dataset o nelle datatable? Se si questo ti altera 
lo stato delle righe portandole ad unchanged e quinidi il dataadapter non 
aggiunge i nuovi records.
Per il  resto ti posso garantire che la tecnica funziona perfettamente per 
cui escludo bachi di vb. 

 cui escludo bachi di vb.
No, il problema non è nello stato delle righe, l'ho controllato prima 
dell'update e queste sono {added}.
Ho provato a specificare per esteso la query da usare e così funziona!
Tuttavia sto scrivendo una classe generica, la query non è sempre la 
stessa ma devo generarla dinamicamente.
Mi sono quindi creato una funzione in cui con un FillSchema metto la 
struttura della tabella dentro ad un dataset, poi ciclo sulle varie 
colonne e creo pezzo per pezzo la query, ma...  con il provider che 
serve a me la FillSchema non va, restituisce un'eccezione per un errore 
di sintassi su una parentesi [.
Eppure il codice mi sembra corretto, inoltre con altri provider funziona.
         Dim myAdapter As IDbDataAdapter
         Dim myCommand As IDbCommand = myConn.CreateCommand
        Dim DataSchema As New DataSet
         myCommand.CommandText = sSelectQuery
         Select Case myDBType
             Case DBTypes.AdaptiveSQLAnywhere
                 myAdapter = New AsaDataAdapter(myCommand)
             Case DBTypes.Access
                 myAdapter = New OleDbDataAdapter(myCommand)
             Case Else : Throw New UnknownDBException
         End Select
         Adapter.FillSchema(DataSchema, SchemaType.Source)

di sintassi su una parentesi [.
Io uso questa funzione per generare le query:
private OracleDataAdapter BuildCommand(string SQLStmt, string
TableName, OracleConnection conOraCli, DataSet ds, string sKeyField)
{
	// Data objects
	DataTable dataTable;
	OracleDataAdapter dataAdapter;
	OracleParameter para;
	// Column variables
	string columnName;
	string columnNameNoSpaces;
	OracleType columnDataType;
	int columnSize;
	// String builders to hold the command texts
	string sInsert;
	string sInsertValues;
	string sUpdate;
	string sDelete;
	string sDeleteWhere;
	dataTable = ds.Tables[TableName];
	dataAdapter = new OracleDataAdapter(SQLStmt, conOraCli);
 
    // Create insert, delete and update commands                     
    OracleCommand OracleInsertCommand1 = new OracleCommand();
    OracleCommand OracleUpdateCommand1 = new OracleCommand();
    OracleCommand OracleDeleteCommand1 = new OracleCommand();
 
    // Buil the command strings dynamically                          
    sInsert = "INSERT INTO " + TableName + " (";
 
    sUpdate = "UPDATE " + TableName + " SET ";
 
    sDelete = "DELETE FROM " + TableName + " ";
	sDeleteWhere = " WHERE ";
 
	sInsertValues = "";
 
    // Loop through each column, dyanamically building the command
strings
	foreach (DataColumn dc in dataTable.Columns)
	{
		// Get the column name, datatype and size
		columnName = dc.ColumnName;
		columnNameNoSpaces = columnName.Replace(" ", "_");
		columnDataType = ConvertSystemToDBType(dc.DataType);
//OracleType.VarChar;dc.DataType;
		columnSize = dc.MaxLength;
		if (columnSize < 0 ) columnSize = 0;
 
		sInsert += columnName;
		sInsert += ", ";
 
		sInsertValues += ":";
		sInsertValues += columnNameNoSpaces;
		sInsertValues += ", ";
 
		if (sKeyField.LastIndexOf(columnName) > -1)
		{
			sDeleteWhere += columnName;
			sDeleteWhere += " = :";
			sDeleteWhere += columnNameNoSpaces;
			sDeleteWhere += " AND ";
		}
		else
		{
			sUpdate += columnName;
			sUpdate += " = :";
			sUpdate += columnNameNoSpaces;
			sUpdate += ", ";
		}
 
        // Create and attach the command parameters                  
        para = new OracleParameter(":" + columnNameNoSpaces,
columnDataType, columnSize);
        para.SourceVersion = DataRowVersion.Current;
        para.SourceColumn = columnName;
        OracleInsertCommand1.Parameters.Add(para);
 
		if (sKeyField.LastIndexOf(columnName) > -1)
        {
			// PrimaryID parameter needs the
DataRowVersion.Original SourceVersion
            para = new OracleParameter(columnNameNoSpaces,
columnDataType, columnSize);
            para.SourceVersion = DataRowVersion.Original;
            para.SourceColumn = columnName;
            OracleUpdateCommand1.Parameters.Add(para);
 
            para = new OracleParameter(columnNameNoSpaces,
columnDataType, columnSize);
            para.SourceVersion = DataRowVersion.Original;
            para.SourceColumn = columnName;
			OracleDeleteCommand1.Parameters.Add(para);
			para = new OracleParameter(columnNameNoSpaces,
columnDataType, columnSize);
			para.SourceVersion = DataRowVersion.Original;
			para.SourceColumn = columnName;
			OracleInsertCommand1.Parameters.Add(para);
		}
		else
		{
			// Non-primaryId parameters use the
DataRowVersion.Current SourceVersion
            para = new OracleParameter(columnNameNoSpaces,
columnDataType, columnSize);
            para.SourceVersion = DataRowVersion.Current;
            para.SourceColumn = columnName;
			OracleUpdateCommand1.Parameters.Add(para);
			para = new OracleParameter(columnNameNoSpaces,
columnDataType, columnSize);
			para.SourceVersion = DataRowVersion.Current;
			para.SourceColumn = columnName;
			OracleInsertCommand1.Parameters.Add(para);
		}
	}
	// Complete the command strings
    sInsert = sInsert.Remove(sInsert.Length - 2, 2);
    sInsert += ") VALUES (";
    sInsertValues = sInsertValues.Remove(sInsertValues.Length - 2, 2);
    sInsertValues += ")";
    sInsert += sInsertValues.ToString();
 
    sUpdate = sUpdate.Remove(sUpdate.Length - 2, 2);
    sDeleteWhere = sDeleteWhere.Remove(sDeleteWhere.Length - 4, 4);
	sUpdate += sDeleteWhere;
	sDelete += sDeleteWhere;
 
    // Set the DataAdapter's command objects                         
    OracleInsertCommand1.Connection = conOraCli;
    OracleInsertCommand1.CommandText = sInsert;
 
    OracleUpdateCommand1.Connection = conOraCli;
    OracleUpdateCommand1.CommandText = sUpdate;
 
    OracleDeleteCommand1.Connection = conOraCli;
    OracleDeleteCommand1.CommandText = sDelete;
 
	dataAdapter.DeleteCommand = OracleDeleteCommand1;
    dataAdapter.InsertCommand = OracleInsertCommand1;
    dataAdapter.UpdateCommand = OracleUpdateCommand1;
 
    return dataAdapter;
}
private OracleType ConvertSystemToDBType(System.Type sysDT)
{
	if (sysDT == System.Type.GetType("System.Char"))
		return OracleType.VarChar;
	if (sysDT == System.Type.GetType("System.Int16"))
		return OracleType.Int16;
	if (sysDT == System.Type.GetType("System.Int32"))
		return OracleType.Int32;
	if (sysDT == System.Type.GetType("System.UInt16"))
		return OracleType.UInt16;
	if (sysDT == System.Type.GetType("System.UInt32"))
		return OracleType.UInt32;
	if (sysDT == System.Type.GetType("System.DateTime"))
		return OracleType.DateTime;
	if (sysDT == System.Type.GetType("System.Decimal"))
		return OracleType.Double;
	if (sysDT == System.Type.GetType("System.Double"))
		return OracleType.Double;
	return OracleType.VarChar;
}
Ciao
-- 
Fritz
Togli *ERASE* per rispondere in e-mail.