#c# #entity-framework
#c# #entity-framework
Вопрос:
Я пытаюсь использовать анонимные типы в Entity Framework, но я получаю сообщение об
Не удается создать постоянное значение
MinQty
и MaxQty
являются int, поэтому я не знаю, нужно ли мне добавлять к Convert.ToInt32
?
Не удается создать постоянное значение типа ‘Анонимный тип’. В этом контексте поддерживаются только примитивные типы или типы перечислений.
Это создает объект списка
var listOfLicense = (from l in db.License
select new
{
l.ProductId,
l.MinLicense,
l.MaxLicense
}).tolist();
Это более крупный объект EF, где я получаю сообщение об ошибке, я пропустил приведение?
var ShoppingCart = (from sc in db.ShoppingCarts
Select new model.Shoppingchart{
ShoppingCartId= sc.Id,
MinQty = (int)listOfLicense
.Where(mt => (int)mt.ProductId == sc.ProductId)
.Select(mt => (int)mt.MinLicense)
.Min(mt => mt.Value),
MaxQty = (int)listOfLicense
.Where(mt => (int)mt.ProductId == p.ProductId)
.Select(mt =>(int) mt.MaxQty)
.Max(mt => mt.Value)}.tolist();
Комментарии:
1.
Min
иMax
являются агрегатными функциями, и вы вызываете два разных агрегата в одном запросе, вероятно, смешанные с другими материалами, которые вы не показываете. Вероятно, вам понадобятся отдельные запросы к БД или переключение на оценку на стороне клиента2. @camilo-terevinto это единственный способ? Я не могу сделать это с подразделами?
3. Это зависит от того, что выполняет весь ваш запрос, но вы не опубликовали все. Если ваш запрос можно использовать с
GroupBy
, то вы можете продолжить с одним запросом, в противном случае вам потребуется несколько запросов / оценка на стороне клиента
Ответ №1:
Это создает объект списка
var listOfLicense = (из l в db.Лицензия выберите new {l.ProductID, l.MinLicense, l.MaxLicense })
Приведенный выше пример не создает список объектов. Он создает запрос для возврата объектов этого анонимного типа.
Это создает список объектов этого типа в памяти:
var listOfLicense = (from l in db.License
select new
{
l.ProductId,
l.MinLicense,
l.MaxLicense
}).ToList();
Использование .ToList()
здесь выполнит запрос и вернет материализованный список анонимных типов. После этого ваш код может работать так, как ожидалось, без исключения. Однако это эффективно загружает 3 столбца из всех строк в вашей таблице базы данных, что может стать проблемой по мере развития системы и добавления строк.
Ошибка, которую вы получаете, не является проблемой приведения, это проблема перевода. Поскольку ваш первоначальный запрос по-прежнему является всего лишь запросом EF, ( IQueryable
) любые дальнейшие запросы к нему должны соответствовать ограничениям EF. EF должен иметь возможность переводить то, что ваши выражения пытаются выбрать, обратно в SQL. В вашем случае ваш реальный код пытается нарушить эти правила.
Как правило, лучше позволить EF работать с IQueryable
, а не материализовывать весь список в памяти. Хотя для этого нам нужно либо увидеть реальный код, либо минимально воспроизводимый пример.
Этот код:
MinQty = (int)listOfLicense
.Where(mt => (int)mt.ParentProductId == p.ProductId)
.Select(mt => (int)mt.MinLicense)
.Min(mt => mt.Value),
… не соответствует указанному выше анонимному типу, поскольку нет корреляции между тем, что mt.ParentProductId
относится к анонимному типу. ( p
похоже, что это связано с этим типом, а не mt
так что, похоже, в вашем примере отсутствует много кода запроса.)
Редактировать: на основе вашего обновленного примера:
var ShoppingCart = (from sc in db.ShoppingCarts
Select new model.Shoppingchart{
ShoppingCartId= sc.Id,
MinQty = (int)listOfLicense
.Where(mt => (int)mt.ProductId == sc.ProductId)
.Select(mt => (int)mt.MinLicense)
.Min(mt => mt.Value),
MaxQty = (int)listOfLicense
.Where(mt => (int)mt.ProductId == p.ProductId)
.Select(mt =>(int) mt.MaxQty)
.Max(mt => mt.Value)}.ToList();
Возможно, удастся встроить что-то подобное в одно выражение запроса в зависимости от отношений между ShoppingCart, продуктом и лицензией. Похоже, что «Лицензия» действительно относится к «Продукту», который содержит минимальное и максимальное количество, которое вас интересует.
Предполагая структуру, подобную:
public class Product
{
[Key]
public int ProductId { get; set; }
public int MinQuantity { get; set; }
public int MaxQuantity { get; set; }
// ...
}
// Here lies a question on how your shopping cart to product relationship is mapped. I've laid out a many-to-many relationship using ShoppingCartItems
public class ShoppingCart
{
[Key]
public int ShoppingCartId { get; set; }
// ...
public virtual ICollection<ShoppingCartItem> ShoppingCartItems { get; set; } = new List<ShoppingCartItem>();
}
public class ShoppingCartItem
{
[Key, Column(0), ForeignKey("ShoppingCart")]
public int ShoppingCartId { get; set; }
public virtual ShoppingCart ShoppingCart{ get; set; }
[Key, Column(1), ForeignKey("Product")]
public int ProductId { get; set; }
public virtual Product Product { get; set; }
}
С помощью чего-то подобного, чтобы получить корзины покупок с минимальным и максимальным количеством продуктов:
var shoppingCarts = db.ShoppingCarts
.Select(sc => new model.ShoppingCart
{
ShoppingCartId = sc.Id,
Products = sc.ShoppingCartItems
.Select(sci => new model.Product
{
ProductId = sci.ProductId,
MinQuantity = sci.MinQuantity,
MaxQuantity = sci.MaxQuantity
}).ToList()
}).ToList();
Это предоставит список корзин для покупок, каждая из которых содержит список продуктов с их соответствующими минимальными / максимальными количествами.
Если вы также хотели наименьшее минимальное количество и наибольшее максимальное количество для всех товаров в корзине:
var shoppingCarts = db.ShoppingCarts
.Select(sc => new model.ShoppingCart
{
ShoppingCartId = sc.Id,
Products = sc.ShoppingCartItems
.Select(sci => new model.Product
{
ProductId = sci.ProductId,
MinQuantity = sci.MinQuantity,
MaxQuantity = sci.MaxQuantity
}).ToList(),
OverallMinQuantity = sc.ShoppingCartItems
.Min(sci => sci.MinQuantity),
OverallMaxQuantity = sc.ShoppingCartItems
.Max(sci => sci.MaxQuantity),
}).ToList();
Хотя я не уверен, насколько практичной может быть подобная фигура по отношению к структуре корзины покупок. В любом случае, с навигационными свойствами, настроенными для связи между вашими объектами, EF должен быть вполне способен создавать IQueryable
запрос для данных, которые вы хотите получить, не прибегая к предварительной выборке списков. Одна из проблем с предварительной выборкой и повторным введением этих списков в дальнейшие запросы заключается в том, что будет максимальное количество строк, которые EF может обработать. Как и в предложениях SQL IN
, существует максимальное количество элементов, которые могут быть проанализированы из набора.
В любом случае, похоже, что это дало вам несколько идей, чтобы попытаться получить нужные вам цифры.
Комментарии:
1. Я обновляю сообщение некоторым дополнительным кодом, могу ли я использовать IQueryable?
2. Я немного расширил ответ, основываясь на вашем обновленном коде, но, похоже, вы добились прогресса в том, чего хотели достичь.