2

我所有的 EF 类都有一个Projection()方法,可以帮助我选择要从类中投影到 SQL 查询的内容:

例子:

    public static Expression<Func<Something, dynamic>> Projection()
    {
        return e => new
        {
            something = e.SomethingId,
            name = e.Name,
            requiredThingId = e.RequiredThingId,
            requiredThing = new
            {
                requiredThingId = e.RequiredThing.RequiredThingId,
                name = e.RequiredThing.Name,
                ...
            },
            optionalThingId = e.OptionalThingId,
            optionalThing = e.OptionalThingId == null ? null : new 
            {
                optionalThingId = e.OptionalThing.OptionalThingId,
                name = e.OptionalThing.Name
            }
            ...
        };
    }

我像这样使用这些投影方法:

  List<dynamic> projected = dbContext.Something.Select(Something.Projection()).ToList();

这种方式让我可以在我的项目中重复使用我的预测。

我想使用ServiceStack.Text将这些列表序列化为 CSV。

我正在这样做:

 string csvString = CsvSerializer.SerializeToCsv<dynamic>(Something.Select(Something.Projection()).ToList());

 byte[] csvBytes = System.Text.Encoding.Unicode.GetBytes(csvString);

 return File(csvBytes, "text/csv", "foo.csv");

但结果是一个空的 csv(csvString 充满了“\r\n”,仅此而已)

问题:

  • 我是否正确使用了该SerializeToCsv()方法?
  • 我可以<dynamic>在这个库中使用吗?
  • 实现我的目的的建议?

对于上面的示例,所需的 CSV 将展平所有属性,例如:

  "somethingId";"name";"requiredThingId";"requiredThing.requiredThingId";"requiredThing.name";"optionalThingId";"optionalThing.optionalThingId";"optionalThing.name"
4

3 回答 3

4

我会回答我自己的问题,但不会标记为已接受,以期获得新的更大答案。

我是否正确使用了 SerializeToCsv() 方法?我可以在这个库中使用动态吗?

答案:两者都可以,但需要 ServiceStack.Text v4.0.36(可在 MyGet 获得,而不是 Nuget)

实现我的目的的建议?

答:ServiceStack.Text可以序列化为 CSV a List<dynamic>,但所有嵌套属性都将呈现为 JSON 并且它们不会被展平,例如:

   List<dynamic> list = new List<dynamic>();
   list.Add(new
   {
         name = "john", 
         pet = new 
         { 
              name = "doggy"
         }
   });

   string csv = CsvSerializer.SerializeToCsv(list);

此列表将被序列化为此 csv:

名字,宠物
“约翰”,{名字=“小狗”}

而不是这个 csv,正如我所期待的:

名字,宠物名字
“约翰”,“小狗”

所以......我终于写了这段代码:

public class CsvHelper
{
    public static string GetCSVString(List<dynamic> inputList)
    {
        var outputList = new List<Dictionary<string, object>>();

        foreach (var item in inputList)
        {
            Dictionary<string, object> outputItem = new Dictionary<string, object>();
            flatten(item, outputItem, "");

            outputList.Add(outputItem);
        }

        List<string> headers = outputList.SelectMany(t => t.Keys).Distinct().ToList();

        string csvString = ";" + string.Join(";", headers.ToArray()) + "\r\n";

        foreach (var item in outputList)
        {
            foreach (string header in headers)
            {
                if (item.ContainsKey(header) && item[header] != null)
                    csvString = csvString + ";" + item[header].ToString();
                else
                    csvString = csvString + ";";
            }

            csvString = csvString + "\r\n";
        }

        return csvString;
    }

    private static void flatten(dynamic item, Dictionary<string, object> outputItem, string prefix)
    {
        if (item == null)
            return;

        foreach (PropertyInfo propertyInfo in item.GetType().GetProperties())
        {
            if (!propertyInfo.PropertyType.Name.Contains("AnonymousType"))
                outputItem.Add(prefix + "__" + propertyInfo.Name, propertyInfo.GetValue(item));
            else
                flatten(propertyInfo.GetValue(item), outputItem, (prefix.Equals("") ? propertyInfo.Name : prefix + "__" + propertyInfo.Name));
        }
    }
}

这是做什么的:

  1. 它将列表展平,使列表中对象的所有属性都是基元(例如:没有嵌套属性)

  2. 它从该扁平列表中创建一个 CSV。

该算法为 O(n*m),
即 n:列表中的项目
数 m:每个项目内的属性数(包括嵌套属性)

于 2015-01-04T20:29:38.470 回答
2

虽然建议使用干净的 POCO 进行序列化,但您可以序列化内联匿名类型,例如:

var somethings =  dbContext.Something.Select(e => new { 
    something = e.SomethingId, 
    name = e.Name 
});
somethings.ToCsv().Print();

否则,我刚刚添加了对序列化的支持,IEnumerable<object>并且IEnumerable<dynamic> 在这个 commit中。

此更改可从v4.0.36+ 开始,现在可在 MyGet 上使用

于 2015-01-02T01:23:22.187 回答
0

我相信正在发生的部分原因是库正在使用对象中的属性来确定要序列化的内容。我相信动态对象不会像 POCO 那样构造属性。如果你不在你的对象上设置一个gettersetter,它肯定不会工作。仅供参考,我使用的是这个库的 4.5.6.0 版本。

于 2017-02-04T02:24:53.513 回答