Скажем, у меня есть класс, я хочу выбрать несколько объектов из него, но в конце создаю один объединенный объект.Это из-за требования к свойствам коллекции объекта, который нужно объединить.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Microsoft.EntityFrameworkCore.Internal;
using Nozomi.Base.Core;
namespace Nozomi.Data.Models.Currency
{
public class Currency : BaseEntityModel
{
public Currency(ICollection<Currency> currencies)
{
if (currencies.Any())
{
var firstCurr = currencies.FirstOrDefault();
if (firstCurr != null)
{
// Doesn't matter...
Id = firstCurr.Id;
CurrencyTypeId = firstCurr.Id;
CurrencyType = firstCurr.CurrencyType;
Abbrv = firstCurr.Abbrv;
Name = firstCurr.Name;
CurrencySourceId = firstCurr.CurrencySourceId;
CurrencySource = firstCurr.CurrencySource;
WalletTypeId = firstCurr.WalletTypeId;
PartialCurrencyPairs = currencies
.SelectMany(c => c.PartialCurrencyPairs)
.DefaultIfEmpty()
.ToList();
}
}
}
[Key]
public long Id { get; set; }
public long CurrencyTypeId { get; set; }
public CurrencyType CurrencyType { get; set; }
public string Abbrv { get; set; } // USD? MYR? IND?
public string Name { get; set; }
public long CurrencySourceId { get; set; }
public Source CurrencySource { get; set; }
// This will have a number if it is a crypto pair to peg to proper entities
public long WalletTypeId { get; set; } = 0;
public ICollection<PartialCurrencyPair> PartialCurrencyPairs { get; set; }
public bool IsValid()
{
return !String.IsNullOrEmpty(Abbrv) && !String.IsNullOrEmpty(Name) && CurrencyTypeId > 0 && CurrencySourceId > 0;
}
}
}
Вот что такое PartialCurrencyPair:
namespace Nozomi.Data.Models.Currency
{
/// <summary>
/// Partial currency pair.
/// </summary>
public class PartialCurrencyPair
{
public long CurrencyId { get; set; }
public long CurrencyPairId { get; set; }
public bool IsMain { get; set; } = false;
public CurrencyPair CurrencyPair { get; set; }
public Currency Currency { get; set; }
}
}
Так что, в принципе, если вы хотитечтобы сделать EURUSD, вам нужно взять две валюты, чтобы сформировать пару.CurrencyPair состоит из двух парциальных валютных пар.Причина, по которой у нас может быть много евро или много долларов, заключается в том, что они поступают из разных источников.
Вот что такое CurrencyPair:
public class CurrencyPair : BaseEntityModel
{
[Key]
public long Id { get; set; }
public CurrencyPairType CurrencyPairType { get; set; }
/// <summary>
/// Which CPC to rely on by default?
/// </summary>
public string DefaultComponent { get; set; }
public long CurrencySourceId { get; set; }
public Source CurrencySource { get; set; }
// =========== RELATIONS ============ //
public ICollection<CurrencyPairRequest> CurrencyPairRequests { get; set; }
public ICollection<WebsocketRequest> WebsocketRequests { get; set; }
public ICollection<PartialCurrencyPair> PartialCurrencyPairs { get; set; }
public bool IsValid()
{
var firstPair = PartialCurrencyPairs.First();
var lastPair = PartialCurrencyPairs.Last();
return (CurrencyPairType > 0) && (!string.IsNullOrEmpty(APIUrl))
&& (!string.IsNullOrEmpty(DefaultComponent))
&& (CurrencySourceId > 0)
&& (PartialCurrencyPairs.Count == 2)
&& (firstPair.CurrencyId != lastPair.CurrencyId)
&& (!firstPair.IsMain == lastPair.IsMain);
}
}
У меня есть IQueryable для объединения водна единая валюта.
Код с комментариями (В основном комментарии говорят о том, чего я пытаюсь достичь.
var query = _unitOfWork.GetRepository<Currency>()
.GetQueryable()
// Do not track the query
.AsNoTracking()
// Obtain the currency where the abbreviation equals up
.Where(c => c.Abbrv.Equals(abbreviation, StringComparison.InvariantCultureIgnoreCase)
&& c.DeletedAt == null && c.IsEnabled)
// Something here that will join the PartialCurrencyPair collection together and create one single Currency object.
.SingleOrDefault();
Как мне это сделать? Большое спасибовперёд! Вот прогресс , которого я добился до сих пор, и это работает, но я очень симпатичен LINQ имеет прекрасный способ сделать это лучше и оптимизированнее :
var combinedCurrency = new Currency(_unitOfWork.GetRepository<Currency>()
.GetQueryable()
// Do not track the query
.AsNoTracking()
// Obtain the currency where the abbreviation equals up
.Where(c => c.Abbrv.Equals(abbreviation, StringComparison.InvariantCultureIgnoreCase)
&& c.DeletedAt == null && c.IsEnabled)
.Include(c => c.PartialCurrencyPairs)
.ThenInclude(pcp => pcp.CurrencyPair)
.ThenInclude(cp => cp.CurrencyPairRequests)
.ThenInclude(cpr => cpr.RequestComponents)
.ThenInclude(rc => rc.RequestComponentDatum)
.ThenInclude(rcd => rcd.RcdHistoricItems)
.ToList());
return new DetailedCurrencyResponse
{
Name = combinedCurrency.Name,
Abbreviation = combinedCurrency.Abbrv,
LastUpdated = combinedCurrency.PartialCurrencyPairs
.Select(pcp => pcp.CurrencyPair)
.SelectMany(cp => cp.CurrencyPairRequests)
.SelectMany(cpr => cpr.RequestComponents)
.OrderByDescending(rc => rc.ModifiedAt)
.FirstOrDefault()?
.ModifiedAt ?? DateTime.MinValue,
WeeklyAvgPrice = combinedCurrency.PartialCurrencyPairs
.Select(pcp => pcp.CurrencyPair)
.Where(cp => cp.CurrencyPairRequests
.Any(cpr => cpr.DeletedAt == null && cpr.IsEnabled))
.SelectMany(cp => cp.CurrencyPairRequests)
.Where(cpr => cpr.RequestComponents
.Any(rc => rc.DeletedAt == null && rc.IsEnabled))
.SelectMany(cpr => cpr.RequestComponents
.Where(rc =>
rc.ComponentType.Equals(ComponentType.Ask) ||
rc.ComponentType.Equals(ComponentType.Bid)))
.Select(rc => rc.RequestComponentDatum)
.SelectMany(rcd => rcd.RcdHistoricItems
.Where(rcdhi => rcdhi.CreatedAt >
DateTime.UtcNow.Subtract(TimeSpan.FromDays(7))))
.Select(rcdhi => decimal.Parse(rcdhi.Value))
.DefaultIfEmpty()
.Average(),
DailyVolume = combinedCurrency.PartialCurrencyPairs
.Select(pcp => pcp.CurrencyPair)
.Where(cp => cp.CurrencyPairRequests
.Any(cpr => cpr.DeletedAt == null && cpr.IsEnabled))
.SelectMany(cp => cp.CurrencyPairRequests)
.Where(cpr => cpr.RequestComponents
.Any(rc => rc.DeletedAt == null && rc.IsEnabled))
.SelectMany(cpr => cpr.RequestComponents
.Where(rc => rc.ComponentType.Equals(ComponentType.VOLUME)
&& rc.DeletedAt == null && rc.IsEnabled))
.Select(rc => rc.RequestComponentDatum)
.SelectMany(rcd => rcd.RcdHistoricItems
.Where(rcdhi => rcdhi.CreatedAt >
DateTime.UtcNow.Subtract(TimeSpan.FromHours(24))))
.Select(rcdhi => decimal.Parse(rcdhi.Value))
.DefaultIfEmpty()
.Sum(),
Historical = combinedCurrency.PartialCurrencyPairs
.Select(pcp => pcp.CurrencyPair)
.SelectMany(cp => cp.CurrencyPairRequests)
.SelectMany(cpr => cpr.RequestComponents)
.Where(rc => componentTypes != null
&& componentTypes.Any()
&& componentTypes.Contains(rc.ComponentType)
&& rc.RequestComponentDatum != null
&& rc.RequestComponentDatum.IsEnabled
&& rc.RequestComponentDatum.DeletedAt == null
&& rc.RequestComponentDatum.RcdHistoricItems
.Any(rcdhi => rcdhi.DeletedAt == null &&
rcdhi.IsEnabled))
.ToDictionary(rc => rc.ComponentType,
rc => rc.RequestComponentDatum
.RcdHistoricItems
.Select(rcdhi => new ComponentHistoricalDatum
{
CreatedAt = rcdhi.CreatedAt,
Value = rcdhi.Value
})
.ToList())
};
Вот конечный результат, который я хочу получить для этого единственного объекта: объект DetailCurrencyResponse.
public class DistinctiveCurrencyResponse
{
public string Name { get; set; }
public string Abbreviation { get; set; }
public DateTime LastUpdated { get; set; }
public decimal WeeklyAvgPrice { get; set; }
public decimal DailyVolume { get; set; }
}
Исторический элемент данных - это, в основном, kvp, где Key (ComponentType) - это перечисление.
public class DetailedCurrencyResponse : DistinctiveCurrencyResponse
{
public Dictionary<ComponentType, List<ComponentHistoricalDatum>> Historical { get; set; }
}
public class ComponentHistoricalDatum
{
public DateTime CreatedAt { get; set; }
public string Value { get; set; }
}