2010-12-04 50 views
1

Je suis un XML qui ressemble à ceci:Comment implémenter IDataReader?

<resultset> 
    <datarow> 
     <datacol>Row 1 - Col 1</datacol> 
     <datacol>Row 1 - Col 2</datacol> 
     <datacol>Row 1 - Col 3</datacol> 
     ... 
    </datarow> 
    ... 
</resultset> 
... 

Ma question est, comment puis-je mettre en œuvre l'interface IDataReader avec ce XML? Je suis perdu ...

J'ai développé ceci:

public sealed class SybaseDataReader : IDataReader 
{ 
    private DataSet _dataSet = new DataSet(); 

    #region IDataReader methods implementation 
    // ... 
} 

Je suis sur la bonne voie?

Merci pour les messages constructifs et bien expliqués.

+1

semble bien, utilise http://msdn.microsoft.com/en-us/library/system.xml.xmlreader.aspx aide? – kenny

+0

Pas vraiment, mon problème principal est de charger le DataSet avec le XML: -/ –

+0

Avez-vous l'intention de l'utiliser pour des jeux de résultats très volumineux? –

Répondre

2

Il n'est pas logique d'avoir un DataSet en tant que membre de System.Data.IDataReader. Mieux vaut penser en termes de XmlDocumnet, XDocument ou XmlReader.

+0

Oui, mais comment!? –

+0

@Arnaud: Implémenter un DataReader n'est pas quelque chose de simple. Vous devrez fournir 'GetSchema()' et 'Read()'. Mieux vaut penser à la façon dont vous allez le faire en premier. –

+3

@Arnaud: Mieux encore, avez-vous vraiment besoin d'un DataReader? Je doute d'une façon ou d'une autre de cela. –

0

Cela peut aider ...

//1. Create dataset 
     var ds = new DataSet("A Dataset"); 
     var table = ds.Tables.Add("A Table"); 
     table.Columns.Add("Id", typeof(int)); 
     table.Columns.Add("Description", typeof(string)); 

     //2. Serialize as xml 
     ds.WriteXml(@"C:\temp\dataset.xml"); 

     //3. Go look at the xml file's contents. 
     //Your xml needs to be translated into this schema. 
     //You will have to write this. (Boring transform work...) 
     //Dataset deserialization does not work with arbitrary xml documuents. 


     //4. Loading the xml file 
     var ds2 = new DataSet(); 
     ds2.ReadXml(@"C:\temp\dataset.xml"); 

     //Suggestion. Investigate using LINQ-to-xml. It would be easier to 
     //read the data from your xml schema. You could also load the Dataset tables row by row 
     //using this type of approach 

     //1. Load xml data into an XElement. 
     var element = XElement.Parse(@"<resultset> 
      <datarow> 
       <datacol>Row 1 - Col 1</datacol> 
       <datacol>Row 1 - Col 2</datacol> 
       <datacol>Row 1 - Col 3</datacol> 
      </datarow> 
     </resultset> 
     "); 

     //2. Create a dataset 
     ds = new DataSet("A Dataset"); 
     table = ds.Tables.Add("A Table"); 
     table.Columns.Add("Col1", typeof(string)); 
     table.Columns.Add("Col2", typeof(string)); 
     table.Columns.Add("Col3", typeof(string)); 

     //3. Walk XElements and add rows to tables 
     foreach (var row in element.Elements("datarow")) 
     { 
      var r = table.NewRow();     
      table.Rows.Add(r); 
      int i = 0; 
      foreach (var columnValue in row.Elements("datacol")) 
      { 
       r[i++] = columnValue.Value; 
      } 
     }   
2

j'ai écrit une implémentation simple lecteur de fichiers. Vous pouvez facilement adapter ce pour lire un fichier xml:

public class MyFileDataReader : IDataReader 
{ 
    protected StreamReader Stream { get; set; } 
    protected object[] Values; 
    protected bool Eof { get; set; } 
    protected string CurrentRecord { get; set; } 
    protected int CurrentIndex { get; set; } 

    public MyFileDataReader(string fileName) 
    { 
     Stream = new StreamReader(fileName); 
     Values = new object[this.FieldCount]; 
    } 

Rappelez-vous que IDataReader a plusieurs méthodes que vous ne avez pas besoin de mettre en œuvre en fonction de votre scénario. Mais sans doute il y a quelques implémentations de méthodes que vous ne serez pas en mesure d'éviter:

public void Close() 
    { 
     Array.Clear(Values, 0, Values.Length); 
     Stream.Close(); 
     Stream.Dispose(); 
    } 

    public int Depth 
    { 
     get { return 0; } 
    } 

    public DataTable GetSchemaTable() 
    { 
     // avoid to implement several methods if your scenario do not demand it 
     throw new NotImplementedException(); 
    } 

    public bool IsClosed 
    { 
     get { return Eof; } 
    } 

    public bool NextResult() 
    { 
     return false; 
    } 

    public bool Read() 
    { 
     CurrentRecord = Stream.ReadLine();    
     Eof = CurrentRecord == null; 

     if (!Eof) 
     { 
      Fill(Values); 
      CurrentIndex++; 
     } 

     return !Eof; 
    } 

    private void Fill(object[] values) 
    { 
     //To simplify the implementation, lets assume here that the table have just 3   
     //columns: the primary key, and 2 string columns. And the file is fixed column formatted 
     //and have 2 columns: the first with width 12 and the second with width 40. Said that, we can do as follows 

     values[0] = null; 
     values[1] = CurrentRecord.Substring(0, 12).Trim(); 
     values[2] = CurrentRecord.Substring(12, 40).Trim(); 

     // by default, the first position of the array hold the value that will be 
     // inserted at the first column of the table, and so on 
     // lets assume here that the primary key is auto-generated 
     // if the file is xml we could parse the nodes instead of Substring operations 
    } 

    public int RecordsAffected 
    { 
     get { return -1; } 
    } 

Pour mettre en œuvre IDataReader, est également obligatoire pour mettre en œuvre le IDisposable et les interfaces IDataRecord.

L'IDisposable est facile, mais l'IDataRecord peut être douloureux. Encore une fois, dans ce scénario, il existe certaines méthodes implémentations que nous ne sommes pas en mesure d'éviter:

public int FieldCount 
    { 
     get { return 3;//assuming the table has 3 columns } 
    } 

    public IDataReader GetData(int i) 
    { 
     if (i == 0) 
      return this; 

     return null; 
    } 

    public string GetDataTypeName(int i) 
    { 
     return "String"; 
    } 

    public string GetName(int i) 
    { 
     return Values[i].ToString(); 
    } 

    public string GetString(int i) 
    { 
     return Values[i].ToString(); 
    } 

    public object GetValue(int i) 
    { 
     return Values[i]; 
    } 

    public int GetValues(object[] values) 
    { 
     Fill(values); 

     Array.Copy(values, Values, this.FieldCount); 

     return this.FieldCount; 
    } 

    public object this[int i] 
    { 
     get { return Values[i]; } 
    } 

Espérons que cela aide.