将复杂对象的iQueryable导出到Excel

我们有一些代码将数据库中的数据导出到Excel,并且运行良好。

主要的问题是我们使用数据库视图来收集所有的数据。 由于我们有多种types的导出对象,这就产生了相当大的观点。

class Event int id string title List<EventDate> Dates string desc class EventDate DateTime start DateTime end List<EventLocation> Locations class EventLocation string address string city string zip class Birthday : Event int balloonsOrdered string cakeText class Meeting : Event string Organizer string Topic 

所以,以上是模型。 BirthdayMeetingEventinheritance,所有Event对象都有一个EventDate对象列表。 每个EventDate对象都有一个开始date,结束date和一个Location对象列表。

我们的目标是find一个dynamic的方式,从数据库中获取数据到Excel文档。 我们宁愿不在数据库中维护一个庞大的视图(因为我们最终会添加更多的事件types)。

我不是那么熟悉.NET的XMLfunction,但我们现在使用的解决scheme使用OpenXML,代码是有道理的。

您的意见和可能的解决scheme非常感谢

您可以使用List<T>和以下代码创build一个CSV文件:

 using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Web; public static void CreateCSV<T>(List<T> list, string csvNameWithExt) { if (list == null || list.Count == 0) return; HttpContext.Current.Response.Clear(); HttpContext.Current.Response.AddHeader( "content-disposition", string.Format("attachment; filename={0}", csvNameWithExt)); HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"; //get type from 0th member Type t = list[0].GetType(); string newLine = Environment.NewLine; using (StringWriter sw = new StringWriter()) { //gets all properties PropertyInfo[] props = t.GetProperties(); //this is the header row //foreach of the properties in class above, write out properties foreach (PropertyInfo pi in props) { sw.Write(pi.Name.ToUpper() + ","); } sw.Write(newLine); //this acts as datarow foreach (T item in list) { //this acts as datacolumn foreach (PropertyInfo Column in props) { //this is the row+col intersection (the value) string value = item.GetType().GetProperty(Column.Name).GetValue(item, null).ToString(); if (value.Contains(",")) { value = "\"" + value + "\""; } sw.Write(value + ","); } sw.Write(newLine); } // render the htmlwriter into the response HttpContext.Current.Response.Write(sw.ToString()); HttpContext.Current.Response.End(); } } 

我改进了Brad的解决scheme,以更好地处理entity framework数据注释:

  • 它从注释中获取显示名称而不是列名
  • 它不会通过注释导出标记为“scaffold = false”的列
  • 它为您提供了一种处理复杂types(不是原始types)

     public static class ExportListToCSV { public static void CreateCSV<T>(List<T> list, string csvNameWithExt) { if (list == null || list.Count == 0) return; HttpContext.Current.Response.Clear(); HttpContext.Current.Response.AddHeader( "content-disposition", string.Format("attachment; filename={0}", csvNameWithExt)); HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"; //get type from 0th member Type t = list[0].GetType(); string newLine = Environment.NewLine; //gets all columns PropertyInfo[] columns = t.GetProperties(); // skip columns where ScaffoldColumn = false // useful to skip column containing IDs for Foreign Keys var props = t.GetProperties(BindingFlags.Instance | BindingFlags.Public) .Select(p => new { Property = p, Attribute = p.GetCustomAttribute<ScaffoldColumnAttribute>() }) .Where(p => p.Attribute == null || (p.Attribute != null && p.Attribute.Scaffold != false)) .ToList(); using (StringWriter sw = new StringWriter()) { //this is the header row foreach (var prop in props) { var pi = prop.Property; string columnName = ""; // outputs raw column name, but this is not really meaningful for the end user //sw.Write(pi.Name + ","); columnName = pi.GetDisplayName(); sw.Write(columnName + ","); } sw.Write(newLine); //this acts as datarow foreach (T item in list) { //this acts as datacolumn foreach (var prop in props) { var column = prop.Property; //this is the row+col intersection (the value) PropertyInfo info = item.GetType().GetProperty(column.Name); //string value = info.GetValue(item, null); string value = GetDescriptionForComplexObjects(info.GetValue(item, null)); if (value.Contains(",")) { value = "\"" + value + "\""; } sw.Write(value + ","); } sw.Write(newLine); } // render the htmlwriter into the response HttpContext.Current.Response.Write(sw.ToString()); HttpContext.Current.Response.End(); } } private static string GetDescriptionForComplexObjects(object value) { string desc = ""; if ( (value != null && !IsSimpleType(value.GetType())) ) { dynamic dynObject = value; if (dynObject != null) { //using Model Extensions, //I made sure all my objects have a DESCRIPTION property //this property must return a string //for an employee object, you would return the employee's name for example //desc = dynObject.DESCRIPTION; } } else { desc = "" + value; } return desc; } public static string GetDisplayName(this PropertyInfo pi) { if (pi == null) { throw new ArgumentNullException(nameof(pi)); } return pi.IsDefined(typeof(DisplayAttribute)) ? pi.GetCustomAttribute<DisplayAttribute>().GetName() : pi.Name; } public static bool IsSimpleType(Type type) { return type.IsPrimitive || new Type[] { typeof(Enum), typeof(String), typeof(Decimal), typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan), typeof(Guid) }.Contains(type) || Convert.GetTypeCode(type) != TypeCode.Object || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0])) ; } } 

    }