有没有一种快速将实体转换为 .csv 文件的方法?

10

目前,我有:

        string outputRow = string.Empty;
        foreach (var entityObject in entityObjects)
        {
            outputRow = entityObject.field1 + "," + entityObject.Field2  etc....
        }

我对Entity Framework还很陌生,有没有更快的方法?


看起来所有的答案都使用了反射。我很好奇是否有任何不使用反射的方法来完成这个任务?虽然我猜可能不可能。 - Brady Moritz
你可以尝试我的超轻量级分隔文件编写器:https://gist.github.com/eranbetzalel/5371817#file-delimitedfilewriter-cs - Eran Betzalel
4个回答

27

以下是一段示例代码,展示了一种简单而强大的方法来实现您想要的功能,无需硬编码属性名称(使用反射):

 /// <summary>
 /// Creates a comma delimeted string of all the objects property values names.
 /// </summary>
 /// <param name="obj">object.</param>
 /// <returns>string.</returns>
 public static string ObjectToCsvData(object obj)
 {
     if (obj == null)
     {
         throw new ArgumentNullException("obj", "Value can not be null or Nothing!");
     }
  
     StringBuilder sb = new StringBuilder();
     Type t = obj.GetType();
     PropertyInfo[] pi = t.GetProperties();
  
     for (int index = 0; index < pi.Length; index++)
     {
         sb.Append(pi[index].GetValue(obj, null));
  
         if (index < pi.Length - 1)
         {
            sb.Append(",");
         }
     }
  
     return sb.ToString();
 }

更多相关内容:

对象转CSV

如何将对象列表转换为CSV

C#中是否有任何CSV读写库

在.NET中编写CSV文件

LINQ to CSV:以您想要的方式获取数据

LINQ to CSV库


如果您的任何属性包含逗号,则会失败。 - Sam
@Sam 这是真的,但如果你只是在模型中添加一个.Replace(",", ",")或类似的结构,那么你就没问题了。甚至用chr(",")替换也可以解决问题。 - Brandon Osborne

6

我采纳了Leniel的建议,并将其包装成一个功能齐全的“写入器”,它还允许您过滤要写入的属性。以下是您可以使用的代码:

public class CsvFileWriter
{
    public static void WriteToFile<T>(string filePath, List<T> objs, string[] propertyNames)
    {
        var builder = new StringBuilder();
        var propertyInfos = RelevantPropertyInfos<T>(propertyNames);
        foreach (var obj in objs)
            builder.AppendLine(CsvDataFor(obj, propertyInfos));

        File.WriteAllText(filePath, builder.ToString());
    }

    public static void WriteToFileSingleFieldOneLine<T>(string filePath, List<T> objs, string propertyName)
    {
        var builder = new StringBuilder();
        var propertyInfos = RelevantPropertyInfos<T>(new[] { propertyName });
        for (var i = 0; i < objs.Count; i++)
        {
            builder.Append(CsvDataFor(objs[i], propertyInfos));

            if (i < objs.Count - 1)
                builder.Append(",");
        }

        File.WriteAllText(filePath, builder.ToString());
    }

    private static List<PropertyInfo> RelevantPropertyInfos<T>(IEnumerable<string> propertyNames)
    {
        var propertyInfos = typeof(T).GetProperties().Where(p => propertyNames.Contains(p.Name)).ToDictionary(pi => pi.Name, pi => pi);
        return (from propertyName in propertyNames where propertyInfos.ContainsKey(propertyName) select propertyInfos[propertyName]).ToList();
    }

    private static string CsvDataFor(object obj, IList<PropertyInfo> propertyInfos)
    {
        if (obj == null)
            return "";

        var builder = new StringBuilder();

        for (var i = 0; i < propertyInfos.Count; i++)
        {
            builder.Append(propertyInfos[i].GetValue(obj, null));

            if (i < propertyInfos.Count - 1)
                builder.Append(",");
        }

        return builder.ToString();
    }
}

0
string csv = "";
//get property names from the first object using reflection    
IEnumerable<PropertyInfo> props = entityObjects.First().GetType().GetProperties();

//header 
csv += String.Join(", ",props.Select(prop => prop.Name)) + "\r\n";

//rows
foreach(var entityObject in entityObjects) 
{ 
    csv += String.Join(", ", props.Select(
        prop => ( prop.GetValue(entityObject, null) ?? "" ).ToString() 
    ) )
    + "\r\n";
}
  • 使用StringBuilder处理大量的实体会更好。
  • 代码没有检查当entityObjects为空时的情况。

0

在 @mBria 的代码基础上,我进行了更新,以便您可以使用点符号提供相关表属性:

public class CsvFileWriter
{
    public static void WriteToFile<T>(string filePath, List<T> objs, string[] propertyNames)
    {
        var builder = new StringBuilder();
        var propertyInfos = RelevantPropertyInfos<T>(propertyNames);
        foreach (var obj in objs)
            builder.AppendLine(CsvDataFor(obj, propertyInfos));

        File.WriteAllText(filePath, builder.ToString());
    }

