在ASP.NET MVC Entitiy Framework中的内容页面中加载多组数据

时间:2016-05-04 18:10:34

标签: asp.net asp.net-mvc entity-framework

我需要在View页面中加载多个实体类型。我为此目的使用ViewModel。但是,我需要进行大约5-6个数据库调用来加载每组数据并将它们分配给ViewModel的相关属性。我想知道这是否是一种推荐的方法,因为它需要多个数据库调用。或者,我是否过度关注这个?这是我代码的快照:

    var model = new EntryListVM();

    string userid = "";
    if (ViewBag.CurrentUserId == null)
        userid = User.Identity.GetUserId();
    else
        userid = ViewBag.CurrentUserId;

    ViewBag.CurrentUserId = userid;

    //First database call
    model.DiscussionWall = db.DiscussionWalls.Find(wallId);

    //Second database call to learn if the current students has any entry
    model.DiscussionWall.DoesStudentHasEntry = db.Entries.Any(ent => ent.DiscussionWallId == wallId && ent.UserId == userid);
    model.PageIndex = pageIndex;

    //Third database call
    model.TeacherBadges = db.Badges.Where(b => b.CourseId == model.DiscussionWall.CourseId && b.IsSystemBadge == false && b.IsEnabled == true).ToList();

    //Fourth database call
    model.Reactions = db.Reactions.Where(re => re.CourseId == model.DiscussionWall.CourseId).ToList();

    int entryPageSize = Convert.ToInt32(ConfigurationManager.AppSettings["EntryPageSize"]);
    int firstChildSize = Convert.ToInt32(ConfigurationManager.AppSettings["FirstChildSize"]);

    List<ViewEntryRecord> entryviews = new List<ViewEntryRecord>();
    bool constrainedToGroup = false;
    if (!User.IsInRole("Instructor") && model.DiscussionWall.ConstrainedToGroups)
    {
        constrainedToGroup = true;
    }

    //Fifth database call USING VIEWS
    //I used views here because of paginating also to bring the first 
    //two descendants of every entry 
    entryviews = db.Database.SqlQuery<ViewEntryRecord>("DECLARE @return_value int;EXEC  @return_value = [dbo].[FetchMainEntries] @PageIndex = {0}, @PageSize = {1}, @DiscussionWallId = {2}, @ChildSize={3}, @UserId={4}, @ConstrainedToGroup={5};SELECT  'Return Value' = @return_value;", pageIndex, entryPageSize, wallId, firstChildSize, userid, constrainedToGroup).ToList();

    model.Entries = new List<Entry>();
    //THIS FUNCTION MAP entryviews to POCO classes
    model.Entries = ControllerUtility.ConvertQueryResultsToEntryList(entryviews);

    //Sixth database call
    var user = db.Users.Single(u => u.Id == userid);

    model.User = user;

我想知道这对初始页面加载是否负担过重?

我可以使用SQL-View一次读取所有数据,但我想我会得到一个太复杂的数据集来管理。

另一个选项可能是在页面加载(主数据)完成后使用Ajax加载其他结果。例如,我可以在加载页面后使用AJAX加载TeacherBadges

我想知道哪种策略更有效并推荐?是否存在特定策略可能更有用的特定情况?

谢谢!

2 个答案:

答案 0 :(得分:4)

这完全取决于您的场景 - 不同的场景有不同的处理方式。做一些性质相似的事情没有一种正确的方法。什么可能对我有用可能不适合你。曾经听过这样的说法:there are many ways to kill a cat?那肯定适用于编程。

我将根据我的想法回答。你的问题非常广泛而且不具体。

  

但是,我不确定这是否是推荐的方法   需要多次数据库调用。

有时您需要进行一次数据库调用来获取数据,有时您需要进行多次数据库调用才能获取数据。例如:

  • 地址的用户详细信息:一次呼叫用户和一次呼叫地址
  • 用户详细信息:一次通话
  

我正在使用ViewModel。

使用view models查看您的观点是一件好事。如果您想了解更多关于视图模型的内容,那么您可以阅读我给出的关于该主题的答案:

What is ViewModel in MVC?

