使用来自动态数据透视表的匿名列加入列表
Joing lists with anonymous columns from dynamic pivot
我有两个列表共享一个公共字段。我想加入公共字段上的列表,但是,其中一个列表来自 SQL 动态数据透视表,因此该列表中的所有列名(链接字段除外)都具有未知的列名。我的问题是如何找到这些列名称以便创建新列表?
例子
class Student
{
int StudentID {get; set;}
string FirstName {get; set;}
string LastName {get; set;}
}
studentCollection 是 Students
的集合
这里以class ReportRanking
为例。它是一个 dynamic
class,从使用动态数据透视表的存储过程返回。所以我不知道列名提前。我使用 TestScore-1
、TestScore-2
等作为占位符来显示返回的内容。列名称将包含学生参加的测试的名称。列中的值将是他们收到的分数。
class StudentTestScores
{
int StudentID {get; set;}
int TestScore-1 {get; set;}
int TestScore-2 {get; set;}
int TestScore-3 {get; set;}
...
}
testResultCollection 是 StudentScores 的集合。
+-----------+---------+----------+----------+---------+
| StudentId | History | Algebra | Geometry | Biology |
+-----------+---------+----------+----------+---------+
| 1 | 88 | 96 | 87 | 91 |
+-----------+---------+----------+----------+---------+
| 2 | 92 | 75 | 88 | 74 |
+-----------+---------+----------+----------+---------+
因为结果来自动态数据透视表,所以我在编译时不知道 StudentTestScores 中列的名称是什么。它们代表学生参加的考试的名称。如何引用列名称以便将列表组合成新的复合列表?
var testResults = from student in studentCollection
join testResult in testResultCollection
on student.StudentId equals testResult.StudentId
select new {
student.StudentId,
student.FirstName,
student.LastName,
testResult.XXXXXXX // Not sure how to reference the test scores
...
}
这就是我需要结束的...
+-----------+-----------+----------+---------+---------+----------+---------+
| StudentId | FirstName | LastName | History | Algebra | Geometry | Biology |
+-----------+-----------+----------+---------+---------+----------+---------+
| 1 | Bob | Smith | 88 | 96 | 87 | 91 |
+-----------+-----------+----------+---------+---------+----------+---------+
| 2 | Sally | Jenkins | 92 | 75 | 88 | 74 |
+-----------+-----------+----------+---------+---------+----------+---------+
如果您在 运行 之前不知道 class 属性 的命名方式,我会使用反射来获取值。
public class Student
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class StudentTestScores
{
public int StudentID { get; set; }
public int TestScoreGen {get; set;}
}
class Program
{
static void Main(string[] args)
{
var studentCollection = new List<Student> { new Student { StudentID = 1, FirstName = "Brett", LastName = "X" }, new Student { StudentID = 2, FirstName = "John", LastName = "Y" } };
var testResultCollection = new List<StudentTestScores> { new StudentTestScores { StudentID = 1, TestScoreGen = 94 }, new StudentTestScores { StudentID = 2, TestScoreGen = 86 } };
var props = testResultCollection.First().GetType().GetProperties();
//Check my properties
props.ToList().ForEach(x => Console.WriteLine(x));
var testResults = from student in studentCollection
join testResult in testResultCollection
on student.StudentID equals testResult.StudentID
select new
{
student.StudentID,
student.FirstName,
student.LastName,
resultName = testResult.GetType().GetProperty(props[1].Name),
resultValue = testResult.GetType().GetProperty(props[1].Name).GetValue(testResult, null)
};
testResults.ToList().ForEach(x => Console.WriteLine($"{x.StudentID} {x.FirstName} {x.LastName} {x.resultName} {x.resultValue}"));
Console.ReadLine();
}
}
更新 11-22
如果 属性 不存在,您可能会遇到问题。在这种情况下,反射会爆炸,因为那里什么都没有。这相当于 SQL 中的左连接。您可能加入了有时存在、有时不存在的事物。在这种情况下,你只需要知道如何处理这样的事情。我已经更新了上面关于如何合成它的例子。基本上我看到我有 2 个或更多属性,但我没有。然后,如果我没有三元运算符,我会选择要做什么。我认为三元运算符非常适合直接赋值给 if, then, else。
public class Student
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class StudentTestScores
{
public int StudentID { get; set; }
//public int TestScoreGen {get; set;}
}
class Program
{
static void Main(string[] args)
{
var studentCollection = new List<Student> { new Student { StudentID = 1, FirstName = "Brett", LastName = "X" }, new Student { StudentID = 2, FirstName = "John", LastName = "Y" } };
//var testResultCollection = new List<StudentTestScores> { new StudentTestScores { StudentID = 1, TestScoreGen = 94 }, new StudentTestScores { StudentID = 2, TestScoreGen = 86 } };
var testResultCollection = new List<StudentTestScores> { new StudentTestScores { StudentID = 1 }, new StudentTestScores { StudentID = 2 } };
var props = testResultCollection.First().GetType().GetProperties();
//Check my properties
props.ToList().ForEach(x => Console.WriteLine(x));
var testResults = from student in studentCollection
join testResult in testResultCollection
on student.StudentID equals testResult.StudentID
select new
{
student.StudentID,
student.FirstName,
student.LastName,
resultName = props.Count() > 1 ? testResult.GetType().GetProperty(props[1]?.Name)?.ToString() : "Nothing",
result = props.Count() > 1 ? testResult.GetType().GetProperty(props[1]?.Name).GetValue(testResult, null) : "0"
};
testResults.ToList().ForEach(x => Console.WriteLine($"{x.StudentID} {x.FirstName} {x.LastName} {x.resultName} {x.result}"));
Console.ReadLine();
}
}
我会将您的对象合并为一个 ExpandoObject
,并且 return 它是动态的。这样你就可以像往常一样访问它的属性(因为它是动态的)并且任何反射代码(比如序列化到 json\csv)也将能够像往常一样探索它的属性。这是代码:
class Student
{
public int StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class StudentTestScores {
public int StudentId { get; set; }
public int History { get; set; }
public int Algebra { get; set; }
public int Geometry { get; set; }
public int Biology { get; set; }
}
static void Main(string[] args) {
var studentCollection = new List<Student>(new [] {
new Student() {StudentId = 1, FirstName = "Test", LastName = "Test"},
});
var testResultCollection = new List<StudentTestScores>(new [] {
new StudentTestScores() {StudentId = 1, Algebra = 2, Biology = 5, Geometry = 3},
});
var testResults = from student in studentCollection
join testResult in testResultCollection
on student.StudentId equals testResult.StudentId
select Combine(student, testResult);
Console.WriteLine(JsonConvert.SerializeObject(testResults));
// outputs [{"StudentId":1,"FirstName":"Test","LastName":"Test","History":0,"Algebra":2,"Geometry":3,"Biology":5}]
Console.ReadKey();
}
static dynamic Combine(params object[] objects) {
var exp = (IDictionary<string, object>) new ExpandoObject();
foreach (var o in objects) {
var dict = o as IDictionary<string, object>;
if (dict != null) {
foreach (var prop in dict) {
if (!exp.ContainsKey(prop.Key)) {
exp.Add(prop.Key, prop.Value);
}
}
}
else {
foreach (var prop in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) {
if (prop.CanRead && !exp.ContainsKey(prop.Name)) {
exp.Add(prop.Name, prop.GetValue(o));
}
}
}
}
return exp;
}
我有两个列表共享一个公共字段。我想加入公共字段上的列表,但是,其中一个列表来自 SQL 动态数据透视表,因此该列表中的所有列名(链接字段除外)都具有未知的列名。我的问题是如何找到这些列名称以便创建新列表?
例子
class Student
{
int StudentID {get; set;}
string FirstName {get; set;}
string LastName {get; set;}
}
studentCollection 是 Students
的集合这里以class ReportRanking
为例。它是一个 dynamic
class,从使用动态数据透视表的存储过程返回。所以我不知道列名提前。我使用 TestScore-1
、TestScore-2
等作为占位符来显示返回的内容。列名称将包含学生参加的测试的名称。列中的值将是他们收到的分数。
class StudentTestScores
{
int StudentID {get; set;}
int TestScore-1 {get; set;}
int TestScore-2 {get; set;}
int TestScore-3 {get; set;}
...
}
testResultCollection 是 StudentScores 的集合。
+-----------+---------+----------+----------+---------+
| StudentId | History | Algebra | Geometry | Biology |
+-----------+---------+----------+----------+---------+
| 1 | 88 | 96 | 87 | 91 |
+-----------+---------+----------+----------+---------+
| 2 | 92 | 75 | 88 | 74 |
+-----------+---------+----------+----------+---------+
因为结果来自动态数据透视表,所以我在编译时不知道 StudentTestScores 中列的名称是什么。它们代表学生参加的考试的名称。如何引用列名称以便将列表组合成新的复合列表?
var testResults = from student in studentCollection
join testResult in testResultCollection
on student.StudentId equals testResult.StudentId
select new {
student.StudentId,
student.FirstName,
student.LastName,
testResult.XXXXXXX // Not sure how to reference the test scores
...
}
这就是我需要结束的...
+-----------+-----------+----------+---------+---------+----------+---------+
| StudentId | FirstName | LastName | History | Algebra | Geometry | Biology |
+-----------+-----------+----------+---------+---------+----------+---------+
| 1 | Bob | Smith | 88 | 96 | 87 | 91 |
+-----------+-----------+----------+---------+---------+----------+---------+
| 2 | Sally | Jenkins | 92 | 75 | 88 | 74 |
+-----------+-----------+----------+---------+---------+----------+---------+
如果您在 运行 之前不知道 class 属性 的命名方式,我会使用反射来获取值。
public class Student
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class StudentTestScores
{
public int StudentID { get; set; }
public int TestScoreGen {get; set;}
}
class Program
{
static void Main(string[] args)
{
var studentCollection = new List<Student> { new Student { StudentID = 1, FirstName = "Brett", LastName = "X" }, new Student { StudentID = 2, FirstName = "John", LastName = "Y" } };
var testResultCollection = new List<StudentTestScores> { new StudentTestScores { StudentID = 1, TestScoreGen = 94 }, new StudentTestScores { StudentID = 2, TestScoreGen = 86 } };
var props = testResultCollection.First().GetType().GetProperties();
//Check my properties
props.ToList().ForEach(x => Console.WriteLine(x));
var testResults = from student in studentCollection
join testResult in testResultCollection
on student.StudentID equals testResult.StudentID
select new
{
student.StudentID,
student.FirstName,
student.LastName,
resultName = testResult.GetType().GetProperty(props[1].Name),
resultValue = testResult.GetType().GetProperty(props[1].Name).GetValue(testResult, null)
};
testResults.ToList().ForEach(x => Console.WriteLine($"{x.StudentID} {x.FirstName} {x.LastName} {x.resultName} {x.resultValue}"));
Console.ReadLine();
}
}
更新 11-22
如果 属性 不存在,您可能会遇到问题。在这种情况下,反射会爆炸,因为那里什么都没有。这相当于 SQL 中的左连接。您可能加入了有时存在、有时不存在的事物。在这种情况下,你只需要知道如何处理这样的事情。我已经更新了上面关于如何合成它的例子。基本上我看到我有 2 个或更多属性,但我没有。然后,如果我没有三元运算符,我会选择要做什么。我认为三元运算符非常适合直接赋值给 if, then, else。
public class Student
{
public int StudentID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class StudentTestScores
{
public int StudentID { get; set; }
//public int TestScoreGen {get; set;}
}
class Program
{
static void Main(string[] args)
{
var studentCollection = new List<Student> { new Student { StudentID = 1, FirstName = "Brett", LastName = "X" }, new Student { StudentID = 2, FirstName = "John", LastName = "Y" } };
//var testResultCollection = new List<StudentTestScores> { new StudentTestScores { StudentID = 1, TestScoreGen = 94 }, new StudentTestScores { StudentID = 2, TestScoreGen = 86 } };
var testResultCollection = new List<StudentTestScores> { new StudentTestScores { StudentID = 1 }, new StudentTestScores { StudentID = 2 } };
var props = testResultCollection.First().GetType().GetProperties();
//Check my properties
props.ToList().ForEach(x => Console.WriteLine(x));
var testResults = from student in studentCollection
join testResult in testResultCollection
on student.StudentID equals testResult.StudentID
select new
{
student.StudentID,
student.FirstName,
student.LastName,
resultName = props.Count() > 1 ? testResult.GetType().GetProperty(props[1]?.Name)?.ToString() : "Nothing",
result = props.Count() > 1 ? testResult.GetType().GetProperty(props[1]?.Name).GetValue(testResult, null) : "0"
};
testResults.ToList().ForEach(x => Console.WriteLine($"{x.StudentID} {x.FirstName} {x.LastName} {x.resultName} {x.result}"));
Console.ReadLine();
}
}
我会将您的对象合并为一个 ExpandoObject
,并且 return 它是动态的。这样你就可以像往常一样访问它的属性(因为它是动态的)并且任何反射代码(比如序列化到 json\csv)也将能够像往常一样探索它的属性。这是代码:
class Student
{
public int StudentId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class StudentTestScores {
public int StudentId { get; set; }
public int History { get; set; }
public int Algebra { get; set; }
public int Geometry { get; set; }
public int Biology { get; set; }
}
static void Main(string[] args) {
var studentCollection = new List<Student>(new [] {
new Student() {StudentId = 1, FirstName = "Test", LastName = "Test"},
});
var testResultCollection = new List<StudentTestScores>(new [] {
new StudentTestScores() {StudentId = 1, Algebra = 2, Biology = 5, Geometry = 3},
});
var testResults = from student in studentCollection
join testResult in testResultCollection
on student.StudentId equals testResult.StudentId
select Combine(student, testResult);
Console.WriteLine(JsonConvert.SerializeObject(testResults));
// outputs [{"StudentId":1,"FirstName":"Test","LastName":"Test","History":0,"Algebra":2,"Geometry":3,"Biology":5}]
Console.ReadKey();
}
static dynamic Combine(params object[] objects) {
var exp = (IDictionary<string, object>) new ExpandoObject();
foreach (var o in objects) {
var dict = o as IDictionary<string, object>;
if (dict != null) {
foreach (var prop in dict) {
if (!exp.ContainsKey(prop.Key)) {
exp.Add(prop.Key, prop.Value);
}
}
}
else {
foreach (var prop in o.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)) {
if (prop.CanRead && !exp.ContainsKey(prop.Name)) {
exp.Add(prop.Name, prop.GetValue(o));
}
}
}
}
return exp;
}