如何将表格数据重新组织为复杂的C#对象?

huangapple go评论75阅读模式
英文:

How can I reorganize data from a table as a complex C# object?

问题

基于这个表格,我想创建一个类似以下 JSON 结构的 C# 对象:

{
   "posts":[
      {
         "1":[
            {
               "en":{
                  "title":"Post 1 title",
                  "body":"This is the content for the post 1"
               }
            },
            {
               "fr":{
                  "title":"Titre de l'article 1",
                  "body":"Voici le contenu de l'article 1"
               }
            }
         ]
      },
      {
         "2":[
            {
               "en":{
                  "title":"Post 2 title",
                  "body":"This is the content for the post 2"
               }
            }
         ]
      },
      {
         "3":[
            {
               "en":{
                  "title":"Post 3 title",
                  "body":"This is the content for the post 3"
               }
            },
            {
               "fr":{
                  "title":"Titre de l'article 3",
                  "body":"Voici le contenu de l'article 3"
               }
            },
            {
               "de":{
                  "title":"Titel von Artikel 3",
                  "body":"Lesen Sie den Inhalt von Artikel 3"
               }
            }
         ]
      }
   ]
}

如何在 C# 中实现这个目标?

在从 SQL 数据库选择数据后,我会循环遍历每一行,尝试将其添加到一个Dictionary<string, Dictionary<string, Dictionary<string, string>>>的嵌套字典中,检查键是否存在于字典中。如果存在,我只需分配值。如果不存在,我会添加键,然后分配值,如下所示:

Dictionary<string, Dictionary<string, Dictionary<string, string>>> postsDictionary = new();

foreach (var post in postsList)
{
    if (postsDictionary.ContainsKey(post.postId))
    {
        if (postsDictionary[post.postId].ContainsKey(post.language))
        {
            if (postsDictionary[post.postId][post.language].ContainsKey(post.name))
            {
                postsDictionary[post.postId][post.language][post.name] = post.value;
            }
            else
            {
                postsDictionary[post.postId][post.language].Add(post.name, post.value);
            }
        }
        else
        {
            postsDictionary[post.postId].Add(post.language, new Dictionary<string, string>());
            postsDictionary[post.postId][post.language].Add(post.name, post.value);
        }
    }
    else
    {
        postsDictionary.Add(post.postId, new Dictionary<string, Dictionary<string, string>>());
        postsDictionary[post.postId].Add(post.language, new Dictionary<string, string>());
        postsDictionary[post.postId][post.language].Add(post.name, post.value);
    }
}

postsDictionary 组织得相当好,但是**是否有更好的方法来实现这一目标?**创建嵌套的字典似乎有点混乱。

英文:

I have a table containing several references to the same posts, themselves containing several references to the same languages like so :

postId language name value
1 en title Post 1 title
1 en body This is the content for the post 1
1 fr title Titre de l'article 1
1 fr body Voici le contenu de l'article 1
2 en title Post 2 title
2 en body This is the content for the post 2
3 en title Post 3 title
3 en body This is the content for the post 3
3 fr title Titre de l'article 3
3 fr body Voici le contenu de l'article 3
3 de title Titel von Artikel 3
3 de body Lesen Sie den Inhalt von Artikel 3

Base on this table, I would like to create a C# object which ressemble to this :

{
   &quot;posts&quot;:[
      {
         &quot;1&quot;:[
            {
               &quot;en&quot;:{
                  &quot;title&quot;:&quot;Post 1 title&quot;,
                  &quot;body&quot;:&quot;This is the content for the post 1&quot;
               }
            },
            {
               &quot;fr&quot;:{
                  &quot;title&quot;:&quot;Titre de l&#39;article 1&quot;,
                  &quot;body&quot;:&quot;Voici le contenu de l&#39;article 1&quot;
               }
            }
         ]
      },
      {
         &quot;2&quot;:[
            {
               &quot;en&quot;:{
                  &quot;title&quot;:&quot;Post 2 title&quot;,
                  &quot;body&quot;:&quot;This is the content for the post 2&quot;
               }
            }
         ]
      },
      {
         &quot;3&quot;:[
            {
               &quot;en&quot;:{
                  &quot;title&quot;:&quot;Post 3 title&quot;,
                  &quot;body&quot;:&quot;This is the content for the post 3&quot;
               }
            },
            {
               &quot;fr&quot;:{
                  &quot;title&quot;:&quot;Titre de l&#39;article 3&quot;,
                  &quot;body&quot;:&quot;Voici le contenu de l&#39;article 3&quot;
               }
            },
            {
               &quot;de&quot;:{
                  &quot;title&quot;:&quot;Titel von Artikel 3&quot;,
                  &quot;body&quot;:&quot;Lesen Sie den Inhalt von Artikel 3&quot;
               }
            }
         ]
      }
   ]
}

