正确组织和转换对象
Proper organization and transformation of objects
我有一个复杂的 SQL 查询 returns 一个 table 像这样:
我用这个对象描述了它 - IEnumerable<Invoice>
其中:
public partial class Invoice
{
public string DocumentNumber { get; set; }
public DateTime? DocumentDate { get; set; }
public string DocumentReference { get; set; }
public string SerialNumber { get; set; }
public string ProductCode { get; set; }
public string Description { get; set; }
public string Certificate { get; set; }
}
这些对象的集合的特殊之处在于它们按前三个字段分组(如果它们相同),其余字段不同。
我的任务是实现此数据的分层表示,它应该如下所示:
我自己决定我的最终视图对象应该具有以下结构 - Dictionary<InvoiceHeader, List<InvoiceHierarchi>>
其中:
public class InvoiceHeader
{
public string DocumentNumber { get; set; }
public DateTime? DocumentDate { get; set; }
public string DocumentReference { get; set; }
}
public class InvoiceHierarchi
{
public string SerialNumber { get; set; }
public string ProductCode { get; set; }
public string Description { get; set; }
public string Certificate { get; set; }
}
问题 #1:我可以编写将 IEnumerable<Invoice>
转换为 Dictionary<InvoiceHeader, List<InvoiceHierarchi>>
的 LINQ 查询吗?如何正确执行?
问题 #2:总的来说,我是否选择了正确的方法来解决我的任务?
Can I write LINQ query that converts IEnumerable<Invoice>
to
Dictionary<InvoiceHeader, List<InvoiceHierarchi>>
and how to do it
right?
是的,你可以。尝试按 InvoiceHeader
分组发票并使用 ToDictionary
方法
转换结果
var invoices = new List<Invoice>();
var result = invoices.GroupBy(i => new InvoiceHeader
{
DocumentDate = i.DocumentDate,
DocumentNumber = i.DocumentNumber,
DocumentReference = i.DocumentReference
}).ToDictionary(g => g.Key, g => g.Select(i => new InvoiceHierarchi
{
Certificate = i.Certificate,
SerialNumber = i.SerialNumber,
ProductCode = i.ProductCode,
Description = i.Description
}).ToList());
另一种选择是使用ToLookup
方法
var anotherResult = invoices.ToLookup(i => new InvoiceHeader
{
DocumentDate = i.DocumentDate,
DocumentNumber = i.DocumentNumber,
DocumentReference = i.DocumentReference
},
i => new InvoiceHierarchi
{
Certificate = i.Certificate,
SerialNumber = i.SerialNumber,
ProductCode = i.ProductCode,
Description = i.Description
});
要正确使用 InvoiceHeader
作为 Dictionary
键,您应该覆盖 GetHashCode()
and Equals()
methods for this class, or implelement IEquatable<T>
接口
public class InvoiceHeader : IEquatable<InvoiceHeader>
{
public string DocumentNumber { get; set; }
public DateTime? DocumentDate { get; set; }
public string DocumentReference { get; set; }
public override int GetHashCode()
{
return DocumentNumber.GetHashCode() ^ DocumentDate.GetHashCode() ^ DocumentReference.GetHashCode();
}
public bool Equals(InvoiceHeader other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return DocumentNumber == other.DocumentNumber &&
Nullable.Equals(DocumentDate, other.DocumentDate) &&
DocumentReference == other.DocumentReference;
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((InvoiceHeader)obj);
}
}
你会得到一个警告,在 GetHashCode()
中使用了非只读 属性,因为不建议对可变对象使用 GetHashCode()
,因为对象的状态可以被更改,但哈希保持不变
You can override GetHashCode()
for immutable reference types. In
general, for mutable reference types, you should override
GetHashCode()
only if:
You can compute the hash code from fields that are not mutable;
You can ensure that the hash code of a mutable object
does not change while the object is contained in a collection that
relies on its hash code.
Otherwise, you might think that the mutable object is lost in the hash table.
因此,最好将 InvoiceHeader
的任何(或所有)属性设为只读,从构造函数中初始化它们并用于获取哈希码
我有一个复杂的 SQL 查询 returns 一个 table 像这样:
我用这个对象描述了它 - IEnumerable<Invoice>
其中:
public partial class Invoice
{
public string DocumentNumber { get; set; }
public DateTime? DocumentDate { get; set; }
public string DocumentReference { get; set; }
public string SerialNumber { get; set; }
public string ProductCode { get; set; }
public string Description { get; set; }
public string Certificate { get; set; }
}
这些对象的集合的特殊之处在于它们按前三个字段分组(如果它们相同),其余字段不同。
我的任务是实现此数据的分层表示,它应该如下所示:
我自己决定我的最终视图对象应该具有以下结构 - Dictionary<InvoiceHeader, List<InvoiceHierarchi>>
其中:
public class InvoiceHeader
{
public string DocumentNumber { get; set; }
public DateTime? DocumentDate { get; set; }
public string DocumentReference { get; set; }
}
public class InvoiceHierarchi
{
public string SerialNumber { get; set; }
public string ProductCode { get; set; }
public string Description { get; set; }
public string Certificate { get; set; }
}
问题 #1:我可以编写将 IEnumerable<Invoice>
转换为 Dictionary<InvoiceHeader, List<InvoiceHierarchi>>
的 LINQ 查询吗?如何正确执行?
问题 #2:总的来说,我是否选择了正确的方法来解决我的任务?
Can I write LINQ query that converts
IEnumerable<Invoice>
toDictionary<InvoiceHeader, List<InvoiceHierarchi>>
and how to do it right?
是的,你可以。尝试按 InvoiceHeader
分组发票并使用 ToDictionary
方法
var invoices = new List<Invoice>();
var result = invoices.GroupBy(i => new InvoiceHeader
{
DocumentDate = i.DocumentDate,
DocumentNumber = i.DocumentNumber,
DocumentReference = i.DocumentReference
}).ToDictionary(g => g.Key, g => g.Select(i => new InvoiceHierarchi
{
Certificate = i.Certificate,
SerialNumber = i.SerialNumber,
ProductCode = i.ProductCode,
Description = i.Description
}).ToList());
另一种选择是使用ToLookup
方法
var anotherResult = invoices.ToLookup(i => new InvoiceHeader
{
DocumentDate = i.DocumentDate,
DocumentNumber = i.DocumentNumber,
DocumentReference = i.DocumentReference
},
i => new InvoiceHierarchi
{
Certificate = i.Certificate,
SerialNumber = i.SerialNumber,
ProductCode = i.ProductCode,
Description = i.Description
});
要正确使用 InvoiceHeader
作为 Dictionary
键,您应该覆盖 GetHashCode()
and Equals()
methods for this class, or implelement IEquatable<T>
接口
public class InvoiceHeader : IEquatable<InvoiceHeader>
{
public string DocumentNumber { get; set; }
public DateTime? DocumentDate { get; set; }
public string DocumentReference { get; set; }
public override int GetHashCode()
{
return DocumentNumber.GetHashCode() ^ DocumentDate.GetHashCode() ^ DocumentReference.GetHashCode();
}
public bool Equals(InvoiceHeader other)
{
if (ReferenceEquals(null, other))
return false;
if (ReferenceEquals(this, other))
return true;
return DocumentNumber == other.DocumentNumber &&
Nullable.Equals(DocumentDate, other.DocumentDate) &&
DocumentReference == other.DocumentReference;
}
public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((InvoiceHeader)obj);
}
}
你会得到一个警告,在 GetHashCode()
中使用了非只读 属性,因为不建议对可变对象使用 GetHashCode()
,因为对象的状态可以被更改,但哈希保持不变
You can override
GetHashCode()
for immutable reference types. In general, for mutable reference types, you should overrideGetHashCode()
only if:You can compute the hash code from fields that are not mutable;
You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
Otherwise, you might think that the mutable object is lost in the hash table.
因此,最好将 InvoiceHeader
的任何(或所有)属性设为只读,从构造函数中初始化它们并用于获取哈希码