LINQ左连接仅适用于ActionResult

时间:2013-06-11 16:55:59

标签: asp.net-mvc linq viewmodel actionresult

我正在努力加快MVC,linq,razor等的速度。一些事情正在发挥作用,而其他一些事情我只是打死了那些让我感到沮丧的事情。这是我无法解决的第一个问题。在这里提出这个问题之前,我已经研究过每一条线索,这是我的第一个,所以请放轻松。我确定答案就在我的面前,但我看不到它。我可以输入14页我尝试过的东西,但是我试图保持这种简洁和重点。我已经完全破坏了我的代码,所以我从内存中提取了大部分内容,因此,它与标点符号错误无关。我道歉错误代码并不准确,因为我也从内存中提取错误代码。

我在ActionResult中有这个左连接linq查询:

public ActionResult Index()
{
    var orders = from o in db.Orders
    join u in db.Users on o.UserId equals u.Id into ou
    where o.UserId == uId
    from o in ou.DefaultIfEmpty()
    select o;

    Return View(orders.ToList());
}

在Index.cshtml中,我通过执行以下操作调用结果:

@foreach (var item in Model.Orders) {
@item.User.Name //(joined Users table)
@item.OrderNumber //(Orders table)

到目前为止,这么好。但是,我想在索引页面上显示的不仅仅是这个列表。所以,我可以说,我需要一个ViewModel来在同一页面上显示其他几个数据(OrdersTotal等)。但是,当我在我的模型中将我的linq查询粘贴在:

public  List<Order> GetOrders()
    {

        var orders = from o in db.Orders
    join u in db.Users on o.UserId equals u.Id into ou
    where o.UserId == uId
    from o in ou.DefaultIfEmpty()
    select o;

        return orders.ToList();
    }

它无法识别已加入的Users表,这意味着它不知道cshtml中的item.User.Name。然后我开始一个潘多拉的实验盒,我无法工作,主要是在select语句中:

select New  //this complains about anonymous type

select New Order(o.OrderNumber,u.Id)  //I can't remember the error here, but red squiggly lines

select New Order { OrderNumber = o.OrderNumber, UserName = u.Name}  //VS complains about not referencing the Users table, it wants to put a UserName field or property stub in my model, which if I do that, then it errors in the cshtml again as I'm guessing because I don't have a UserName in my Orders table?

有几次,我得到了上面的查询,但是在尝试再次访问cshtml中的Users表时会引发异常。我的viewmodel控制器如下所示:

public ActionResult Index()
{

var ordersummary = new OrdersSummary();
var viewModel = new OrderSummary
  {
    Orders = ordersummary.GetOrders(),
    OrdersTotal = ordersummary.GetOrdersTotal(),
  };

return View(viewModel);
}

我的viewModel模型如下所示:

public class OrderSummary
    {
        public List<Order> Orders { get; set; }
        public decimal OrdersTotal { get; set; }
        public virtual User Users { get; set; }
    {

我的订单模型基本上遍历数据库中的不同列,具有与上面相同的公共虚拟用户用户,这些工作正常,从ActionResult中提取列表。

public class Order
    {

        public int Id { get; internal set; }
        public int UserId { get; set; }
        public int OrderNumber { get; set; }
        ...
        ...
        public virtual User Users { get; set; }
    }

我不禁想到我在我的模型或控制器中做了一些根本错误的事情,而不是在linq语句的语法中。非常感谢任何帮助。

更新:我现在已经完成了一些教程,我基本上试图在这里模仿这个页面(从ViewModels开始,尽管我的OrderSummary模型来自上面的ShoppingCart GetCartItems等):

http://www.asp.net/mvc/tutorials/mvc-music-store/mvc-music-store-part-8

但是,上面的教程不需要sql join。想象一下票务系统,你有门票(订单)和技术人员(用户),你正在尝试为技术人员分配门票(每张门票一张技术,但有些门票可能没有分配给他们的技术,但也称为空)以及我是什么我试图创建的是概览部分,您可以在其中查看所有票证和分配给表格中的票据的技术,然后进一步统计数据,例如Total#of Tickets,或者最终可能是TechA拥有x#门票。所以,我需要订单数据库中的所有信息,只需要来自用户数据库的名称,然后就可以在索引页面上引入多条信息。

我注意到一些教程使用额外的表来加入ID。所以,在我的情况下,一个额外的表只有OrderId和UserId。这可能是一种更好的联接方式(因缺乏正确的术语而“加入”)?

2 个答案:

答案 0 :(得分:0)

如果你想使用匿名类型,你可以返回IEnumerable<dynamic>并像以前一样工作;

public IEnumerable<dynamic> GetOrders()
{
    var orders = from order in db.Orders
                 join u in db.Users on order.UserId equals u.Id into ou
                 where order.UserId == uId
                 from user in ou.DefaultIfEmpty()
                 select new { order, user };

    return orders.ToList();
}

var item = GetOrders().First();
item.order.Number        // (Orders table)
item.user.Name           // (joined Users table)

答案 1 :(得分:0)

所以,完整的答案如下:

我在评论中提到的cshtml怪异是由于:

'object' does not contain a definition for 'X'

  

匿名对象由编译器作为内部对象发出。剃刀   视图会自动编译成单独的程序集   ASP.NET运行时。这意味着您无法访问任何匿名用户   控制器中生成的对象。

所以,这很糟糕,它不喜欢上面的匿名查询,即使我在调试时可以看到来自两个表的信息(当我将鼠标悬停在我的cshtml中的项目上时)。无论如何,我仍然使用Joachim建议的“动态”,尽管这里有人说这可能不是最好的做事方式。但是,我不得不将我的linq查询更改为以下内容以消除匿名:

var orders = from order in db.Orders
             join u in db.Users on order.UserId equals u.Id into ou
             where order.UserId == uId
             from user in ou.DefaultIfEmpty()
             select new OrderSummary 
               { 
               OrderNumber = order.OrderNumer, 
               UserName = user.Name
               };

这方面的诀窍是(对我来说无论如何):

  1. 在我“选择”“新”“订单”(以及其他一些事情)之前,而不是“OrderSummary”。我从来没有真正清楚这个值应该是“选择新的ViewModel名称,或者我想在其他情况下只是模型名称”。
  2. 在括号内,“OrderNumber =”可以命名为任何名称。但是你必须在你的ViewModel中创建一个属性存根,在我的例子中是OrderSummary。 (VS将为您提供创建属性存根的下拉选项。)我认为它是从我的ViewModel中定义的订单列表中提取此信息,但我想仍然需要属性存根。我也希望不必定义我的所有订单列(即在SQL中查找订单。*),但我想这是唯一的选择。
  3. 那么在我的Index.cshtml中,我做的与原版类似,除了在我定义它们时调用上面的值:

    @foreach (var item in Model.Orders) {
    @item.UserName //(joined Users table) *This is the only line that changed.
    @item.OrderNumber //(Orders table)}
    

    我的控制器从未改变过所有这些......我认为这就是它。我希望这可以节省别人在将来尝试设置ViewModel的麻烦。活到老,学到老。我的编程术语相当薄弱,所以如果我使用了任何错误的措辞,我会道歉。祝你好运。