2016-04-15 7 views
3

En utilisant EPPlus, je veux lire une table Excel, puis stocker tout le contenu de chaque colonne dans son List correspondant. Je veux qu'il reconnaisse le titre de la table et catégorise le contenu en fonction de cela.EPPlus - Lire Excel Table

Par exemple, si mon tableau Excel est comme ci-dessous:

Id Name  Gender 
1 John  Male 
2 Maria Female 
3 Daniel Unknown 

Je veux que les données à stocker dans List<ExcelData>

public class ExcelData 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public string Gender { get; set; } 
} 

Alors que je peux appeler le contenu en utilisant le nom de rubrique . Par exemple, quand je fais ceci:

foreach (var data in ThatList) 
{ 
    Console.WriteLine(data.Id + data.Name + data.Gender); 
} 

Il me donnera cette sortie:

1JohnMale 
2MariaFemale 
3DanielUnknown 

C'est vraiment tout ce que je suis:

var package = new ExcelPackage(new FileInfo(@"C:\ExcelFile.xlsx")); 
ExcelWorksheet sheet = package.Workbook.Worksheets[1]; 

var table = sheet.Tables.First(); 

table.Columns.Something //I guess I can use this to do what I want 

S'il vous plaît aider :( J'ai passé de longues heures à chercher des exemples de code à ce sujet afin que je puisse en tirer des leçons mais en vain. Je comprends aussi ExcelTo LinQ est géré pour faire cela mais il ne peut pas reconnaître la table.

Répondre

4

Il n'y a pas natif mais si vous utilisez ce que je mets dans ce post:

How to parse excel rows back to types using EPPlus

Si vous voulez pointer à une table que il devra être modifié. Quelque chose comme cela devrait le faire:

public static IEnumerable<T> ConvertTableToObjects<T>(this ExcelTable table) where T : new() 
{ 
    //DateTime Conversion 
    var convertDateTime = new Func<double, DateTime>(excelDate => 
    { 
     if (excelDate < 1) 
      throw new ArgumentException("Excel dates cannot be smaller than 0."); 

     var dateOfReference = new DateTime(1900, 1, 1); 

     if (excelDate > 60d) 
      excelDate = excelDate - 2; 
     else 
      excelDate = excelDate - 1; 
     return dateOfReference.AddDays(excelDate); 
    }); 

    //Get the properties of T 
    var tprops = (new T()) 
     .GetType() 
     .GetProperties() 
     .ToList(); 

    //Get the cells based on the table address 
    var groups = table.WorkSheet.Cells[table.Address.Start.Row, table.Address.Start.Column, table.Address.End.Row, table.Address.End.Column] 
     .GroupBy(cell => cell.Start.Row) 
     .ToList(); 

    //Assume the second row represents column data types (big assumption!) 
    var types = groups 
     .Skip(1) 
     .First() 
     .Select(rcell => rcell.Value.GetType()) 
     .ToList(); 

    //Assume first row has the column names 
    var colnames = groups 
     .First() 
     .Select((hcell, idx) => new { Name = hcell.Value.ToString(), index = idx }) 
     .Where(o => tprops.Select(p => p.Name).Contains(o.Name)) 
     .ToList(); 

    //Everything after the header is data 
    var rowvalues = groups 
     .Skip(1) //Exclude header 
     .Select(cg => cg.Select(c => c.Value).ToList()); 


    //Create the collection container 
    var collection = rowvalues 
     .Select(row => 
     { 
      var tnew = new T(); 
      colnames.ForEach(colname => 
      { 
       //This is the real wrinkle to using reflection - Excel stores all numbers as double including int 
       var val = row[colname.index]; 
       var type = types[colname.index]; 
       var prop = tprops.First(p => p.Name == colname.Name); 

       //If it is numeric it is a double since that is how excel stores all numbers 
       if (type == typeof(double)) 
       { 
        //Unbox it 
        var unboxedVal = (double)val; 

        //FAR FROM A COMPLETE LIST!!! 
        if (prop.PropertyType == typeof(Int32)) 
         prop.SetValue(tnew, (int)unboxedVal); 
        else if (prop.PropertyType == typeof(double)) 
         prop.SetValue(tnew, unboxedVal); 
        else if (prop.PropertyType == typeof(DateTime)) 
         prop.SetValue(tnew, convertDateTime(unboxedVal)); 
        else 
         throw new NotImplementedException(String.Format("Type '{0}' not implemented yet!", prop.PropertyType.Name)); 
       } 
       else 
       { 
        //Its a string 
        prop.SetValue(tnew, val); 
       } 
      }); 

      return tnew; 
     }); 


    //Send it back 
    return collection; 
} 

Voici une méthode d'essai:

[TestMethod] 
public void Table_To_Object_Test() 
{ 
    //Create a test file 
    var fi = new FileInfo(@"c:\temp\Table_To_Object.xlsx"); 

    using (var package = new ExcelPackage(fi)) 
    { 
     var workbook = package.Workbook; 
     var worksheet = workbook.Worksheets.First(); 
     var ThatList = worksheet.Tables.First().ConvertTableToObjects<ExcelData>(); 
     foreach (var data in ThatList) 
     { 
      Console.WriteLine(data.Id + data.Name + data.Gender); 
     } 

     package.Save(); 
    } 
} 

Gave ceci dans la console:

1JohnMale 
2MariaFemale 
3DanielUnknown 

juste être prudent si vous champ Id est un numéro ou une chaîne dans Excel puisque la classe attend une chaîne.

1

Le code ci-dessous lira les données excel dans un datatable, qui est converti en liste de datarows.

if (FileUpload1.HasFile) 
{ 
    if (Path.GetExtension(FileUpload1.FileName) == ".xlsx") 
    { 
     Stream fs = FileUpload1.FileContent; 
     ExcelPackage package = new ExcelPackage(fs); 
     DataTable dt = new DataTable(); 
     dt= package.ToDataTable(); 
     List<DataRow> listOfRows = new List<DataRow>(); 
     listOfRows = dt.AsEnumerable().ToList(); 

    } 
} 
+1

obtenir l'erreur ' « ExcelPackage » ne contient pas une définition pour « ToDataTable » et aucune méthode d'extension « ToDataTable » accepter un premier argument de type « ExcelPackage » n'a pu être trouvée (vous manque une directive à l'aide ou référence d'assemblage?) ' –