C# 处理中等csv报告中的数据质量问题。最佳做法 需要一个更好的练习问题的帮助
我有一个azure函数,它将不同API中的数据进行匹配,以创建最终的csv报告。我有一个60k-100k的柱状图和30根柱子 为了便于解释,我将使用一个小的学校示例C# 处理中等csv报告中的数据质量问题。最佳做法 需要一个更好的练习问题的帮助,c#,design-patterns,azure-functions,C#,Design Patterns,Azure Functions,我有一个azure函数,它将不同API中的数据进行匹配,以创建最终的csv报告。我有一个60k-100k的柱状图和30根柱子 为了便于解释,我将使用一个小的学校示例 公立学生{ 字符串级别{get;set;} Name LegName{get;set;} 字符串父名称{get;set;} 字符串教师ID{get;set;} 字符串SchoolId{get;set;} } 公共名称{ 字符串名{get;set;} 字符串LastName{get;set;} } 在构建报告之前,我从两个公开学校和
公立学生{
字符串级别{get;set;}
Name LegName{get;set;}
字符串父名称{get;set;}
字符串教师ID{get;set;}
字符串SchoolId{get;set;}
}
公共名称{
字符串名{get;set;}
字符串LastName{get;set;}
}
在构建报告之前,我从两个公开学校和教师信息的API创建了两个字典。当然,还有来自学生API的Student
列表。我无法控制这个trhee API、设计、数据质量,什么都没有
现在,当我有了所有的数据后,我开始创建报告
string GenerateTXT(字典学校、字典教师、学生){
StringBuilder内容=新建StringBuilder();
foreach(学生中的var学生){
content.Append($“{student.Grade}\t”);
Append($“{student.LegName.FirstName}\t”);
Append($“{student.LegName.LastName}\t”);
content.Append($“{schools.TryGetValue(student.TeacherId)}\t”);
content.Append($“{teachers.TryGetValue(student.SchoolId)}t”;
content.Append($“{student.FatherNme}\t”);
content.AppendLine();
}
返回content.ToString();
}
现在问题来了。我开始注意到数据质量问题,所以函数开始抛出异常。例如,没有有效学校或老师的学生,或者没有名字的学生。我尝试解决预期的场景和异常处理
string GenerateTXT(字典学校、字典教师、学生){
StringBuilder内容=新建StringBuilder();
var值=string.Empty;
foreach(学生中的var学生){
试一试{
content.Append($“{student.Grade}\t”);
Append($“{student.LegName.FirstName}\t”);
Append($“{student.LegName.LastName}\t”);
if(teachers.TryGetValue(student.TeacherId))
content.Append($“{teachers[student.TeacherId]}\t”);
其他的
content.Append($“\t”);
if(schools.TryGetValue(student.SchoolId))
content.Append($“{schools[student.SchoolId]}\t”);
其他的
content.Append($“\t”);
content.Append($“{student.FatherNme}\t”);
content.AppendLine();
}
捕获(例外情况除外){
log.Error($“读取worker{student.FirstName}时出错”);
}
}
返回content.ToString();
}
问题是,当发生意外错误时,我会停止阅读下一列可能有的数据,而跳转到下一个工作人员。因此,如果某个学生由于某种随机原因没有名字,那么报告中的那一行只会有分数,而没有其他内容,但我实际上拥有其余的数据值。所以问题来了。我可以在每一列上放置一个try catch
,但请记住,我的真实场景有大约30列,可能更多……所以我认为这是一个非常糟糕的解决方案。有没有一种模式可以更好地解决这个问题
提前感谢!所以我要给你的第一点建议是使用。这是一个经过验证的库,因为它可以处理所有你永远不会想到的边缘情况。因此,请尝试一下:
public class Student
{
public string Grade { get; set; }
public Name LegName { get; set; }
public string FatherName { get; set; }
public string TeacherId { get; set; }
public string SchoolId { get; set; }
}
public class Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class NormalizedData
{
public string Grade { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string School { get; set; }
public string Teacher { get; set; }
public string FatherName { get; set; }
}
static void GenerateCSVData(CsvHelper.CsvWriter csv, Dictionary<string, string> schools,
Dictionary<string, string> teachers, Student[] students)
{
var normalizedData = students.Select(x => new NormalizedData
{
Grade = x.Grade,
FatherName = x.FatherName,
FirstName = x.LegName?.FirstName, // sanity check incase LegName is null
LastName = x.LegName?.LastName, // ...
School = schools.ContainsKey(x.SchoolId ?? string.Empty) ? schools[x.SchoolId] : null,
Teacher = teachers.ContainsKey(x.TeacherId ?? string.Empty) ? teachers[x.TeacherId] : null
});
csv.WriteRecords(normalizedData);
}
private static string GenerateStringCSVData(Dictionary<string, string> schools,
Dictionary<string, string> teachers, Student[] students)
{
using(var ms = new MemoryStream())
{
using(var sr = new StreamWriter(ms, leaveOpen: true))
using (var csv = new CsvHelper.CsvWriter(sr,
new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = ",", // change this to "\t" if you want to use tabs
Encoding = Encoding.UTF8
}))
{
GenerateCSVData(csv, schools, teachers, students);
}
ms.Position = 0;
return Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length);
}
}
private static int Main(string[] args)
{
var teachers = new Dictionary<string, string>
{
{ "j123", "Jimmy Carter" },
{ "r334", "Ronald Reagan" },
{ "g477", "George Bush" }
};
var schools = new Dictionary<string, string>
{
{ "s123", "Jimmy Carter University" },
{ "s334", "Ronald Reagan University" },
{ "s477", "George Bush University" }
};
var students = new Student[]
{
new Student
{
FatherName = "Bob Jimmy",
SchoolId = "s477",
Grade = "5",
LegName = new Name{ FirstName = "Apple", LastName = "Jimmy" },
TeacherId = "r334"
},
new Student
{
FatherName = "Jim Bobby",
SchoolId = null, // intentional
Grade = "", // intentional
LegName = null, // intentional
TeacherId = "invalid id" // intentional
},
new Student
{
FatherName = "Mike Michael",
SchoolId = "s123",
Grade = "12",
LegName = new Name{ FirstName = "Peach", LastName = "Michael" },
TeacherId = "g477"
},
};
var stringData = GenerateStringCSVData(schools, teachers, students);
return 0;
}
因此,您可以看到,其中一个学生有无效数据,但它通过放置空白数据而不是崩溃或抛出异常来恢复正常
现在我还没有看到您的原始数据,因此您可能需要对其进行更多调整,以涵盖所有边缘情况,但当使用CsvHelper作为您的作者时,调整将更容易。感谢您的时间!因此,广义上讲,您的建议是处理每一列中的每一种可能情况,直到不存在异常为止好消息CsvHelper@Aferrercrafter--是的,您希望在不停止的情况下处理所有数据。您已经知道数据可能/正在丢失,但如果是这种情况,则可以这样做。您可以不设置空白数据,而是将“”在这些点上,使用此CSV的任何人都知道这是故意的,因为数据不在原始集中。是的,空格是一条业务规则。还有列的顺序,我的问题开始了,因为最后几列中有几个是hacoded值。因此,对于我处理它时遇到的每一个错误,我都有数百行h空列,包括列这应该总是存在的,因为它们是harcoded值
Grade,FirstName,LastName,School,Teacher,FatherName
5,Apple,Jimmy,George Bush University,Ronald Reagan,Bob Jimmy
,,,,,Jim Bobby
12,Peach,Michael,Jimmy Carter University,George Bush,Mike Michael