2014-09-01 10 views
8

Sto cercando di generare un file Excel utilizzando il seguente codice:proprietà Ignorare quando chiamata in LoadFromCollection EPPlus

public static Stream GenerateFileFromClass<T>(IEnumerable<T> collection, int startrow, int startcolumn, byte[]templateResource) 
     { 
using (Stream template = new MemoryStream(templateResource))//this is an excel file I am using for a base/template 
    { 
     using (var tmpl = new ExcelPackage(template)) 
     { 
      ExcelWorkbook wb = tmpl.Workbook; 
      if (wb != null) 
      { 
       if (wb.Worksheets.Count > 0) 
       { 
        ExcelWorksheet ws = wb.Worksheets.First(); 
        ws.Cells[startrow, startcolumn].LoadFromCollection<T>(collection, false); 
       } 
       return new MemoryStream(tmpl.GetAsByteArray()); 
      } 
      else 
      { 
       throw new ArgumentException("Unable to load template WorkBook"); 
      } 
     } 
    } 
} 

Questo funziona come un piacere, però .. Io voglio ignorare un paio di immobili a mia collezione di classi, quindi corrisponde al mio modello. So che LoadFromCollection genererà colonne nel file Excel in base alle proprietà pubbliche della classe, ma mentre sto caricando la classe utilizzando Entity Framework, se contrassegno il campo come privato, EF si lamenta, principalmente perché uno dei campi Non voglio mostrare è la chiave.

Ho provato a contrassegnare le proprietà che non desidero utilizzando [XmlIgnore], senza risultato. C'è un modo per farlo, a meno di caricare l'intera collezione in un set di dati o alcuni di essi e tagliare le colonne fuori da quello? O il casting su una classe base senza le proprietà di cui non ho bisogno?

+1

Non potresti usare qualcosa come automapper o mappatura personalizzata ad un altro POCO cui solo le proprietà desiderate e quindi passare tale nuova collezione oggetto a epplus, invece della collezione EF –

risposta

14

Sì, EPPlus fornisce un sovraccarico del metodo .LoadFromCollection<T>() con un parametro MemberInfo[] per le proprietà che si desidera includere.

Questo ci dà tutto ciò di cui abbiamo bisogno per ignorare qualsiasi proprietà con un determinato attributo.

Per esempio, se vogliamo ignorare le proprietà con questo attributo personalizzato:

public class EpplusIgnore : Attribute { } 

allora possiamo scrivere un po 'di metodo di estensione prima trovare tutte MemberInfo oggetti per le proprietà senza l'attributo [EpplusIgnore] poi tornare alla risultato del corretto sovraccarico del metodo .LoadFromCollection nella DLL di EPPlus.

Qualcosa di simile a questo:

public static class Extensions 
{ 
    public static ExcelRangeBase LoadFromCollectionFiltered<T>(this ExcelRangeBase @this, IEnumerable<T> collection) where T:class 
    { 
     MemberInfo[] membersToInclude = typeof(T) 
      .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
      .Where(p=>!Attribute.IsDefined(p,typeof(EpplusIgnore))) 
      .ToArray(); 

     return @this.LoadFromCollection<T>(collection, false, 
      OfficeOpenXml.Table.TableStyles.None, 
      BindingFlags.Instance | BindingFlags.Public, 
      membersToInclude); 
    } 

} 

Così, ad esempio, utilizzando in questo modo ignorerà la proprietà .Key quando si esporta una raccolta Person di eccellere:

public class Person 
{ 
    [EpplusIgnore] 
    public int Key { get; set; } 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var demoData = new List<Person> { new Person { Key = 1, Age = 40, Name = "Fred" }, new Person { Key = 2, Name = "Eve", Age = 21 } }; 

     FileInfo fInfo = new FileInfo(@"C:\Temp\Book1.xlsx"); 
     using (var excel = new ExcelPackage()) 
     { 
      var ws = excel.Workbook.Worksheets.Add("People"); 
      ws.Cells[1, 1].LoadFromCollectionFiltered(demoData); 

      excel.SaveAs(fInfo); 
     } 
    } 
} 

Dare l'uscita che avevamo expect:

enter image description here

+0

Funziona per me. Ma ho creato un metodo LoadFromCollectionFiltered (questo ExcelRangeBase @questo, IEnumerable collection, bool printHeader) per decidere se voglio stampare l'intestazione o meno dopo. –

+0

Questo è un suggerimento fantastico, ma sfortunatamente non funziona per me. Utilizzando lo standard LoadFromCollection per un oggetto IEnumerable , funziona perfettamente, solo con le colonne aggiuntive. Quando utilizzo il metodo filtrato che hai fornito qui, ricevo un errore sulla dichiarazione dei tipi: 'Proprietà fornite nel parametro Proprietà deve essere dello stesso tipo di T' –

+0

Risolto il mio problema; la mia classe ereditava da un'altra classe e Epplus non sta verificando i sottotipi o l'ereditarietà quando verifica il tipo di dichiarazione.Pertanto, ho appena dovuto aggiungere un'altra clausola where per assicurarsi che non includesse la classe genitore nella matrice 'MemberInfo'. Come: '.Where (p => p.DeclaringType! = Typeof (ParentObject))' –

2

Grazie Stewart_R, in base al lavoro che ho fatto uno nuovo che riceve i nomi di proprietà:

public static ExcelRangeBase LoadFromCollection<T>(this ExcelRangeBase @this, 
    IEnumerable<T> collection, string[] propertyNames, bool printHeaders) where T:class 
{ 
    MemberInfo[] membersToInclude = typeof(T) 
      .GetProperties(BindingFlags.Instance | BindingFlags.Public) 
      .Where(p=>propertyNames.Contains(p.Name)) 
      .ToArray(); 

    return @this.LoadFromCollection<T>(collection, printHeaders, 
      OfficeOpenXml.Table.TableStyles.None, 
      BindingFlags.Instance | BindingFlags.Public, 
      membersToInclude); 
}