Можно ли написать запрос LINQ, который преобразует IEnumerable<Invoice>
в Dictionary<InvoiceHeader, List<InvoiceHierarchi>>
и как это сделать правильно?
Да, вы можете. Попробуйте сгруппировать счета по 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()
и Equals()
для этого класса или реализацию IEquatable<T>
interface
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()
с изменяемыми объектами, так как состояние объекта можно изменить, но ha sh остается прежним
Вы можете переопределить GetHashCode()
для неизменяемых ссылочных типов. В целом, для изменяемых ссылочных типов вы должны переопределять GetHashCode()
только в том случае, если:
Вы можете вычислить код ha sh из полей, которые не являются изменяемыми;
Вы можете гарантировать, что код ha sh изменяемого объекта не изменится, пока объект содержится в коллекции, которая использует свой код ha sh.
В противном случае вы можете подумать, что изменяемый объект потерян в таблице ha sh.
Итак, лучше сделать любые (или все) свойства InvoiceHeader
доступными только для чтения, инициализировать их из конструктора и использовать для получения кода ha sh *