【问题标题】:In MVC, pass complex query and view model to session?在 MVC 中,将复杂的查询和视图模型传递给会话?
【发布时间】:2015-11-14 15:48:42
【问题描述】:

我有一个视图模型:

 public class UserCollectionView
    {
        public CardCollection CardCollections { get; set; }
        public Card Cards { get; set; }    
    }

我有一个列表视图控制器:

public ActionResult ViewCollection(int? page)
        {
            var userid = (int)WebSecurity.CurrentUserId;
            var pageNumber = page ?? 1;
            int pageSize = 5;                
            ViewBag.OnePageOfCards = pageNumber;
            if (Session["CardCollection"] != null)
            {    
             var paging = Session["CardCollection"].ToString.();
             return View(paging.ToPagedList(pageNumber, pageSize));    
            }                                  
            var viewModel = from c in db.Cards
                            join j in db.CardCollections on c.CardID equals j.CardID
                            where (j.NumberofCopies > 0) && (j.UserID == userid)
                            orderby c.Title
                            select new UserCollectionView { Cards = c, CardCollections = j };

            Session["CardCollection"] = viewModel;
            return View(viewModel.ToPagedList(pageNumber, pageSize));

我正在尝试使用 PagedList 将分页添加到结果中。当我不使用从单个视图中返回来自 2 个数据库的数据的查询时,我已经能够做到这一点。 As shown here

我的最终结果如下所示:

     Cards.SeveralColumns   CardCollections.ColumnA   CardCollections.ColumnB 
Row 1 Data from Cards Table  A from CardCollections    B from CardCollections
Row 2 Data from Cards Table  A from CardCollections    B from CardCollections
Row 3 Data from Cards Table  A from CardCollections    B from CardCollections

等等...我收到一个错误 The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. 我已经尝试过各种 SQL 语句,但无法使其适合我的视图模型。在 SQL Management Studio 中,这会返回正确的结果 Select * from Cards Inner Join CardCollections On Cards.CardID = CardCollections.CardID where CardCollections.UserID = 1 and CardCollections.NumberofCopies > 0;

我需要一种在会话中传递查询的方法,以便分页正常运行。任何建议表示赞赏。 :)

【问题讨论】:

  • 这个错误是在控制器中还是在渲染视图时出现?
  • 在最初呈现视图后选择第二页时会发生这种情况。错误发生在控制器中。它在 CardCollection 会话中传递了很多东西,但结果视图状态为 The operation cannot be completed because the DbContext has been disposed.

标签: mysql asp.net-mvc asp.net-mvc-4 session pagination


【解决方案1】:

简短的回答是,你不能。模型需要是内容的快照,因此您不能跨边界传递打开的查询(作为会话的移交或直接传递给客户端)。

您所看到的是上下文在其初始使用之外的处置(您在其中组装var viewmodel)。

话虽如此,如果查询数据是一项昂贵的操作,您可以缓存结果(以节省开销)。基本上,您会将整个集合(或至少集合的一个大子集)存储在会话/内存缓存中(然后可以将其操作到分页列表中)。大意是:

public ActionResult ViewCollection(int? page)
{
  var userId = (int) WebSecurity.CurrentUserId;
  var pageNumber = page ?? 1;
  var pageSize = 5;

  ViewBag.OnePageOfCards = pageNumber;

  var cacheKey = String.Format("ViewCollection[{0}]", userId);
  var entities = GetOrCreateCacheItem<IEnumerable<UserCollectionView>>(cacheKey, () => {
    var query = (from c in db.Cards
                 join j in db.CardCollections on c.CardID equals j.CardID
                 where (j.NumberofCopies > 0) && (j.UserID == userid)
                 orderby c.Title
                 select new UserCollectionView { Cards = c, CardCollections = j }
                )
                .ToList(); // Force fetch from Db so we can cache
  });

  return View(entities.ToPagedList(pageNumber, pageSize));
}

// To give an example of a cache provider; Feel free to change this,
// abstract it out, etc.
private T GetOrCreateCacheItem<T>(string cacheKey, Func<T> getItem)
{
  T cacheItem = MemoryCache.Default.Get(cacheKey) as T;
  if (cacheItem == null)
  {
    cacheItem = getItem();
    var cacheExpiry = DateTime.Now.AddMinutes(5);
    MemoryCache.Default.Add(cacheKey, cacheItem, cacheExpiry);
  }
  return cacheItem;
}

【讨论】:

    【解决方案2】:

    事实证明,我根本不需要传递查询。如果我让它运行,它可以在没有会话的情况下正常工作。我不太确定为什么会这样,但我的搜索查询必须通过。也许是因为我使用视图模型来执行查询。如果我发现任何东西,我会进行实验并发布。目前的工作代码是:

    public ActionResult ViewCollection(int? page)
            {
                var userid = (int)WebSecurity.CurrentUserId;
                var pageNumber = page ?? 1;
                int pageSize = 5;
    
                ViewBag.OnePageOfCards = pageNumber;
                ViewBag.Rarity_ID = new SelectList(db.Rarities, "RarityID", "Title");
                ViewBag.MainType_ID = new SelectList(db.MainTypes, "MainTypeID", "Title");
                ViewBag.CardSet_ID = new SelectList(db.CardSets, "CardSetID", "Title");
                ViewBag.SubType_ID = new SelectList(db.SubTypes, "SubTypeID", "Title");
                var viewModel = from c in db.Cards
                                join j in db.CardCollections on c.CardID equals j.CardID
                                where (j.NumberofCopies > 0) && (j.UserID == userid)
                                orderby c.Title
                                select new UserCollectionView { Cards = c, CardCollections = j };
                return View(viewModel.ToPagedList(pageNumber, pageSize));
    

    【讨论】:

    • 您只是在每次调用操作时重新获取数据。 ToPagedList 很可能是执行查询(所以现在您有实时数据,而不是 IQueryable),然后将其传递(作为集合)到您的视图模型,组装。
    • 我的搜索使用 ToPagedList var CardList = db.Cards.SqlQuery(SQLstatement).ToList(); return View(CardList.ToPagedList(pageNumber, pageSize)); 但我必须在会话中传递查询,否则它会崩溃,因为它会尝试重新运行构建没有任何值的查询的整个搜索。
    猜你喜欢
    • 1970-01-01
    • 2015-01-28
    • 2012-08-10
    • 2015-10-19
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    相关资源
    最近更新 更多