使用selectmany展平列表,如何获取父对象,当子对象为null时?
我需要显示清单:
"付款人:付款人A,状态:有效"
"付款人:付款人A,状态:最高"
"付款人:付款人A,状态:快速"
"付款人:付款人B,状态:" - "
// Parent class
public class Payer
{
public string Name { get; set; }
public List<Status> Status { get; set; }
}
// Child class
public class Status
{
public string Name { get; set; }
}
static void Main(params string[] args)
{
// Lets build some example-data
List<Payer> payers = new List<Payer>()
{
new Payer()
{
Name = "Payer A",
Status = new List<Status>()
{
new Status() { Name = "Active" },
new Status() { Name = "Top" },
new Status() { Name = "Fast" }
}
},
new Payer()
{
Name = "Payer B",
Status = new List<Status>()
{
// Payer B got no Status
}
}
};
var payerStatuses = payers.SelectMany
(
payer => payer.Status, // Select the Children
(payer, stat) => new { Name = payer.Name, Status = stat.Name } // Tell Linq what to take from parent (payer) and what to take from child (status)
);
// let's see what we got
foreach (var payerStatus in payerStatuses)
{
Console.WriteLine("Payer: {0}, Status: {1}", payerStatus.Name, payerStatus.Status);
}
// Result:
// "Payer: Payer A, Status: Active"
// "Payer: Payer A, Status: Top"
// "Payer: Payer A, Status: Fast"
// But I need payer B too!
}
答案 0 :(得分:1)
我在猜你想做什么。您想要一个付款人状态对象。你想看到付款人B的三个对象非A,对吗?
你不应该混合使用linq-styles。这里有一些如何使用SelectMany的例子:
// Parent class
public class Payer
{
public string Name { get; set; }
public List<Status> Status { get; set; }
}
// Child class
public class Status
{
public string Name { get; set; }
}
static void Main(params string[] args)
{
// Lets build some example-data
List<Payer> payers = new List<Payer>()
{
new Payer()
{
Name = "Payer A",
Status = new List<Status>()
{
new Status() { Name = "Active" },
new Status() { Name = "Top" },
new Status() { Name = "Fast" }
}
},
new Payer()
{
Name = "Payer B",
Status = new List<Status>()
{
// Payer B got no Status
}
}
};
var payerStatuses = payers.SelectMany
(
payer => payer.Status.DefaultIfEmpty(), // Select the Children. If no status, we want an empty list
(payer, stat) => new { Name = payer.Name, Status = stat == null ? null : stat.Name } // Tell Linq what to take from parent (payer) and what to take from child (status). check if status is not null, because we receive an empty status-list for payers without status
);
// let's see what we got
foreach (var payerStatus in payerStatuses)
{
Console.WriteLine("Payer: {0}, Status: {1}", payerStatus.Name, payerStatus.Status);
}
// Expected:
// "Payer: Payer A, Status: Active"
// "Payer: Payer A, Status: Top"
// "Payer: Payer A, Status: Fast"
// "Payer: Payer B, Status: "
}
答案 1 :(得分:0)
所以你有付款人,每个付款人都有零个或多个PayerStatuses。
我需要使用selectmany,所以我可以根据状态获取行
不知道这意味着什么。你开始提到解决方案,然后你开始说出你想要的,但解决方案不起作用?也许下次首先指定你想要的东西,然后你尝试了什么,然后告诉我们为什么它不起作用。
除此之外,你没有告诉我们你想要什么,你也忘了写你的付款人和你的PayerStatus课程。
您是否拥有“使用此状态的付款人”课程,就像您使用实体框架时一样?或者你只有两张单独的桌子?
如果您只有两个单独的表,那么您如何表明PayerStatus属于哪个Payer?每个PayerStatus是否属于一个Payer(一对多关系),或者是否有可能属于多个付款人的PayerStatusses(多对多)或者PayerStatusses根本不属于付款人吗?
让我们假设您的关系是最常见的:您在Payers和PayerStatuses之间存在一对多的关系:每个付款人都有零个或多个Payerstatuses;每个PayerStatus都属于一个付款人。
在表格中,这通常使用主键和外键来解决:
class Payer
{
public int Id {get; set;} // primary key
... // other Payer properties
}
class PayerStatus
{
public int Id {get; set;} // primary key
// every PayerStatus belongs to exactly one Payer using foreign key:
public int PayerId {get; set;}
... // other properties
}
如果您有这样的表格,那么为了获得“每个付款人使用他的PayerStatuses”,您就可以GroupJoin。
// your two tables: Payers and Statuses:
IEnumerable<Payer> payers = ...
IEnumerable<PayerStatus> statuses = ...
// GroupJoin these two tables:
var prayersWithTheirStatusses = payers.GroupJoin(statusses,
payer => payer.Id, // from each payer take the Id
status => status.PayerId, // from each status take the PayerId
(payer, statusses) => new // when they match, make a new object:
{
// take only the Payer properties you plan to use, for instance:
PayerId = payer.Id,
Name = payer.Name,
Reputation = payer.Reputation,
...
// from all payer's statuses, take only the properties you plan to use
Statusses = statusses.Select(status => new
{
Description = status.Description,
StatusValue = status.Value,
...
})
.ToList(),
}
}
这样,即使付款人根本没有任何身份,您也可以获得所有付款人的所有状态。
因此,如果您有以下表格:
Payers
Id = 10, Name = A
Id = 11, Name = B
Id = 12, Name = C
PayerStatusses
Id = 21, PayerId = 10, ...
Id = 22, PayerId = 11, ...
Id = 23, PayerId = 10, ...
上面的linq语句将为您提供类似
的内容Payer 10, name A with Status list containing data from statuses 21 and 23
Payer 11. name B with Status list with one element containing data from status 22
Payer 12, name C with empty status list
很多时候,人们不希望付款人拥有他的状态,而是每个付款人一行和他的一个状态。所以他们喜欢以下结果
10 - A - status 21
10 - A - status 23
11 - B - status 22
12 - C - (null)
我从来没有找到一个正确的用例,你更喜欢在GroupJoin之上。我认为这仍然需要,因为人们认为没有联系的SQL语句的局限性可以让“付款人拥有他们的状态”,所以他们采取了下一个最好的事情,Left Outer Join, as is answered several times on SO:
继GroupJoin之后:
.SelectMany(payer => payer.Statusses.DefaultIfEmpty(),
(payer, status) => new
{
// payer properties:
PayerId = payer.PayerId,
PayerName = payer.Name,
Reputation = payer.Reputation,
// status properties:
StatusDescription = status.Description,
StatusValue = status.Value,
});