2010-10-13 19 views
0

Supposons que vous avez un fichier CSV avec la structure suivanteComment renvoyer des objets entièrement remplis à l'aide de FileHelpers pour des données partiellement complètes?

LINE1: ID,Description,Value 
LINE2: 1,Product1,2 
LINE3: ,,3 
LINE4: ,,4 
LINE5: 2,Product2,2 
LINE6: ,,3 
LINE7: ,,5 

Avec la classe correspondante FileHelpers définition

[DelimitedRecord(",") ] 
[IgnoreFirst(1)] 
public class Product 
{ 
    public int ID { get; set; } 
    public string Description { get; set; } 

    [FieldConverter(ConverterKind.Decimal)] 
    public decimal Val{ get; set; } 
} 

Comment utiliser FileHelpers, pour retourner des objets tels que chaque objet est entièrement rempli? Permettez-moi de clarifier, actuellement, le résultat de l'utilisation engine.ReadFile ne produira que des objets des lignes 2 et 5 comme entièrement rempli, ce qui est logique puisque les champs sont vides. Toutefois, les objets des lignes 3 et 4 doivent également avoir les mêmes ID et Description que la ligne 1. Le champ Value doit rester intact pour chaque ligne. Je ne suis pas sûr du bon terme pour les données, mais il semble être «partiellement normalisé».

Mon approche actuelle pour résoudre ceci est la suivante en utilisant l'événement AfterRead. Je n'ai pas une bonne compréhension des événements, des gestionnaires d'événements, des délégués, etc., donc je cherche un moyen alternatif pour y parvenir en utilisant FileHelpers. Il semble aussi très maladroit.

// call the csv repo using the ffg lines within a console app 
    var repo2 = new CSVRepositoryBase<Product>(); 
    repo2.AfterRead +=new AfterReadHandler<object>(repo2_AfterRead); 
    var products = repo2.Read("some file path"); 

    public static Product PreviousRecord { get; set; } 

    private static void repo2_AfterRead 
     (EngineBase engine, FileHelpers.Events.AfterReadEventArgs<object> e) 
    { 
     var record = (Product)e.Record; 

     if (PreviousRecord == null) 
     { 
      PreviousRecord = new Product(); 
      PreviousRecord.ID = record.ID; 
     } 

     if (String.IsNullOrEmpty(record.ID)) // newline record = blank row 
     { 
      record.ID = PreviousRecord.ID; 
     } 
     PreviousRecord.ID = record.ID; 

    } 


public class CSVRepositoryBase<T> where T : class 
{ 
    // shorten for brevity 

    public IEnumerable<T> Read(string fileName){/*snip*/ } 

    #region Events 
    public event AfterReadHandler<object> AfterRead 
    { 
     add { engine.AfterReadRecord += value; } 
     remove { engine.AfterReadRecord -= value; } 
    } 
    #endregion 
} 

Répondre

2

Vous pouvez essayer d'utiliser les interfaces pour AfterRead au lieu d'événements comme celui-ci.

Si je comprends bien que vous devez faire quelque chose comme ça:

[DelimitedRecord(",") ] 
[IgnoreFirst(1)] 
public class Product 
:INotifyRead 
{ 
    public int? ID; 
    public string Description; 

    [FieldConverter(ConverterKind.Decimal)] 
    public decimal? Val; 

    private static Product Previuous; 

    public void AfterRead(EngineBase engine, string line) 
    { 
     if (!ID.HasValue && Previous != null) 
       this.ID = Previus.ID; 

     if (!Val.HasValue && Previous != null) 
       this.Val= Previus.Val; 

     Previuous = this; 
    } 
} 

Hope this helps

+0

J'utilise un dll construit à partir du tronc sourceforge - de sorte que le ci-dessus devrait être la version générique 'INotifyRead <> '. Cependant, les lignes ffg 'BeforeReadEventArgs e = null; if (MustNotifyRead) {e = nouveau BeforeReadEventArgs (ceci, enregistrement, currentLine, LineNumber); skip = OnBeforeReadRecord (e); if (e.RecordLineChanged) line.ReLoad (e.RecordLine);} '(EventEngineBase.cs: 61) lève une exception 'Impossible de convertir un objet de type' Product 'en type' FileHelpers.Events.INotifyRead'1 [System. Objet]'.' – Ahmad

+0

@marcoMeli - ah, j'ai trouvé mon problème. J'utilisais la version non générique de la classe FileHelper 'FileHelperEngine (typeOf (Product))' au lieu de 'new FileHelper ()'. – Ahmad