没有重复数据的 LINQ 查询分组
LINQ query grouping without duplication of data
所以我想显示按两个字段分组的输出:SubsidiaryCode
和 AssetCreatedDate
。我的问题是它冗余地显示分组值。
由于我的详细信息 class.
,我怀疑它重复了
我想要的是:
但是显示是这样的:
LINQ 查询:
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public IList<AssetListTemplate> List = new List<AssetListTemplate>();
public IList<AssetListTemplate> GetList()
{
using (var ctx = LinqExtensions.GetDataContext<NXpert.FixedAsset.DataAccess.FixedAssetDataContext>("AccountingDB"))
{
var list = (from x in ctx.DataContext.AssetRegistryEntities
where x.SubsidiaryCode2 != "" && x.SubsidiaryCode2.ToUpper().Contains("y-") && x.AssetCreatedDate>=FromDate && x.AssetCreatedDate <= ToDate
group new { x.SubsidiaryCode2, x.AssetCreatedDate,x.AssetCategoryID } by x into groupedList
select new AssetListTemplate
{
IsSelected = false,
SubsidiaryCode = groupedList.Key.SubsidiaryCode2,
AssetCreatedDate = groupedList.Key.AssetCreatedDate,
AssetCategory = groupedList.Key.AssetCategoryID
}
).OrderBy(x => x.SubsidiaryCode).ThenBy(y => y.AssetCreatedDate).ToList();
List = list;
foreach (var item in List)
{
var details = (from x in ctx.DataContext.AssetRegistryEntities
join y in ctx.DataContext.AssetCategoryEntities on x.AssetCategoryID equals y.AssetCategoryID
join z in ctx.DataContext.FixedAssetOtherInfoEntities on x.AssetCode equals z.AssetCode
where x.SubsidiaryCode2 == item.SubsidiaryCode
select new Details
{
AssetCode = x.AssetCode,
AssetCodeDesc = y.AssetCategoryDesc,
AssetDesc = x.AssetCodeDesc,
DepInCharge = z.DepartmentInCharge,
SerialNo = x.SerialNumber,
ModelNo = x.ModelNumber
}).ToList();
item.Details = details;
}
return List;
}
}
}
public class AssetListTemplate
{
public bool IsSelected { get; set; }
public string SubsidiaryCode { get; set; }
public DateTime? AssetCreatedDate { get; set; }
public string AssetCategory { get; set; }
public List<Details> Details { get; set; }
}
public class Details {
public string AssetCode { get; set; }
public string AssetCodeDesc { get; set; }
public string AssetDesc { get; set; }
public string DepInCharge { get; set; }
public string SerialNo { get; set; }
public string ModelNo { get; set; }
}
SQL Query:
SELECT Are_SubsidiaryCode2[SubsidiaryCode],Are_AssetCreatedDate[AssetCreatedDate],Are_AssetCategoryID[AssetCategory]
FROM E_AssetRegistry
WHERE Are_SubsidiaryCode2<>''
AND Are_SubsidiaryCode2 LIKE '%Y-%'
GROUP BY Are_SubsidiaryCode2
,Are_AssetCreatedDate
,Are_AssetCategoryID
ORDER BY AssetCreatedDate ASC
您似乎没有对任何聚合函数使用分组,因此您可以通过使用 distinct 使生活更简单:
from x in ctx.DataContext.AssetRegistryEntities
where x.SubsidiaryCode2.Contains("y-") && x.AssetCreatedDate>=FromDate && x.AssetCreatedDate <= ToDate
select new AssetListTemplate
{
IsSelected = false,
SubsidiaryCode = groupedList.Key.SubsidiaryCode2,
AssetCreatedDate = groupedList.Key.AssetCreatedDate.Value.Date,
AssetCategory = groupedList.Key.AssetCategoryID
}
).Distinct().OrderBy(x => x.SubsidiaryCode).ThenBy(y => y.AssetCreatedDate).ToList();
旁注,您不需要将列表分配给类变量,也不需要 return 它;我建议只 return 它。如果您要缓存结果,请将 class 级别的 var 设置为私有,第一次分配它并 return ,第二次只分配 return (使用 null-ness 的 class 级别 var 来确定查询是否已经 运行)
扩展评论:
您不需要将数据存储在 public 属性 和 return 中。不要这样做:
public class Whatever{
public string Name {get;set;}
public string GetName(){
var name = "John";
Name = name;
return name;
}
通常我们会 return 它:
public class Whatever{
public string GetName(){
var name = MySlowDatabaseCallToCalculateAName();
return name;
}
//use it like:
var w = new Whatever();
var name = w.GetName();
或者我们存储它:
public class Whatever{
public string Name {get;set;}
public void PopulateName(){
Name = MySlowDatabaseCallToCalculateAName();
}
//use it like
var w = new Whatever();
w.PopulateName();
var name = w.Name;
如果我们提供某种缓存,我们 可能 会有类似两者的混合,比如如果查询真的很慢并且数据不经常更改,但它被广泛使用:
public class Whatever{
private string _name;
private DateTime _nameGeneratedAt = DateTime.MinValue;
public string GetName(){
//if it was more than a day since we generated the name, generate a new one
if(_nameGeneratedAt < DateTime.UtcNow.AddDays(-1)){
_name = MySlowDatabaseCallToCalculateAName();
_nameGeneratedAt = DateTime.UtcNow; //and don't do it again for at least a day
}
return _name;
}
这意味着我们每天只需要做一次缓慢的事情,但通常在“给我一个 name/asset list/whatever”这样的方法中,我们不会设置 public属性以及return这件事;呼叫者不知道该用哪一个——他们想要这个名字;他们应该访问 Name 属性 还是调用 GetName?如果 属性 被称为“MostRecentlyGeneratedName”,方法被称为“GenerateLatestName”,这将更有意义 - 调用者可以知道他们可能会先调用 Generate..(
,然后他们可以使用 MostRecently..
-就像缓存一样;调用 class 可以决定是获取最新的,还是重用最近生成的一个(但它确实引入了一些令人头疼的问题,如果其他操作在第一个操作的中间使用 属性..)..
..但我们可能不会这样做;相反,我们只提供 Generate..(
方法,如果调用者想要缓存它并重用结果,它可以
所以我想显示按两个字段分组的输出:SubsidiaryCode
和 AssetCreatedDate
。我的问题是它冗余地显示分组值。
由于我的详细信息 class.
我想要的是:
但是显示是这样的:
LINQ 查询:
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public IList<AssetListTemplate> List = new List<AssetListTemplate>();
public IList<AssetListTemplate> GetList()
{
using (var ctx = LinqExtensions.GetDataContext<NXpert.FixedAsset.DataAccess.FixedAssetDataContext>("AccountingDB"))
{
var list = (from x in ctx.DataContext.AssetRegistryEntities
where x.SubsidiaryCode2 != "" && x.SubsidiaryCode2.ToUpper().Contains("y-") && x.AssetCreatedDate>=FromDate && x.AssetCreatedDate <= ToDate
group new { x.SubsidiaryCode2, x.AssetCreatedDate,x.AssetCategoryID } by x into groupedList
select new AssetListTemplate
{
IsSelected = false,
SubsidiaryCode = groupedList.Key.SubsidiaryCode2,
AssetCreatedDate = groupedList.Key.AssetCreatedDate,
AssetCategory = groupedList.Key.AssetCategoryID
}
).OrderBy(x => x.SubsidiaryCode).ThenBy(y => y.AssetCreatedDate).ToList();
List = list;
foreach (var item in List)
{
var details = (from x in ctx.DataContext.AssetRegistryEntities
join y in ctx.DataContext.AssetCategoryEntities on x.AssetCategoryID equals y.AssetCategoryID
join z in ctx.DataContext.FixedAssetOtherInfoEntities on x.AssetCode equals z.AssetCode
where x.SubsidiaryCode2 == item.SubsidiaryCode
select new Details
{
AssetCode = x.AssetCode,
AssetCodeDesc = y.AssetCategoryDesc,
AssetDesc = x.AssetCodeDesc,
DepInCharge = z.DepartmentInCharge,
SerialNo = x.SerialNumber,
ModelNo = x.ModelNumber
}).ToList();
item.Details = details;
}
return List;
}
}
}
public class AssetListTemplate
{
public bool IsSelected { get; set; }
public string SubsidiaryCode { get; set; }
public DateTime? AssetCreatedDate { get; set; }
public string AssetCategory { get; set; }
public List<Details> Details { get; set; }
}
public class Details {
public string AssetCode { get; set; }
public string AssetCodeDesc { get; set; }
public string AssetDesc { get; set; }
public string DepInCharge { get; set; }
public string SerialNo { get; set; }
public string ModelNo { get; set; }
}
SQL Query:
SELECT Are_SubsidiaryCode2[SubsidiaryCode],Are_AssetCreatedDate[AssetCreatedDate],Are_AssetCategoryID[AssetCategory]
FROM E_AssetRegistry
WHERE Are_SubsidiaryCode2<>''
AND Are_SubsidiaryCode2 LIKE '%Y-%'
GROUP BY Are_SubsidiaryCode2
,Are_AssetCreatedDate
,Are_AssetCategoryID
ORDER BY AssetCreatedDate ASC
您似乎没有对任何聚合函数使用分组,因此您可以通过使用 distinct 使生活更简单:
from x in ctx.DataContext.AssetRegistryEntities
where x.SubsidiaryCode2.Contains("y-") && x.AssetCreatedDate>=FromDate && x.AssetCreatedDate <= ToDate
select new AssetListTemplate
{
IsSelected = false,
SubsidiaryCode = groupedList.Key.SubsidiaryCode2,
AssetCreatedDate = groupedList.Key.AssetCreatedDate.Value.Date,
AssetCategory = groupedList.Key.AssetCategoryID
}
).Distinct().OrderBy(x => x.SubsidiaryCode).ThenBy(y => y.AssetCreatedDate).ToList();
旁注,您不需要将列表分配给类变量,也不需要 return 它;我建议只 return 它。如果您要缓存结果,请将 class 级别的 var 设置为私有,第一次分配它并 return ,第二次只分配 return (使用 null-ness 的 class 级别 var 来确定查询是否已经 运行)
扩展评论:
您不需要将数据存储在 public 属性 和 return 中。不要这样做:
public class Whatever{
public string Name {get;set;}
public string GetName(){
var name = "John";
Name = name;
return name;
}
通常我们会 return 它:
public class Whatever{
public string GetName(){
var name = MySlowDatabaseCallToCalculateAName();
return name;
}
//use it like:
var w = new Whatever();
var name = w.GetName();
或者我们存储它:
public class Whatever{
public string Name {get;set;}
public void PopulateName(){
Name = MySlowDatabaseCallToCalculateAName();
}
//use it like
var w = new Whatever();
w.PopulateName();
var name = w.Name;
如果我们提供某种缓存,我们 可能 会有类似两者的混合,比如如果查询真的很慢并且数据不经常更改,但它被广泛使用:
public class Whatever{
private string _name;
private DateTime _nameGeneratedAt = DateTime.MinValue;
public string GetName(){
//if it was more than a day since we generated the name, generate a new one
if(_nameGeneratedAt < DateTime.UtcNow.AddDays(-1)){
_name = MySlowDatabaseCallToCalculateAName();
_nameGeneratedAt = DateTime.UtcNow; //and don't do it again for at least a day
}
return _name;
}
这意味着我们每天只需要做一次缓慢的事情,但通常在“给我一个 name/asset list/whatever”这样的方法中,我们不会设置 public属性以及return这件事;呼叫者不知道该用哪一个——他们想要这个名字;他们应该访问 Name 属性 还是调用 GetName?如果 属性 被称为“MostRecentlyGeneratedName”,方法被称为“GenerateLatestName”,这将更有意义 - 调用者可以知道他们可能会先调用 Generate..(
,然后他们可以使用 MostRecently..
-就像缓存一样;调用 class 可以决定是获取最新的,还是重用最近生成的一个(但它确实引入了一些令人头疼的问题,如果其他操作在第一个操作的中间使用 属性..)..
..但我们可能不会这样做;相反,我们只提供 Generate..(
方法,如果调用者想要缓存它并重用结果,它可以