Мне нужно приводить только примитивные типы?

#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. Я немного расширил ответ, основываясь на вашем обновленном коде, но, похоже, вы добились прогресса в том, чего хотели достичь.