【问题标题】:Why related table values comes null on HttpContext.Session.Get using List<>?为什么使用 List<> 的相关表值在 HttpContext.Session.Get 上为空?
【发布时间】:2019-08-06 21:25:08
【问题描述】:

我正在开发一个购物车(使用 MVC Asp.Net Core 2.2 和 EF)。

有 3 个表(模型类):

  • 产品;
  • Tamanho(与 Produto 表相关);
  • TipoMassa(与 Produto 表相关)。

在 ProductController 类中,我创建了一个存储在 Session 中的列表,以便在 CartController 类中获取此列表。

但是,当我尝试在 CartController 类中获取该列表时,相关表(Tamanho 和 TipoMassa)中的值是空的。该列表仅包含 Produto 表值。

我该如何解决?

产品控制器类

public ActionResult AddToCart(IFormCollection collection)
{
    string Nome = collection["Nome"];
    byte IdTamanho = Convert.ToByte(collection["IdTamanho"]);
    byte IdTipoMassa = Convert.ToByte(collection["IdTipoMassa"]);


    var produtoContext = _context.Produto
            .Include(c => c.IdCategoriaNavigation)
            .Include(c => c.IdTamanhoNavigation)
            .Include(c => c.IdTipoMassaNavigation)
            .FirstOrDefault(p => p.Nome == Nome && p.IdTamanho == IdTamanho
        && p.IdTipoMassa == IdTipoMassa);

    if (produtoContext == null)
    {
        return NotFound();
    }

    // Add itens na Sesssion
    List<Produto> itens = new List<Produto>();
    itens = HttpContext.Session.Get<List<Produto>>("itens");
    if (itens == null)
    {
        itens = new List<Produto>();
    }

    itens.Add(produtoContext);
    HttpContext.Session.Set("itens", itens);
    TempData["save"] = "Adicionado com sucesso";

    return RedirectToAction(nameof(Index), "Produto");
}
  • 工作正常! 但是在 [CartController] IdCategoriaNavigation 中,IdTamanhoNavigation 和 IdTipoMassaNavigation 为空。代码如下。

购物车控制器类

public IActionResult Index()
{
    List<Produto> itens = HttpContext.Session.Get<List<Produto>>
            ("itens");
    if (itens == null)
    {
        itens  = new List<Produto>();
    }
    return View(itens.ToList());
}
  • 当我尝试在视图中显示值时,相关的表值(IdCategoriaNavigation、IdTamanhoNavigation 和 IdTipoMassaNavigation)为空。代码如下。

购物车视图

 @foreach (var item in Model)
 {
  <tr>
      <td>
          <small class="text-muted"> 2x </small>
      </td>
      <td>
           @Html.DisplayFor(modelItem => item.Nome)
           <br />
           <small class="text-muted">@Html.DisplayFor(modelItem => item.Descricao)</small>
  
            @if (item.IdCategoria == 1)
            {
              <small class="text-dark font-italic">
                  <label for="idTamanho"> 
                     @Html.DisplayFor(modelItem => item.IdTamanhoNavigation)
                  </label>
                    @Html.DisplayFor(modelItem => item.IdTamanhoNavigation.Valor)
              </small>

              <small class="text-dark font-italic">
                    <label for="idTamanho"> @Html.DisplayFor(model => item.IdTipoMassaNavigation)</label>
                      @Html.DisplayFor(modelItem => item.IdTipoMassaNavigation.Valor)
              </small>
             }
        </td>
        <td class="text-right">
             2x R$ @Html.DisplayFor(modelItem => item.Preco)
        </td>
        <td class="align-content-end">
             <a asp-controller="Produto" asp-action="RemoveFromCart" asp-route-id="@item.IdProduto" class="text-white">
                 <i class="fa fa-times text-info"></i>
             </a>
        </td>
 </tr>
 }

产品模型类

public partial class Produto
{
    public Produto()
    {
        Cardapio = new HashSet<Cardapio>();
        ItensPedido = new HashSet<ItensPedido>();
        Promocao = new HashSet<Promocao>();
    }

    public int IdProduto { get; set; }
    public int IdCategoria { get; set; }
    public byte IdTamanho { get; set; }
    public byte IdTipoMassa { get; set; }
    public string Nome { get; set; }
    public string Descricao { get; set; }
    public string Imagem { get; set; }

    [Column(TypeName = "decimal(18, 2)")]
    public decimal Preco { get; set; }
    public bool IsAtivo { get; set; }

