如何在 ASP.Net Core 中将模型(包含超过 3000 条记录的列表)从一个视图发送到另一个 get 操作?

How to send a model (a List with more than 3000 records) from a view to another get action in ASP.Net Core?

提问人:NedaM 提问时间:10/26/2023 最后编辑:NedaM 更新时间:10/27/2023 访问量:90

问:

我有一个 ASP.net 核心项目。我想通过“a”标签将整个模型(即产品列表)从视图发送到控制器中的另一个获取操作。我使用了 TempData,但它不起作用。产品模型具有许多属性和外键。 下面是一个示例:

第一个动作是:

public IActionResult ShowProducts(int side, MyViewModel myViewModel)
{
    ViewBag.side = side;
    if (side == 0)
    {
        List<Product> products =  ShowAllProducts();
        return View(products);
    }

    List<Product> products2 = FilterProducts(myViewModel);
    return View(products2 );
}

List<Product> FilterProducts(MyViewModel myViewModel)
{
    List<Product> Products = new List<Product>() {};
    //some code...
    return products;
}

List<Product> ShowAllProducts()
{
    return _context.Products.Include(p => p.Table1).Include(p => p.Table2)
         .Include(p => p.Table3).Include(p => p.Table4)
         .Include(p => p.Table5).Include(p => p.Table6)
         .Include(p => p.Table7).Include(p => p.Table8).Tolist();
}

第二个动作是:

public IActionResult PrintProducts(List<Product> model)
{
    return View(model);
}

ShowProducts 视图是:

    @model IEnumerable<Product>
    
     @*some tag*@

     <a title="Print" asp-action="PrintProducts" asp-route-model ="@Model"></a>

     @*some tag*@

在此示例中,第二个操作中的模型为空。实际上它不发送。

我这样更改了视图:

 @model IEnumerable<Product>

 @*some tag*@
 <a title="Print" href="@Url.Action("PrintProducts", "Controller", new { model = @Model })"></a>

 @*some tag*@   

但这种方式也行不通。

我使用并更改了这样的操作: 第一个动作:TempData

public IActionResult ShowProducts(int side, MyViewModel myViewModel)
{
    ViewBag.side = side;

    if (side == 0)
    {
        List<Product> products =  ShowAllProducts();
        TempData["MyModel"] = products;

        return View(products);
    }

    List<Product> products2 = FilterProducts(myViewModel);
    TempData["MyModel"] = products2;

    return View(products2 );
}

第二个动作是:

public IActionResult PrintProducts()
{
    List<Product> model= TempData["MyModel"] as List<Product>;
    return View(model);
}

但这样一来,第一个视图根本没有加载!我的状态代码为 500。

有什么方法可以解决这个问题吗?

C# HTML ASP.NET-Core 参数传递 模型绑定

评论

0赞 D A 10/26/2023
这样想并发送 3000 条记录作为参数是错误的。我不知道为什么在 UI 中需要 3000。没有人能看到它们。通常,使用分页或无限滚动或其他机制,这些机制将仅带来 UI 中所需的内容,而不是整个 products 表。
0赞 NedaM 10/26/2023
不幸的是,在这种情况下,需要发送所有记录才能查看。
0赞 user16606026 10/26/2023
500 表示某种例外。可以使用调试器查看是否引发了任何异常,并查看详细信息。这没什么可做的,而且有很多可能的理由要考虑,如果我们只知道 500 次发生的话。
0赞 Pete 10/26/2023
您可以缓存模型或将其放入会话变量中
0赞 NedaM 10/27/2023
@Pete 请解释一下是怎么做到的?谢谢。

答:

0赞 Bas Visscher 10/26/2023 #1

分页

通常,如果要显示大量数据,则可以使用分页。这实质上是将数据划分为多个称为页面的记录块。现在,如果你想在一个页面上显示所有数据,你可以在水下多次调用GET来获取你想要的所有数据。这样可以减少单个调用中的数据量。它还使事情更具可扩展性。

滤波

使用筛选,因此用户可以根据某些条件进行筛选。例如,搜索框。这将允许用户输入名称,并且您仅返回符合这些条件的项目。

订购

如果要对数据进行分页,还需要确保按特定顺序获取数据。如果每次调用的数据都是随机顺序的,则每次提取页面时,页面将包含不同的项目。它还允许用户按不同的属性进行排序。

这是我如何做到这一点的,它还包含过滤和排序。

[HttpGet]
[Route("GetAll")]
virtual public async Task<ActionResult<DbItem[]>> GetAll(string? filter, string? order, int? pageNo, int? pageSize)
{
    IQueryable<DbItem> query = _context.Set<DbItem>();

    // Apply filters to the query (you need to implement your filter logic)
    if (!string.IsNullOrEmpty(filter))
    {
        //Example of how to filter by title
        query = query.Where(a=>a.Title.Contains(filter));
    }

    // Apply ordering to the query if orderBy is provided
    if (!string.IsNullOrEmpty(order))
    {
        // Exmaple where order contains your property name
        query.OrderBy(e => EF.Property<DbItem>(e, order));
    }

    // Ensure the pagesize is something reasonable
    pageSize ??= 30;
    if (pageSize < 1 || pageSize > 30)
        pageSize = 30;

    // Ensure the page is something reasonable
    pageNo ??= 0;
    if (pageNo < 0)
        pageNo = 0;

    // Apply paging to the query
    int skip = pageNo.Value * pageSize.Value;
    query = query.Skip(skip).Take(pageSize.Value);

    // Execute the query and return the items
    var result = await query.ToListAsync();
    return Ok(result);
}

如何显示这一点

在 HTML 方面,根据您想要的用户体验,有不同的解决方案。您在互联网上经常看到的一些选项:

  • 在页面底部添加分页器:https://getbootstrap.com/docs/4.0/components/pagination/
  • 使用无尽的滚动条,这就是 Instagram、TikTok 等应用程序。
  • 使用一个表,当您滚动到底部时,该表会获取新数据。
  • 由于您使用的是 ASP 作为前端,因此您可能希望使用 AJAX 获取更多数据,并使用 jQuery 将其附加到页面中。

更多信息

Microsoft文档有一个很好的解释:https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/sort-filter-page?view=aspnetcore-7.0

评论

0赞 NedaM 10/26/2023
感谢您的解释,但我在处理 3000 条记录时没有问题,我在将列表模型发送到另一个操作:)时遇到了问题
0赞 NedaM 10/26/2023
我想你已经回答了另一个问题!!
0赞 Brando Zhang 10/27/2023 #2

默认情况下,tempdata 的提供程序是基于 cookie 的。大多数 Web 客户端(如 Web 浏览器)对每个 Cookie 的最大大小和 Cookie 总数实施限制。使用 Cookie TempData 提供程序时,请验证应用不会超过这些限制。考虑数据的总大小。考虑由于加密和分块而导致的 Cookie 大小增加。

因此,我们不建议您在临时数据中存储 3000 条记录,一种可能的方法是存储记录 ID,然后在另一种方法中使用该 ID 查询数据。

另一种方法是将数据存储在会话、内存缓存或 redis 缓存中。

有关 tempdata 工作原理和选择要存储缓存的存储的更多详细信息,您可以参考本文