我在SQL Server 2005中编写了一个正确的外连接查询,它工作正常,但我无法将其转换为LINQ。
这是我的问题:
select b.number, COUNT(*) AS [AudioCount] from audios a
right join months b on DATEPART(Month, a.[RecordedDate]) = b.number
group by number
请帮我转换为LINQ。
谢谢&问候, Anil Saklania
编辑:更正了查询。
答案 0 :(得分:1)
根据您要查找的内容,我将其反转为左连接,但它是从数月到音频的左连接。这将使您在一个月没有录音时返回零计数。使用paolo的原始测试数据进行测试。
var audioMonths = from month in ListOfMonths
join audio in ListOfAudios on
month.number equals audio.RecordedDate.Month into audioLeftJoin
from audio in audioLeftJoin.DefaultIfEmpty()
select new
{
Month = month.number,
AudioId = audio != null ? audio.someProperty : null //Need some property on the audio object to see if it exists
};
var monthAudioCount = from audioMonth in audioMonths
group audioMonth by audioMonth.Month into grouping
select new
{
Month = grouping.Key,
AudioCount = grouping.Count(audioMonth => audioMonth.AudioId != null)
};
答案 1 :(得分:1)
首先,本书的一些注释:J.&amp ;;的LINQ Pocket Reference。 B. Albahari:
1.使用来自的额外转换为SelectMany
2. into 子句在 join 子句后直接出现时转换为GroupJoin。
Mike和Paolo的上述两个优秀解决方案都在查询中使用了第二个额外的 from 子句,因为它转换为SelectMany。 使用SelectMany,“序列序列”(一系列音频序列)将转换为单个 flat 集合结果集。然后,为了对音频进行计数,在第二步中,单个平面输出集合根据月份进行分组。在上面的两个解决方案中,都已完成,并且它可以正常工作,但它还需要仔细检查空值。
开发自然层次。 更简洁的替代方法是使用GroupJoin而不是SelectMany。 GroupJoin产生分层结果集,而不是SelectMany的平坦结果集。当然,分层结果集不需要分组,因此我们消除了第二步。
最重要的是,通过利用GroupJoin的分层结果集,我们不必检查空值。
因此,我们通过此代码实现另一个干净的左外连接,并借用Paolo的数据:
static void Main(string[] args)
{
var ListOfAudios = new List<Audio>() {
new Audio() { someProperty = "test", RecordedDate = new DateTime(2011, 01, 01) },
new Audio() { someProperty = "test", RecordedDate = new DateTime(2011, 01, 02) },
new Audio() { someProperty = "test", RecordedDate = new DateTime(2011, 02, 01) },
new Audio() { someProperty = "test", RecordedDate = new DateTime(2011, 02, 02) }
};
var ListOfMonths = new List<Month>() {
new Month() {number=1, someMonthProperty="testMonth"},
new Month() {number=2, someMonthProperty="testMonth"},
new Month() {number=3, someMonthProperty="testMonth"}
};
var q = from month in ListOfMonths
join audio in ListOfAudios on month.number equals audio.RecordedDate.Month
into hierarch
select new
{
MonthNum = month.number,
AudioCnt = hierarch.Count()
};
foreach (var m in q)
{
Console.WriteLine("{0} - {1}", m.MonthNum,m.AudioCnt);
}
Console.ReadLine();
}
答案 2 :(得分:0)
根据您的问题的一些评论,除了将您的查询翻译为linq之外,可能有更直接的方法来做您想做的事情。然而,就像练习一样,这是一种写作方式:
var res = from audio in ListOfAudios
join month in ListOfMonths
on audio.RecordedDate.Month equals month.number into joinAudioMonth
from j in joinAudioMonth.DefaultIfEmpty()
group j by j.number into g
select new
{
number = g.Key,
cnt = g.Count()
};
修改强> 上面的代码没有按照您的要求进行正确的加入,这是基于迈克回答的修改后的代码。这个不依赖于Audio对象的属性(即使对象本身存在,也可能为null)。但我很挑剔,迈克的回答基本上是正确的。
var audioMonths =
from month in ListOfMonths
join audio in ListOfAudios on
month.number equals audio.RecordedDate.Month into monthAudioJoin
from joined in monthAudioJoin.DefaultIfEmpty()
select new
{
Month = month.number,
J = joined
};
var res = from audioMonth in audioMonths
group audioMonth by audioMonth.Month into grouping
select new
{
number = grouping.Key,
cnt = grouping.Count(a => a.J != null)
};
以下是我测试它的方式:
public class Audio
{
public string someProperty {get; set;}
public DateTime RecordedDate {get; set; }
}
public class Month
{
public string someMonthProperty {get; set;}
public int number {get; set; }
}
public static void Main (string[] args)
{
var ListOfAudios = new List<Audio>() {
new Audio(){someProperty="test", RecordedDate=new DateTime(2011,01,01)},
new Audio(){someProperty="test", RecordedDate=new DateTime(2011,01,02)},
new Audio(){someProperty="test", RecordedDate=new DateTime(2011,02,01)},
new Audio(){someProperty="test", RecordedDate=new DateTime(2011,02,02)}
};
var ListOfMonths = new List<Month>() {
new Month() {number=1, someMonthProperty="testMonth"},
new Month() {number=2, someMonthProperty="testMonth"},
new Month() {number=3, someMonthProperty="testMonth"}
// ...
};
var audioMonths =
from month in ListOfMonths
join audio in ListOfAudios on
month.number equals audio.RecordedDate.Month into monthAudioJoin
from joined in monthAudioJoin.DefaultIfEmpty()
select new
{
Month = month.number,
J = joined
};
var res = from audioMonth in audioMonths
group audioMonth by audioMonth.Month into grouping
select new
{
number = grouping.Key,
cnt = grouping.Count(a => a.J != null)
};
foreach(var r in res)
{
Console.WriteLine("{0} - {1}", r.number, r.cnt);
}