    [JsonIgnore]
    public virtual Categoria IdCategoriaNavigation { get; set; }
    [JsonIgnore]
    public virtual Tamanho IdTamanhoNavigation { get; set; }
    [JsonIgnore]
    public virtual TipoMassa IdTipoMassaNavigation { get; set; }
    public virtual ICollection<Cardapio> Cardapio { get; set; }
    public virtual ICollection<ItensPedido> ItensPedido { get; set; }
    public virtual ICollection<Promocao> Promocao { get; set; }
}

Tamanho 模型类

public partial class Tamanho
{
    public Tamanho()
    {
        Produto = new HashSet<Produto>();
    }

    public byte IdTamanho { get; set; }
    public string Valor { get; set; }

    public virtual ICollection<Produto> Produto { get; set; }
}

TipoMassa 模型类

public partial class TipoMassa
{
    public TipoMassa()
    {
        Produto = new HashSet<Produto>();
    }

    public byte IdTipoMassa { get; set; }
    public string Valor { get; set; }

    public virtual ICollection<Produto> Produto { get; set; }
}

我想在 ShoppingCart 视图中显示所有值。

【问题讨论】:

  • 尝试使用 Session.Add 而不是 Session.Set

标签: c# asp.net-core model-view-controller


【解决方案1】:

除非我弄错了,否则我认为问题仅仅是 lambda 函数:

代替

@Html.DisplayFor(modelItem => item.IdTamanhoNavigation)
                              ^^^

你需要引用正确的输入参数(modelItem):

@Html.DisplayFor(modelItem => modelItem.IdTamanhoNavigation)
                                 ^^^

【讨论】:

  • @peter 谢谢菲利普,是我试图解决问题的错误。但“主要问题是”从 ShoppingCart 控制器上的会话中获取列表,但相关导航值仍为 null。
  • @GutoBarroso 你的意思是 foreach (模型中的变量项)给你一个 NullReference 错误吗? “项目”是空的吗?还是 item.IdTamanhoNavigation 为空?
  • 问题应该与父/子集合有关。父集合项 (item.IdTamanhoNavigation) 给我 null。 Child 集合项 (item.IdTamanhoNavigation.Valor) 给了我一个 NullReference 错误。因为 JsonConvert.SerializeObject 没有序列化相关的表值(给我一个检测到关于子集合的自引用循环)。
  • 序列化对象时使用 PreservReferensHandling.Objects 解决的问题。 newtonsoft.com/json/help/html/PreserveObjectReferences.htm
【解决方案2】:

我忘了说我一直在使用 JSon 将该 List 序列化为 Session。 但是我不得不在 Produto Model 类的那些相关方法上使用 [JsonIgnore], 如果没有,当包含这些相关的表值时,我会从 Newtonsoft.Jason 收到错误消息。

如下图所示

关于 ShoppingCart 控制器类

public ActionResult AddToCart(IFormCollection collection)
{
    ...

    var produtoContext = _context.Produto
        .Include(c => c.IdCategoriaNavigation)
         ^^^^
        .Include(c => c.IdTamanhoNavigation)
         ^^^^
        .Include(c => c.IdTipoMassaNavigation)
         ^^^^
       .FirstOrDefault(p => p.Nome == Nome && p.IdTamanho == IdTamanho 
    && p.IdTipoMassa == IdTipoMassa);

    ... 

    The produtoContex here, normally has all the values from the related tables.
        {PianoPizza.Models.Categoria} 
        {PianoPizza.Models.Tamanho}
        {PianoPizza.Models.TipoMassa}

        But when I set the List on Session I got the Json error.     

    HttpContext.Session.Set("itens", itens);
                        ^^^^
    ...
 }

JsonSerializationException:检测到类型为“Pianino.Models.Produto”的自引用循环。 路径“[0].IdCategoriaNavigation.Produto”。 Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)

即使评论第一个包括,我对 IdTamanhoNavigation 和 IdTipoMassaNavigation 也是如此。

所以,使用如下所示的 [JsonIgnore],我修复了该错误。另一方面,当我从 ShoppingCart Controller 类的 Session 中获取 List 时,这些值变为 null。

关于产品模型类

 [JsonIgnore]
 public virtual Categoria IdCategoriaNavigation { get; set; }
 [JsonIgnore]
 public virtual Tamanho IdTamanhoNavigation { get; set; }
 [JsonIgnore]
 public virtual TipoMassa IdTipoMassaNavigation { get; set; }

关于实用程序类

public static class SessionExtensions
{

    public static void Set<T>(this ISession session, string key, T value)
    {
        session.SetString(key, JsonConvert.SerializeObject(value));
    }

    public static T Get<T>(this ISession session, string key)
    {
        var value = session.GetString(key);

        return value == null ? default(T) :
            JsonConvert.DeserializeObject<T>(value);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    • 2020-09-01
    • 2021-05-11
    • 2014-03-24
    相关资源
    最近更新 更多