    public static void WriteToFileSingleFieldOneLine<T>(string filePath, List<T> objs, string propertyName)
    {
        var builder = new StringBuilder();
        var propertyInfos = RelevantPropertyInfos<T>(new[] { propertyName });
        for (var i = 0; i < objs.Count; i++)
        {
            builder.Append(CsvDataFor(objs[i], propertyInfos));

            if (i < objs.Count - 1)
                builder.Append(",");
        }

        File.WriteAllText(filePath, builder.ToString());
    }
        public static string GetCSVData<T>(List<T> objs, string[] propertyNames, string[] renameHeaders)
        {
            var propertyInfos = RelevantPropertyInfos<T>(propertyNames);
            var builder = new StringBuilder();

            if (renameHeaders != null && renameHeaders.Count() > 0)
                builder.AppendLine("\"" + String.Join("\",\"", renameHeaders.Select(i => i.Replace("\"", "'"))) + "\"");
            else
                builder.AppendLine(String.Join(",", propertyInfos.Select(i => i.Name).ToList()));

            foreach (var obj in objs)
                builder.AppendLine(CsvDataFor(obj, propertyInfos));

            return builder.ToString();
        }
        
        private static List<PropertyInfo> RelevantPropertyInfos<T>(IEnumerable<string> propertyNames)
        {
            var propertyInfos = typeof(T).GetProperties().Where(p => propertyNames.Contains(p.Name)).ToDictionary(pi => pi.Name, pi => pi);
            propertyInfos.Remove("EntityAspect");

            // Adding related objects
            foreach (var property in typeof(T).GetProperties())
            {
                if (property.PropertyType.Namespace == "System.Collections.Generic") // if property is a collection
                {
                    var subType = property.PropertyType.GenericTypeArguments[0]; // Get the type of items in collection
                    var subProperties = subType.GetProperties().Where(p => propertyNames.Contains($"{property.Name}.{p.Name}")); // Get properties of related object

                    foreach (var subProperty in subProperties)
                    {
                        propertyInfos.Add($"{property.Name}.{subProperty.Name}", subProperty); // Add subproperties to propertyInfos
                    }
                }
                else if (!property.PropertyType.Namespace.StartsWith("System")) // if property is an object
                {
                    var subProperties = property.PropertyType.GetProperties().Where(p => propertyNames.Contains($"{property.Name}.{p.Name}")); // Get properties of related object

                    foreach (var subProperty in subProperties)
                    {
                        propertyInfos.Add($"{property.Name}.{subProperty.Name}", subProperty); // Add subproperties to propertyInfos
                    }
                }
            }

            return (from propertyName in propertyNames where propertyInfos.ContainsKey(propertyName) select propertyInfos[propertyName]).ToList();
        }

        private static string CsvDataFor<T>(T obj, List<PropertyInfo> propertyInfos)
        {
            var values = new List<string>();

            foreach (var propertyInfo in propertyInfos)
            {
                try
                {
                    // Check if it's a nested property
                    if (propertyInfo.ReflectedType.Name != obj.GetType().Name)
                    {
                        var property = typeof(T).GetProperty(propertyInfo.ReflectedType.Name);

                        if (property != null)
                        {
                            var subProperty = property.PropertyType.GetProperty(propertyInfo.Name);

                            if (subProperty != null)
                            {
                                if (property.PropertyType.Namespace == "System.Collections.Generic") // if it's a collection
                                {
                                    var collection = property.GetValue(obj) as IEnumerable;

                                    if (collection != null)
                                    {
                                        values.Add(String.Join(";", from object item in collection select subProperty.GetValue(item)?.ToString()));
                                    }
                                    else
                                    {
                                        values.Add(""); // Add empty value if collection is null
                                    }
                                }
                                else // if it's a single object
                                {
                                    var relatedObject = property.GetValue(obj);

                                    if (relatedObject != null)
                                    {
                                        values.Add(subProperty.GetValue(relatedObject)?.ToString());
                                    }
                                    else
                                    {
                                        values.Add(""); // Add empty value if related object is null
                                    }
                                }
                            }
                            else
                            {
                                values.Add(""); // Add empty value if subProperty not found
                            }
                        }
                        else
                        {
                            values.Add(""); // Add empty value if property not found
                        }
                    }
                    else
                    {
                        var value = propertyInfo.GetValue(obj);
                        values.Add(value == null ? "" : value.ToString());
                    }
                }
                catch (Exception ex)
                {
                    // Handle any error that occurred during getting the value.
                    // This block will catch any unhandled exceptions and allow the loop to continue with the next property.
                    // Add error handling code here as needed.

                    values.Add(""); // Add empty value in case of error
                }
            }

            //Join the string representations of the values with a comma and return the result.
            return string.Join(",", values);
        }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接