How can I achieve that in C# ?

After selecting my datas from my SQL database, I loop through every line, trying to add it to a dictionnary of dictionnary of dictionnary of string Dictionary&lt;string, Dictionary&lt;string, Dictionary&lt;string, string&gt;&gt;&gt;, testing if the key exists in the dictionnary. If it exists, I just assign the value. If not, I add the key and then assign the value, like so :

Dictionary&lt;string, Dictionary&lt;string, Dictionary&lt;string, string&gt;&gt;&gt; postsDictionnary= new();
foreach(var post in postsList)
{
if (postsDictionnary.ContainsKey(post.postId))
{
if (postsDictionnary[post.postId].ContainsKey(post.language))
{
if (postsDictionnary[post.itemId][post.language].ContainsKey(post.name))
{
postsDictionnary[post.itemId][post.language][post.name] = post.value;
}
else
{
postsDictionnary[post.postId][post.language].Add(post.name, post.value);
}
}
else
{
postsDictionnary[post.postId].Add(post.language, new Dictionary&lt;string, string&gt;());
postsDictionnary[post.postId][post.language].Add(post.name, post.value);
}
}
else
{
postsDictionnary.Add(post.postId, new Dictionary&lt;string, Dictionary&lt;string, string&gt;&gt;());
postsDictionnary[post.postId].Add(post.language, new Dictionary&lt;string, string&gt;());
postsDictionnary[post.postId][post.language].Add(post.name, post.value);
}
}

postsDictionnary is quite well organized, but is there a better way to achieve this ? It seems pretty dirty to create a dictionnary of dictionnary of dictionnary of string...

答案1

得分: 1

假设你有以下类和对象列表:

