假设我有三张桌子。基本上,一个表,一个表描述事物的可能属性,一个桥表提供特定事物的那些属性的值。这使您可以执行动态元数据。
用户可以随时添加元数据属性,然后他们可以为“事物”表中的任何事物提供这些属性的值。
所以这样:
Table: Persons
PersonID | FirstName | LastName
1 | Bob | Jones
2 | Fred | Smith
3 | Sally | Doe
Table: Properties
PropertyID | Name
1 | SupervisorName
2 | Age
3 | Birthday
4 | EmployeeNumber
5 | Hometown
Table: PropertyValues
PersonID | PropertyID | PropertyValue
1 | 1 | Frank Grimes
1 | 2 | 47
2 | 2 | 35
2 | 4 | 1983738
2 | 3 | 5/5/1978
3 | 3 | 4/4/1937
3 | 5 | Chicago, IL
因此,用户希望能够查看这些属性的报告。也许我想看一张包含所有员工年龄和生日的表格。如果没有为这些用户填充这些值,表中将会出现空白。那么也许我想看一个包含主管,年龄和生日的报告 - 我也应该能够即时生成该表。
现在,为了使用SQL执行此操作,我将动态构造一个查询,并为每个要转移到顶部的属性添加一个连接到该查询。这就是它现在的运作方式。
如果我想在LINQ中执行此操作,并且在编写代码时我知道要转动哪些属性,我也可以这样做 - 我只使用GroupJoin()。
我不知道的是如何动态构建一个LINQ查询,它允许我在运行时转动任意数量的属性,而不知道它们是提前的。
有什么想法吗?
(在你将膝盖反复标记为副本之前,知道我在发布此问题之前做了大量的StackOverflow研究,如果之前已经问过这个问题,我找不到它。)
答案 0 :(得分:2)
您可以动态构建linq表达式树。以下MSDN文章中介绍了此主题(包括示例):http://msdn.microsoft.com/en-us/library/bb882637.aspx
我的建议是为您的任务编写一个示例Linq查询,并使用表达式树以编程方式重建它。一旦它工作,你就可以调整它并注入动态部件。
答案 1 :(得分:0)
我的想法是你可以加入以下条件:
人员类
public class Person
{
public int Id {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
}
物业类
public class Property
{
public int Id {get; set;}
public string Name {get; set;}
}
价值等级
public class Value
{
public int PersonId {get; set;}
public int PropertyId {get; set;}
public string Val {get; set;}
}
<强>代码强>
void Main()
{
var selectBy = "Birthday";
var persons = new List<Person>() { new Person {Id = 1, FirstName = "Bob", LastName = "Jones"}, new Person {Id = 2, FirstName = "Fred", LastName = "Smith"}, new Person {Id = 3,FirstName = "Sally", LastName = "Doe"}};
var properties = new List<Property>() { new Property {Id = 1, Name = "SupervisorName"}, new Property {Id = 2, Name = "Age"}, new Property {Id = 3, Name = "Birthday"}, new Property {Id = 4, Name = "EmployeeNumber"}, new Property {Id = 5, Name = "Hometown"}};
var values = new List<Value>() { new Value {PersonId = 1, PropertyId = 1, Val="Frank Grimes"}, new Value {PersonId = 1, PropertyId = 2, Val="47"}, new Value {PersonId = 2, PropertyId = 2, Val="35"}, new Value {PersonId = 2, PropertyId = 4, Val="1983738"}, new Value {PersonId = 2, PropertyId = 3, Val="5/5/1978"}, new Value {PersonId = 3, PropertyId = 3, Val="4/4/1937"}, new Value {PersonId = 3, PropertyId = 5, Val="Chicago, IL"}};
var result = from v in values
join p in persons on v.PersonId equals p.Id
join p2 in properties on v.PropertyId equals p2.Id
where p2.Name.Equals(selectBy)
select new { Name = p.FirstName + " " + p.LastName,
Value = v.Val
};
result.Dump();
}
<强>结果
名称,价值
Fred Smith 5/5/1978
Sally Doe 4/4/1937
修订答案
void Main()
{
var selectBy = "Birthday";
var persons = new List<Person>() { new Person {Id = 1, FirstName = "Bob", LastName = "Jones"}, new Person {Id = 2, FirstName = "Fred", LastName = "Smith"}, new Person {Id = 3,FirstName = "Sally", LastName = "Doe"}};
var properties = new List<Property>() { new Property {Id = 1, Name = "SupervisorName"}, new Property {Id = 2, Name = "Age"}, new Property {Id = 3, Name = "Birthday"}, new Property {Id = 4, Name = "EmployeeNumber"}, new Property {Id = 5, Name = "Hometown"}};
var values = new List<Value>() { new Value {PersonId = 1, PropertyId = 1, Val="Frank Grimes"}, new Value {PersonId = 1, PropertyId = 2, Val="47"}, new Value {PersonId = 2, PropertyId = 2, Val="35"}, new Value {PersonId = 2, PropertyId = 4, Val="1983738"}, new Value {PersonId = 2, PropertyId = 3, Val="5/5/1978"}, new Value {PersonId = 3, PropertyId = 3, Val="4/4/1937"}, new Value {PersonId = 3, PropertyId = 5, Val="Chicago, IL"}};
// Default Values for the Cartesian Product
var defaultValues = new string[]{"","","","",""};
// propertyKeys are used to filter values generated for pivot table
var propertyKeys = new List<Property> { new Property{Id=1}, new Property{Id=2}, new Property{Id=3}};
// Generate default values for every person and each property
var cartesianProduct = from ppl in persons
from prop in properties
join pk in propertyKeys on prop.Id equals pk.Id
select new {PersonId = ppl.Id, PropertyId = prop.Id, Val = defaultValues[prop.Id-1]};
// Create Pivot Values based on selected PropertyIds
var newValues = from cp in cartesianProduct
join v in values on new {cp.PersonId, cp.PropertyId} equals new { v.PersonId, v.PropertyId } into gj
from x in gj.DefaultIfEmpty()
select new {
PersonId = (x == null ? cp.PersonId : x.PersonId),
PropertyId = (x == null ? cp.PropertyId: x.PropertyId),
Val = ( x == null ? cp.Val : x.Val )
};
foreach( var y in newValues )
{
var aPerson = persons.Where( r=> r.Id == y.PersonId ).First().FirstName;
var aProperty = properties.Where( r=> r.Id == y.PropertyId ).First().Name;
Console.WriteLine(string.Format("{0:12} {1:12} {2:12}", aPerson, aProperty, y.Val));
}
}
<强>结果:强>
Bob SupervisorName Frank Grimes
Bob Age 47
鲍勃生日
Fred SupervisorName
Fred Age 35
弗雷德生日5/5/1978
莎莉主管姓名
莎莉年龄
莎莉生日4/4/1937