C# 在EPPlus中调用LoadFromCollection时忽略属性

C# 在EPPlus中调用LoadFromCollection时忽略属性,c#,excel,entity-framework-6,epplus,C#,Excel,Entity Framework 6,Epplus,我正在尝试使用以下代码生成Excel文件: public static Stream GenerateFileFromClass<T>(IEnumerable<T> collection, int startrow, int startcolumn, byte[]templateResource) { using (Stream template = new MemoryStream(templateResource))//this is an excel

我正在尝试使用以下代码生成Excel文件:

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");
            }
        }
    }
}
publicstaticstreamgenerateFileFromClass(IEnumerable集合、int-startrow、int-startcolumn、byte[]templateResource)
{
使用(Stream template=new MemoryStream(templateResource))//这是一个用于基本/模板的excel文件
{
使用(var tmpl=new ExcelPackage(模板))
{
Excel工作簿wb=tmpl.工作簿;
如果(wb!=null)
{
如果(wb.Worksheets.Count>0)
{
Excel工作表ws=wb.Worksheets.First();
单元格[startrow,startcolumn].LoadFromCollection(collection,false);
}
返回新的MemoryStream(tmpl.GetAsByteArray());
}
其他的
{
抛出新ArgumentException(“无法加载模板工作簿”);
}
}
}
}
然而,这就像是一种享受。。我想忽略我的类集合中的几个属性,所以它和我的模板匹配。我知道,
LoadFromCollection
将根据类的公共属性在Excel文件中生成列,但当我使用Entity Framework加载类时,如果我将字段标记为private,则EF会抱怨-主要是因为我不想显示的字段之一是键


我尝试使用
[XmlIgnore]
标记我不想要的属性,但没有成功。除了将整个集合加载到数据集或类似的数据集中并从中删除列之外,还有什么方法可以做到这一点?或者强制转换到没有我不需要的属性的基类?

是的,EPPlus为您希望包含的属性提供了一个带有
MemberInfo[]
参数的
.LoadFromCollection()
方法重载

这使我们可以忽略任何具有特定属性的属性

例如,如果要忽略具有此自定义属性的属性:

公共类EpplusIgnore:属性{}
然后我们可以编写一个小的扩展方法,首先查找属性的所有
MemberInfo
对象,而不使用
[EpplusIgnore]
属性,然后返回EPPlus dll中
.LoadFromCollection
方法的正确重载结果

大概是这样的:

公共静态类扩展
{
公共静态ExcelRangeBase LoadFromCollectionFiltered(this ExcelRangeBase@this,IEnumerable collection),其中T:class
{
MemberInfo[]membersToInclude=类型(T)
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p=>!Attribute.IsDefined(p,typeof(EpplusIgnore)))
.ToArray();
返回@this.LoadFromCollection(collection,false,
OfficeOpenXml.Table.TableStyles.None,
BindingFlags.Instance | BindingFlags.Public,
成员(包括);
}
}
例如,在将
个人
集合导出到excel时,这样使用它将忽略
.Key
属性:

公共类人物
{
[签名者]
公共int密钥{get;set;}
公共字符串名称{get;set;}
公共整数{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
var demoData=new List{new Person{Key=1,Age=40,Name=“Fred”},new Person{Key=2,Name=“Eve”,Age=21};
FileInfo fInfo=newfileinfo(@“C:\Temp\Book1.xlsx”);
使用(var excel=new ExcelPackage())
{
var ws=excel.Workbook.Worksheets.Add(“人员”);
ws.Cells[1,1].LoadFromCollectionFiltered(解调数据);
excel.SaveAs(fInfo);
}
}
}
给出我们期望的输出:


谢谢Stewart\R,基于您的工作,我制作了一个新的,用于接收财产名称:

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);
}
公共静态ExcelRangeBase LoadFromCollection(this ExcelRangeBase@this,
IEnumerable集合,字符串[]propertyNames,bool printHeaders),其中T:class
{
MemberInfo[]membersToInclude=类型(T)
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p=>propertyNames.Contains(p.Name))
.ToArray();
返回@this.LoadFromCollection(集合、打印头、,
OfficeOpenXml.Table.TableStyles.None,
BindingFlags.Instance | BindingFlags.Public,
成员(包括);
}

EPPlus
的5.5版开始,
EpplusIgnore
属性被烘焙到库中。

我们可以像下面那样使用它

使用系统;
使用OfficeOpenXml.Attributes;
命名空间ExportToExcel.Services.ExportViewModels
{
[EpplusTable]
公共类学生导出视图模型
{
//[EpplusTableColumn]
[签名者]
公共字符串Id{get;set;}
...
}
}
请注意,
EpplusTable
EpplusTableColumn
属性是必需的

这里是相关测试用例的链接


最近,我不得不在一个项目中使用
EPPlus
,我在这篇博文中记录了设置过程下面是Stewart_R答案的简短版本。如果有人使用通用方法创建excel,请继续使用以下方法

 public static class EPPlusHelper
    {
        public static byte[] GetExportToExcelByteArray<T>(IEnumerable<T> data)
        {
            var memoryStream = new MemoryStream();
            ExcelPackage.LicenseContext = LicenseContext.Commercial;

            using (var excelPackage = new ExcelPackage(memoryStream))
            {
                //To get all members without having EpplusIgnore attribute added
                MemberInfo[] membersToInclude = typeof(T)
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Where(p => !Attribute.IsDefined(p, typeof(EpplusIgnore)))
                .ToArray();

                var worksheet = excelPackage.Workbook.Worksheets.Add("Sheet1");
                worksheet.Cells["A1"].LoadFromCollection(data, true, TableStyles.None, BindingFlags.Instance | BindingFlags.Public,
                membersToInclude);
                worksheet.Cells["A1:AN1"].Style.Font.Bold = true;
                worksheet.DefaultColWidth = 20;

                return excelPackage.GetAsByteArray();
            }
        }
    }

你能不能使用像AutoMapper或自定义映射到另一个只包含所需属性的POCO的东西,然后将新对象集合传递给epplus,而不是EF collectionIt对我有效。但是我创建了一个LoadFromCollectionFiltered方法(这个ExcelRangeBase@this,IEnumerable collection,bool printHeader),以决定是否要在以后打印标题。这是一个非常好的建议,但不幸的是,它对我不起作用。使用IEnumerable的标准LoadFromCollection,只需额外的
public ActionResult ExportToExcel()
        {
            var result= // Here pass your data (list)
            byte[] fileResult = EPPlusHelper.GetExportToExcelByteArray(result);

            return File(fileResult, "application/vnd.ms-excel", "FileName.xlsx");
        }