public class Post
{
    public int PostId { get; set; }
    public string Language { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

然后你可以编写以下的LINQ查询:

var posts = new List&lt;Post&gt;
{
    new Post { PostId = 1, Language = &quot;en&quot;, Name = &quot;title&quot;, Value = &quot;Post 1 title&quot; },
    new Post { PostId = 1, Language = &quot;en&quot;, Name = &quot;body&quot;, Value = &quot;This is the content for the post 1&quot; },
    new Post { PostId = 1, Language = &quot;fr&quot;, Name = &quot;title&quot;, Value = &quot;Titre de l&#39;article 1&quot; },
    new Post { PostId = 1, Language = &quot;fr&quot;, Name = &quot;body&quot;, Value = &quot;Voici le contenu de l&#39;article 1&quot; },
    new Post { PostId = 2, Language = &quot;en&quot;, Name = &quot;title&quot;, Value = &quot;Post 2 title&quot; },
    new Post { PostId = 2, Language = &quot;en&quot;, Name = &quot;body&quot;, Value = &quot;This is the content for the post 2&quot; },
    new Post { PostId = 3, Language = &quot;en&quot;, Name = &quot;title&quot;, Value = &quot;Post 3 title&quot; },
    new Post { PostId = 3, Language = &quot;en&quot;, Name = &quot;body&quot;, Value = &quot;This is the content for the post 3&quot; },
    new Post { PostId = 3, Language = &quot;fr&quot;, Name = &quot;title&quot;, Value = &quot;Titre de l&#39;article 3&quot; },
    new Post { PostId = 3, Language = &quot;fr&quot;, Name = &quot;body&quot;, Value = &quot;Voici le contenu de l&#39;article 3&quot; },
    new Post { PostId = 3, Language = &quot;de&quot;, Name = &quot;title&quot;, Value = &quot;Titel von Artikel 3&quot; },
    new Post { PostId = 3, Language = &quot;de&quot;, Name = &quot;body&quot;, Value = &quot;Lesen Sie den Inhalt von Artikel 3&quot; }
};

var result = posts
    .GroupBy(x =&gt; 1)
    .ToDictionary(x =&gt; &quot;posts&quot;,
        p =&gt; p.GroupBy(bp =&gt; bp.PostId)
            .ToDictionary(bp =&gt; bp.Key,
                bp =&gt; bp.GroupBy(lp =&gt; lp.Language)
                    .ToDictionary(lp =&gt; lp.Key, lp =&gt; lp.ToDictionary(n =&gt; n.Name, n =&gt; n.Value))
            )
    );

请注意,这段代码是一个LINQ查询,用于将列表中的Post对象进行分组和嵌套字典化的操作。如果你需要更多关于这段代码的信息或有任何其他问题,请随时提问。

英文:

Assuming that you have the following class and list of these objects

public class Post
{
    public int PostId { get; set; }
    public string Language { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

Then you can write the following LINQ Query:

var posts = new List&lt;Post&gt;
{
    new Post { PostId = 1, Language = &quot;en&quot;, Name = &quot;title&quot;, Value = &quot;Post 1 title&quot; },
    new Post { PostId = 1, Language = &quot;en&quot;, Name = &quot;body&quot;, Value = &quot;This is the content for the post 1&quot; },
    new Post { PostId = 1, Language = &quot;fr&quot;, Name = &quot;title&quot;, Value = &quot;Titre de l&#39;article 1&quot; },
    new Post { PostId = 1, Language = &quot;fr&quot;, Name = &quot;body&quot;, Value = &quot;Voici le contenu de l&#39;article 1&quot; },
    new Post { PostId = 2, Language = &quot;en&quot;, Name = &quot;title&quot;, Value = &quot;Post 2 title&quot; },
    new Post { PostId = 2, Language = &quot;en&quot;, Name = &quot;body&quot;, Value = &quot;This is the content for the post 2&quot; },
    new Post { PostId = 3, Language = &quot;en&quot;, Name = &quot;title&quot;, Value = &quot;Post 3 title&quot; },
    new Post { PostId = 3, Language = &quot;en&quot;, Name = &quot;body&quot;, Value = &quot;This is the content for the post 3&quot; },
    new Post { PostId = 3, Language = &quot;fr&quot;, Name = &quot;title&quot;, Value = &quot;Titre de l&#39;article 3&quot; },
    new Post { PostId = 3, Language = &quot;fr&quot;, Name = &quot;body&quot;, Value = &quot;Voici le contenu de l&#39;article 3&quot; },
    new Post { PostId = 3, Language = &quot;de&quot;, Name = &quot;title&quot;, Value = &quot;Titel von Artikel 3&quot; },
    new Post { PostId = 3, Language = &quot;de&quot;, Name = &quot;body&quot;, Value = &quot;Lesen Sie den Inhalt von Artikel 3&quot; }
};

var result = posts
    .GroupBy(x =&gt; 1)
    .ToDictionary(x =&gt; &quot;posts&quot;,
        p =&gt; p.GroupBy(bp =&gt; bp.PostId)
            .ToDictionary(bp =&gt; bp.Key,
                bp =&gt; bp.GroupBy(lp =&gt; lp.Language)
                    .ToDictionary(lp =&gt; lp.Key, lp =&gt; lp.ToDictionary(n =&gt; n.Name, n =&gt; n.Value))
            )
    );

答案2

得分: 0

我认为你需要将这个 DataTable 转换成 JSON。为此,你可以在 .NET 中使用 Newtonsoft Json 库,将数据序列化为有效的 JSON。

类似这样:

string result;
result = JsonConvert.SerializeObject(dt); // 其中 dt 是 DataTable 的内容

更多信息请查阅 Newtonsoft Json 文档

英文:

I think you need to convert this DataTable into JSON. For that you use can Newtonsoft Json Library in .NET and serialize the data to a valid JSON.

Something like this:

string result;
result = JsonConvert.SerializeObject(dt); //where dt is content of DataTable

For more info Newtonsoft Json

答案3

得分: 0

以下是翻译好的部分:

为什么不创建一个代表该对象的类?

这里是一个可以用于您的示例的类:

internal class Post
{
    public int PostId { get; set; }
    public string Language { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }
}

要将SQL查询结果转换为该类的实例,您可以使用ORM。对于这个示例,您可以考虑使用像Dapper这样的微型ORM,可以查看这个链接:https://www.learndapper.com/dapper-query/selecting-multiple-rows

使用以下代码连接到数据库并执行查询:

using (var connection = new SqlConnection(connectionString))
{
    var sql = "SELECT * FROM yourTable"; // 小心:性能!您可能需要添加过滤器
    var posts = await connection.QueryAsync<Post>(sql);
    
    foreach (var post in posts)
    {
        Console.WriteLine($"{post.PostId} {post.Language} {post.Name} {post.Value}");
    }
}

以下是使用LINQ执行的一些示例查询:

var engPosts = posts.Where(x => x.Language == "ENG").ToList();
var allTittles = posts.Where(x => x.Name == "Title").ToList();

请记住,根据您的用例,您可能希望在这个基础上创建其他数据结构,以提高性能、可用性、搜索等方面的效果。

英文:

Why not create a class that represent that object?

Here is a class that can be use for your example:

internal class Post
{
public int PostId { get; set; }
public string Language { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}

To convert the result of your SQL query into instance of this class, you can use an ORM. For this example you might want to use a micro ORM like dapper who will see this link https://www.learndapper.com/dapper-query/selecting-multiple-rows

using (var connection = new SqlConnection(connectionString))
{
var sql = &quot;SELECT * FROM yourTable&quot;; // Careful: perf! You might want filters
var posts = await connection.QueryAsync&lt;Post&gt;(sql);
foreach(var post in posts)
{
Console.WriteLine($&quot;{post.PostId} {post.Language} {post.Name} {post.Value}&quot;);
}
}

Some example query you can do using LINQ:

var engPosts = posts.Where(x=&gt;x.Language == &quot;ENG&quot;).ToList();
var allTittles = posts.Where(x=&gt;x.Name==&quot;Title&quot;).ToList();

Bear in mind that depending of your use case you might want to have other data structure on top of this one to improve performance, usability, search, etc.

答案4

得分: 0

public class Content
{
    public string Title { get; set; }
    public string Body { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public Dictionary<string, Content> LocalizedContent { get; } = new();
}

List<Post> posts = new();

var post = new Post { Id = 1 };
post.LocalizedContent["en"] = new Content { 
    Title = "Post 1 title", 
    Body = "This is the content for the post 1"
};
post.LocalizedContent["fr"] = new Content {
    Title = "Titre de l'article 1",
    Body = "Voici le contenu de l'article 1"
};
posts.Add(post);

// In a DB you would have 2 tables:

TABLE Post
    Id int PRIMARY KEY

TABLE Content
    PostId int PRIMARY KEY, FOREIGN KEY
    Language char(2) PRIMARY KEY
    Title varchar(80)
    Body varchar(max)

语言也可以作为外键链接到包含受支持语言以及完整语言名称的语言表中。

英文:

You could create an object model consisting of posts containing different language contents.

public class Content
{
    public string Title { get; set; }
    public string Body { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public Dictionary&lt;string, Content&gt; LocalizedContent { get; } = new();
}

Example:

List&lt;Post&gt; posts = new();

var post = new Post { Id = 1 };
post.LocalizedContent[&quot;en&quot;] = new Content { 
    Title = &quot;Post 1 title&quot;, 
    Body = &quot;This is the content for the post 1&quot;
};
post.LocalizedContent[&quot;fr&quot;] = new Content {
    Title = &quot;Titre de l&#39;article 1&quot;,
    Body = &quot;Voici le contenu de l&#39;article 1&quot;
};
posts.Add(post);

A post contains a dictionary of contents where the language is used as key. This allows you to add different localized contents to a post.

In a DB you would have 2 tables:

TABLE Post
Id int PRIMARY KEY
TABLE Content
PostId int PRIMARY KEY, FOREIGN KEY
Language char(2) PRIMARY KEY
Title varchar(80)
Body varchar(max)

The language could could also be a foreign key into a language table containing supported languages along with the full language name.

答案5

得分: 0

以下是翻译好的部分:

var result = new Dictionary<int, Dictionary<string, PostItem>>();

var postsG = posts.GroupBy(p => new { p.PostId });
foreach (var item in postsG)
{
    var posGG = item.GroupBy(i => i.Language);
    var dict = new Dictionary<string, Item>();
    foreach (var p in posGG)
    {
        var i = new PostItem();
        foreach (var pp in p)
            if (pp.Name == "title") i.title = (string)pp.Value;
            else i.body = (string)pp.Value;
        dict.Add(p.Key, i);
    }
    result.Add(item.Key.PostId, dict);
}

public class PostItem
{
    public string title { get; set; }
    public string body { get; set; }
}

输出部分:

JsonConvert.SerializeObject(result, Newtonsoft.Json.Formatting.Indented);

{
  "1": {
    "en": {
      "title": "Post 1 title",
      "body": "This is the content for the post 1"
    },
    "fr": {
      "title": "Titre de l'article 1",
      "body": "Voici le contenu de l'article 1"
    }
  },
  "2": {
    "en": {
      "title": "Post 2 title",
      "body": "This is the content for the post 2"
    }
  },
  "3": {
    "en": {
      "title": "Post 3 title",
      "body": "This is the content for the post 3"
    },
    "fr": {
      "title": "Titre de l'article 3",
      "body": "Voici le contenu de l'article 3"
    },
    "de": {
      "title": "Titel von Artikel 3",
      "body": "Lesen Sie den Inhalt von Artikel 3"
    }
  }
}
英文:

For the people who prefer c# stricted code

    var result = new Dictionary&lt;int, Dictionary&lt;string, PostItem&gt;&gt;();
var postsG = posts.GroupBy(p =&gt; new { p.PostId });
foreach (var item in postsG)
{
var posGG = item.GroupBy(i =&gt; i.Language);
var dict = new Dictionary&lt;string, Item&gt;();
foreach (var p in posGG)
{
var i = new PostItem();
foreach (var pp in p)
if (pp.Name == &quot;title&quot;) i.title = (string)pp.Value;
else i.body = (string)pp.Value;
dict.Add(p.Key, i);
}
result.Add(item.Key.PostId, dict);
}
public class PostItem
{
public string title { get; set; }
public string body { get; set; }
}

output

JsonConvert.SerializeObject(result, Newtonsoft.Json.Formatting.Indented);
{
&quot;1&quot;: {
&quot;en&quot;: {
&quot;title&quot;: &quot;Post 1 title&quot;,
&quot;body&quot;: &quot;This is the content for the post 1&quot;
},
&quot;fr&quot;: {
&quot;title&quot;: &quot;Titre de l&#39;article 1&quot;,
&quot;body&quot;: &quot;Voici le contenu de l&#39;article 1&quot;
}
},
&quot;2&quot;: {
&quot;en&quot;: {
&quot;title&quot;: &quot;Post 2 title&quot;,
&quot;body&quot;: &quot;This is the content for the post 2&quot;
}
},
&quot;3&quot;: {
&quot;en&quot;: {
&quot;title&quot;: &quot;Post 3 title&quot;,
&quot;body&quot;: &quot;This is the content for the post 3&quot;
},
&quot;fr&quot;: {
&quot;title&quot;: &quot;Titre de l&#39;article 3&quot;,
&quot;body&quot;: &quot;Voici le contenu de l&#39;article 3&quot;
},
&quot;de&quot;: {
&quot;title&quot;: &quot;Titel von Artikel 3&quot;,
&quot;body&quot;: &quot;Lesen Sie den Inhalt von Artikel 3&quot;
}
}
}

huangapple
  • 本文由 发表于 2023年7月31日 19:52:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76803346.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定