当您拥有来自多个数据集的数据时,查看模型非常理想。视图模型还可用于显示来自一个数据集的数据,例如:

  • 显示多个地址的用户详细信息
  • 仅显示用户详细信息
  

我在单独的linq语句中读取控制器中的数据,并且   将它们分配给ViewModel的相关List属性。

我不会总是返回一个列表 - 这完全取决于你需要什么。

如果我有一个对象要返回,那么我将填充一个对象:

User user = userRepository.GetById(userId);

如果我有一个要返回的对象列表,那么我将返回一个对象列表:

List<User> users = userRepository.GetAll();

返回单个对象然后填充此对象的列表是没有用的:

List<User> user = userRepository.GetByUserId(userId).ToList();
  

第二个选项可能是使用SQL-View来读取所有数据   数据库调用,然后将它们正确映射到实体   控制器。

这与您的第一个问题类似,您在数据库级别返回数据的方式取决于您。它可以是stored proceduresviews。我个人更喜欢存储过程。我之前从未使用过视图。无论你选择什么,上面提到的存储库方法看起来都应该是一样的。

  

第三个选项可能是使用Ajax加载后的其他结果   页面加载(包含主数据)已完成。

如果您愿意,可以这样做。如果不是真的需要,我不会这样做。我尝试在页面加载时加载数据。我尝试在页面完全加载之前在屏幕上获取尽可能多的数据。有些时候我必须在页面加载后转到AJAX路由。加载页面后,我不得不进行AJAX调用来加载我的HTML表格。

如果你真的需要显示数据,那就这么做。你不需要任何奇特的方法来做到这一点。也许以后你需要更改屏幕数据,然后使用AJAX很酷。

  

我想知道哪种策略更有效并推荐?在那儿   特定策略可能更有用的特定情况?

我们假设您要显示用户列表。我们进行数据库调用并将列表返回给视图。如果我只返回一个列表,我通常不会使用视图模型:

public class UserController : Controller
{
     private IUserRepository userRepository;
     private IAddressRepository addressRepository;

     public UserController(IUserRepository userRepository, IAddressRepository addressRepository)
     {
          this.userRepository = userRepository;
          this.addressRepository = addressRepository;
     }

     public ActionResult Index()
     {
          List<User> users = userRepository.GetAll();

          return View(users);
     }
}

您的观点可能如下所示:

@model List<YourProject.Models.User>

@if (Model.Count > 0)
{
     foreach (var user in Model)
     {
          <div>@user.Name</div>
     }
}

如果您需要获取单个用户的详细信息和地址列表,那么我将使用视图模型,因为现在我需要显示来自多个数据集的数据。因此,用户视图模型可能如下所示:

public class UserViewModel
{
     public UserViewModel()
     {
          Addresses = new List<Address>();
     }

     public int Id { get; set; }

     public string Name { get; set; }

     public List<Address> Addresses { get; set; }
}

您的详细信息操作方法可能如下所示:

public ActionResult Details(int id)
{
     User user = userRepository.GetById(id);
     UserViewModel model = new UserViewModel();
     model.Name = user.Name;
     model.Addresses = addressRepository.GetByUserId(id);

     return View(model);
}

然后您需要在视图中显示用户详细信息和地址:

@model YourProject.ViewModels.UserViewModel

<div>First Name: @Model.Name</div>
<div>
     @if (Model.Addresses.Count > 0)
     {
          foreach (var address in Model.Address)
          {
               <div>@address.Line1</div>
               <div>@address.Line2</div>
               <div>@address.Line3</div>
               <div>@address.PostalCode</div>
          }
     }
</div>

我希望这会有所帮助。这可能是一个广泛的答案,但它可以指导你在正确的道路上。

答案 1 :(得分:1)

包含链接数据

对于链接数据,它很简单(你可能知道这种方式):

var users = context.Users.Include(user => user.Settings).ToList();

它会查询所有用户并为每个用户预加载设置。

对不同的数据集使用匿名类

以下是一个例子:

context.Users.Select(user => new 
{
    User = user,
    Settings = context.Settings
        .Where(setting => setting.UserId == user.Id)
        .ToList()
}).ToList();

您仍然需要选择主要查询集合(在这种情况下为用户),但这是一个选项。希望它有所帮助。