Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 利用LINQ实现复群_C#_Linq - Fatal编程技术网

C# 利用LINQ实现复群

C# 利用LINQ实现复群,c#,linq,C#,Linq,我熟悉LINQ中的简单groupby操作。但我有一个复杂的场景。我需要使用group by将CostPageRow记录转换为CostPageSelection域对象。如何从列表中获取域对象 注意:我上面写的小组成员没有给出列表。我不知道怎么写。CostPageSelection中有一个列表 List<CostPageRow> costPageRows = searchDAL .GetAllCostPages(contextObject, searchCriteria);

我熟悉
LINQ
中的简单
groupby
操作。但我有一个复杂的场景。我需要使用group by将
CostPageRow
记录转换为
CostPageSelection
域对象。如何从列表中获取域对象

注意:我上面写的小组成员没有给出列表。我不知道怎么写。CostPageSelection中有一个列表

List<CostPageRow> costPageRows = searchDAL
    .GetAllCostPages(contextObject, searchCriteria);


var orderGroups = costPageRows
     .GroupBy(x => new { 
         x.CostPage, 
         x.Description, 
         x.BillTypeDirect,
         x.BillTypeWarehouse,
         x.OrderType,
         x.Vendor,
         x.VendorID 
     })
     .Select(y => new CostPageParent { 
           CostPage = y.First().CostPage 
     })
     .ToList();
域模型

public class CostPageSelection
{
    public CostPageParent CostPageParent { get; set; }
    public List<ItemChild> ChildItems { get; set; }
}


//CostPageParent
public class CostPageParent
{
    public int? SelectedCostPageID { get; set; }
    public string CostPage { get; set; }
    public string Description { get; set; }
    public string Vendor { get; set; }
    public string VendorID { get; set; }
    public string BillTypeDirect { get; set; }
    public string BillTypeWarehouse { get; set; }
    public string OrderType { get; set; }
}

//ItemChild
public class ItemChild
{
    public int? SelectedItemID { get; set; }
    public string ItemID { get; set; }
    public string ItemDescription { get; set; }
    public string BrandCode { get; set; }
    public string PackSize { get; set; }
}
公共类CostPageSelection
{
公共CostPageParent CostPageParent{get;set;}
公共列表子项{get;set;}
}
//CostPageParent
公共类CostPageParent
{
public int?SelectedCostPageID{get;set;}
公共字符串CostPage{get;set;}
公共字符串说明{get;set;}
公共字符串供应商{get;set;}
公共字符串VendorID{get;set;}
公共字符串BillTypeDirect{get;set;}
公共字符串BillTypeWarehouse{get;set;}
公共字符串OrderType{get;set;}
}
//项目儿童
公共类ItemChild
{
public int?SelectedItemID{get;set;}
公共字符串ItemID{get;set;}
公共字符串ItemDescription{get;set;}
公共字符串BrandCode{get;set;}
公共字符串PackSize{get;set;}
}

我想您正在寻找这样的产品:

