没有重复数据的 LINQ 查询分组

LINQ query grouping without duplication of data

所以我想显示按两个字段分组的输出:SubsidiaryCodeAssetCreatedDate。我的问题是它冗余地显示分组值。 由于我的详细信息 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..( 方法,如果调用者想要缓存它并重用结果,它可以