var orderGroups = costPageRows
 .GroupBy(x => new { 
     x.CostPage, 
     x.Description, 
     x.BillTypeDirect,
     x.BillTypeWarehouse,
     x.OrderType,
     x.Vendor,
     x.VendorID 
 })
 // The following statement is basically a let statement from query expression
 .Select(y => new {
      y, 
      first = y.First()
 })
 // What happens next is projection into the CostPageSelection type using z.first
 // and then all the grouped items in z are projected into the ItemChild type
 .Select(z => new CostPageSelection {
      new CostPageParent { 
          z.first.CostPage, 
          // other props 
          ChildItems = z.Select(i => new ItemChild {
              i.ItemID,
              // other props 
          }).ToList()
 })
 .ToList();

从您的问题来看,您的数据库似乎包含一个扁平的父子关系层次结构,如果数据库模式被规范化以避免数据重复,则会更好:换句话说,每个
CostPageRow
行都应该包含对不同表的引用,该表包含相关的
CostPageParent
实例(但我假设您已经有一个正在运行的数据库,这不是一个选项)

要解决当前的问题,您需要从每个
CostPageRow
实例中提取定义单个组的属性(这些属性将形成一个新的
CostPageParent
实例),然后使用这些
CostPageParent
实例作为唯一键创建组,最后,将这些组投影到
CostPageSelection
的新实例(每个实例都有一个唯一的
CostPageParent
键)

创建组密钥后,您需要修改代码以使用
IGrouping.Key
属性获取组密钥:

var groups = costPageRows
    .GroupBy(x => new CostPageParent()
        {
            CostPage = x.CostPage,
            Description = x.Description,
            BillTypeDirect =  x.BillTypeDirect,
            BillTypeWarehouse = x.BillTypeWarehouse,
            OrderType = x.OrderType,
            Vendor = x.Vendor
        }, 
        new CostPageParentEqualityComparer())
    .Select(y => new CostPageSelection
        {
            CostPageParent = y.Key,
            ChildItems = y.Select(i => 
                new ItemChild()
                { 
                    BrandCode = i.BrandCode,
                    ItemDescription = i.ItemDescription,
                    ItemID = i.ItemID,
                    PackSize = i.PackSize
                })
                .ToList()
        })
    .ToList();
请注意,您需要指定
IEqualityComparer
实现以使分组有效属性:

class CostPageParentEqualityComparer : IEqualityComparer<CostPageParent>
{
    public bool Equals(CostPageParent x, CostPageParent y)
    {
        if (x == null)
            return y == null;

        if (object.ReferenceEquals(x, y))
            return true;

        return 
            x.BillTypeDirect == y.BillTypeDirect &&
            x.BillTypeWarehouse == y.BillTypeWarehouse &&
            ...
    }

    public int GetHashCode(CostPageParent obj)
    {
        var x = 31;
        x = x * 17 + obj.BillTypeDirect.GetHashCode();
        x = x * 17 + obj.BillTypeWarehouse.GetHashCode();
        ...
        return x;
    }
}
class CostPageParentEqualityComparer:IEqualityComparer
{
公共布尔等于(CostPageParent x,CostPageParent y)
{
如果(x==null)
返回y==null;
if(object.ReferenceEquals(x,y))
返回true;
返回
x、 BillTypeDirect==y.BillTypeDirect&&
x、 BillTypeWarehouse==y.BillTypeWarehouse&&
...
}
public int GetHashCode(CostPageParent obj)
{
var x=31;
x=x*17+obj.BillTypeDirect.GetHashCode();
x=x*17+obj.BillTypeWarehouse.GetHashCode();
...
返回x;
}
}

那么,你有什么问题?@lazyberezovsky。我上面写的小组没有给出清单。我不知道怎么写。CostPageSelection中有一个列表。@Groo您能发布您的代码吗?我的信念是,分组是必要的。因为常见的是父母。我们有一份清单谢谢。。它起作用了。。你能解释一下为什么我们需要GetHashCode逻辑吗?即使我作为GetHashCode的结果返回一个硬编码的值,分组也可以正常工作。@Groo
GroupBy
是在内部使用基于哈希的数据结构实现的(无论是
Dictionary
还是类似的),因此,如果您想对某个类型使用
GroupBy
,您肯定需要有一个适当的
GetHashCode
实现。@Lijo它是有效的,因为正确实现
GetHashCode
的规则规定,根据
Equals
相等的所有对象都必须有相同的哈希代码。最好确保不相等的对象不太可能具有相同的哈希(某些情况是不可避免的)。共享散列的对象越多,数据结构的性能就越差。如果所有对象都有相同的has代码,它将工作,但速度会非常慢。有关详细信息,请参阅。@Servy:是的,你说得对,我不知道我在想什么,因为这是在
O(n)
time中实现分组的唯一合理方法。当然,Lijo的代码使用的是常量散列值,但性能是二次的。我看到了这条评论,并立即开始写一个一般性的答案,解释为什么在所有情况下实施它都是好的。
class CostPageParentEqualityComparer : IEqualityComparer<CostPageParent>
{
    public bool Equals(CostPageParent x, CostPageParent y)
    {
        if (x == null)
            return y == null;

        if (object.ReferenceEquals(x, y))
            return true;

        return 
            x.BillTypeDirect == y.BillTypeDirect &&
            x.BillTypeWarehouse == y.BillTypeWarehouse &&
            ...
    }

    public int GetHashCode(CostPageParent obj)
    {
        var x = 31;
        x = x * 17 + obj.BillTypeDirect.GetHashCode();
        x = x * 17 + obj.BillTypeWarehouse.GetHashCode();
        ...
        return x;
    }
}