【问题标题】:How to put one or many LINQ Lambda return records to List ?! C#如何将一个或多个 LINQ Lambda 返回记录放到 List 中?! C#
【发布时间】:2017-10-18 14:55:09
【问题描述】:

这个我的代码和这个动作中的每一行都会做一些事情并从数据库中检索一些记录,让我举一个关于这个动作的例子,这个动作将显示 Ordre 和该 ordre 下的产品,这意味着 Ordre (1212 ) 可能有 1 个产品或多个产品,但我的代码只显示该订单的一个记录,而不是所有记录,所以我的问题是如何将此操作的返回记录列出?还是我应该做点别的!谁能指引我正确的方向?谢谢

控制器中的代码:

public ActionResult OrdreOpenDetails(string id)
{
    DataContext data_2 = new DataContext();
    Ordre_Open_Details_VM oodvm = new Ordre_Open_Details_VM();



    oodvm.SalesLine = data_2.Sales_Line.FirstOrDefault(n => n.Document_No_ == id);
    oodvm.SalesHeader = data_2.Sales_Header.FirstOrDefault(m => m.No_ == oodvm.SalesLine.Document_No_);
    oodvm.SalesPersonPurchasers = data_2.Salesperson_Purchasers.FirstOrDefault(h=>h.Code == oodvm.SalesHeader.Salesperson_Code);
    oodvm.SalesCommentLine = data_2.Sales_Comment_Line.FirstOrDefault(z => z.No_ == oodvm.SalesLine.Document_No_);
    oodvm.PurchaseLine = data_2.Purchase_Line.FirstOrDefault(t=>t.Document_No_ == oodvm.SalesLine.Købsordrenr_);



    return View(oodvm);
} 

我的 ViewModel 类:

  public class Ordre_Open_Details_VM
    {
        public Sales_Header SalesHeader { get; set; }
        public Sales_Line SalesLine { get; set; }
        public Purchase_Line PurchaseLine { get; set; }
        public Salesperson_Purchasers SalesPersonPurchasers { get; set; }
        public Sales_Comment_Line SalesCommentLine { get; set; }
    }

视图中的代码:

@model DBhandling.Ordre_Open_Details_VM


<h2>OrdreOpenDetails</h2>

<div class="content">
    <div class="container-fluid">
        <div class="row">
            <div class="col-lg-4 col-md-5">
                <div class="card">
                    <div class="card-header" data-background-color="purple">
                        <h4 class="title">Detaljer</h4>
                        @*<p class="category">Detaljer <span>»</span> Order nr <span>»</span> @Model.SalesInvoiceHeader.Order_No_</p>*@
                    </div>
                    <div class="card-content">
                        <form>

                            <div class="row">
                                <div class="col-md-6">
                                    <div class="form-group label-floating">
                                        <label>Order nr.</label>
                                        <input type="text" class="form-control border-input" disabled value="@Model.SalesHeader.No_">
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <div class="form-group label-floating">
                                        <label>vare nummer</label>
                                        <input type="text" class="form-control border-input" disabled value="@Model.SalesLine.No_">
                                    </div>
                                </div>
                            </div>
                            <div class="row">
                                <div class="col-md-6">
                                    <div class="form-group label-floating">
                                        <label>Forventet levering</label>
                                        <input type="datetime" class="form-control border-input" disabled value="@Model.SalesLine.Planned_Delivery_Date">
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <div class="form-group label-floating">
                                        <label>Forventet levering Direkte</label>
                                        <input type="datetime" class="form-control border-input" disabled value="@(Model.PurchaseLine != null ? Model.PurchaseLine.Planned_Receipt_Date :(DateTime?)null )">
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <div class="form-group label-floating">
                                        <label>Sales Person</label>
                                        <input type="text" class="form-control border-input" disabled value="@Model.SalesPersonPurchasers.Name">
                                    </div>
                                </div>

                            </div>
                            <div class="row">
                                <div class="col-md-12">
                                    <div class="form-group label-floating">
                                        <label>Comment</label>
                                        <input type="text" class="form-control border-input" disabled value="@(Model.SalesCommentLine != null ? Model.SalesCommentLine.Comment : "No Comment")">
                                    </div>
                                </div>
                            </div>


                            <div class="clearfix"></div>
                        </form>
                    </div>


                </div>

            </div>
        </div>
    </div>
</div>

【问题讨论】:

  • 您是否尝试过使用SelectMany
  • @code4life 请你举一个我的代码的例子! :)
  • 我认为最好让您的 Ordre_Open_Details_VM 类属性成为每个对应对象的列表。这样,您的 oodvm 实例可以使用 SelectMany Linq 方法填充。在这种情况下,oodvm 将代表多个订单,每个属性的索引代表一个唯一的订单条目。然后你可以随心所欲地遍历这些
  • 代码中的哪一行是实际的命令?您的视图模型只有单个项目,并且需要一个订单列表,然后您的代码需要使用 Where 和 ToList 调用订单。然后你会在你的视图中迭代它......
  • @klabranche this to lines 是关于 ordres 的,先生,如果可能的话,最好用我的代码举个例子,而不是我可以了解更多信息:) - oodvm.SalesLine = data_2。 Sales_Line.FirstOrDefault(n => n.Document_No_ == id); oodvm.SalesHeader = data_2.Sales_Header.FirstOrDefault(m => m.No_ == oodvm.SalesLine.Document_No_);

标签: c# linq lambda


【解决方案1】:

编辑:我看到您的 LINQ 条件是基于在 SalesLine 分配中设置的 ID 值? (m =&gt; m.No_ == oodvm.SalesLine.Document_No_) 这不是一个很聪明的做法,把这个逻辑改成根据数据本身的ID来选择订单,而不是根据你之前检索到的,否则我描述的方法将不起作用。我不知道您的数据是如何设置的,所以我将在 SelectMany 函数调用中留下“条件”。

您可以将视图模型类更改为包含每个对象的列表,而不仅仅是一个实例

public class Ordre_Open_Details_VM
{
    public List<Sales_Header> SalesHeader { get; set; }
    public List<Sales_Line> SalesLine { get; set; }
    public List<Purchase_Line> PurchaseLine { get; set; }
    public List<Salesperson_Purchasers> SalesPersonPurchasers { get; set; }
    public List<Sales_Comment_Line> SalesCommentLine { get; set; }
}

然后你可以利用 SelectMany Linq 方法来检索所有满足你条件的订单。

oodvm.SalesLine = data_2.Sales_Line.SelectMany(condition);
oodvm.SalesHeader = data_2.Sales_Header.SelectMany(conditon);
oodvm.SalesPersonPurchasers = data_2.Salesperson_Purchasers.SelectMany(condition);
oodvm.SalesCommentLine = data_2.Sales_Comment_Line.SelectMany(condtion);
oodvm.PurchaseLine = data_2.Purchase_Line.SelectMany(condition);

这样设置,oodvm 的属性会包含多个订单,每个索引对应一个条目。

所以

oodvm.SalesLine[0]
oodvm.SalesHeader[0]
oodvm.SalesPersonPurchasers[0]
//...

将代表您想要的第一个订单。您可以根据需要使用它进行迭代。

【讨论】:

  • 我改变了一些东西,但出现了几个错误:对于这一行 oodvm.SalesLine = data_2.Sales_Line.SelectMany(n => n.Document_No_ == id);而这一行 data_2.Sales_Header.SelectMany(m => m.No_ == oodvm.SalesLine.**Document_No_)**;这行 oodvm.SalesPersonPurchasers = data_2.Salesperson_Purchasers.SelectMany(h => h.Code == oodvm.SalesHeader.**Salesperson_Code**);这行 oodvm.SalesCommentLine = data_2.Sales_Comment_Line.SelectMany(z => z.No_ == oodvm.SalesLine.**Document_No_**);
  • @ManDown 阅读我的编辑,您不应该根据已检索的内容检索数据,您需要根据 data_2 对象中的内容更改您使用的条件。
  • 我所有的条件都基于 ID,我必须将 ID 从 SaleLine 加入到 SaleHeader ID,因为 Saleheader 中的 ID 在 SaleLine 中不起作用,这就是我这样做的原因,但你会看到我的条件吗在 dat 上编辑,所以我知道这里是错误的。
  • @ManDown 如果您的联接基于 ID,那么您的 data_2 应该已经反映了这一点。在您的条件下利用它来发挥您的优势。
【解决方案2】:

您的视图模型只有一个实体用于您的订单 (Sales_Line)。你需要把它列成一个列表。

  public class Ordre_Open_Details_VM
    {
        public Sales_Header SalesHeader { get; set; }
        public List<Sales_Line> SalesLine { get; set; }
        public Purchase_Line PurchaseLine { get; set; }
        public Salesperson_Purchasers SalesPersonPurchasers { get; set; }
        public Sales_Comment_Line SalesCommentLine { get; set; }
    }

您用于填充视图模型的代码仅调用找到的第一项,因为您使用的是FirstOrDefault

要返回许多 SalesLines,请改用 WhereToList

oodvm.SalesLine = data_2.Sales_Line.Where(n => n.Document_No_ == id).ToList();

然后,您的视图将需要使用 razor 语法遍历列表,例如:

@foreach(var saleLine in Model.SalesLine)
{
  <div>@saleLine.PropertyXYZ</div>

}

作为奖励,您可以考虑更改代码以更高效地调用数据。您的代码按原样调用了数据库五次:

oodvm.SalesLine = data_2.Sales_Line.SelectMany(n => n.Document_No_ == id);
oodvm.SalesHeader = data_2.Sales_Header.SelectMany(m => m.No_ == oodvm.SalesLine.Document_No_);
oodvm.SalesPersonPurchasers = data_2.Salesperson_Purchasers.SelectMany(h=>h.Code == oodvm.SalesHeader.Salesperson_Code);
oodvm.SalesCommentLine = data_2.Sales_Comment_Line.SelectMany(z => z.No_ == oodvm.SalesLine.Document_No_);
oodvm.PurchaseLine = data_2.Purchase_Line.SelectMany(t=>t.Document_No_ == oodvm.SalesLine.Købsordrenr_);

每一行都在告诉 EF 在另一个调用中返回数据库,其中包含上一次调用的受限信息。在这种情况下,您可以创建一个实际上将在一次调用中执行此操作的查询。下面是将 SalesLine 调用和 SalesHeader 调用合并为一个数据库调用的示例。

oodvm.SalesLine = data_2.Sales_Line.FirstOrDefault(n => n.Document_No_ == id);
    oodvm.SalesHeader = data_2.Sales_Header.FirstOrDefault(m => m.No_ == oodvm.SalesLine.Document_No_);

更改为:

oodvm.SalesLine = data_2.Sales_Line.Include(n=>n.SalesHeader).Where(n=> n.Document_No_ == id).ToList();

由于 SalesLine 与 SalesHeader 相关,EF 知道如何根据定义的关系检索它。

上面的例子使用了一种叫做eager loading的技术。我用Include 操作告诉EF 一起获取相关的SalesHeader 信息。在正常的 SQL 语法中是这样的:

    select * from SalesLine 
    Inner Join SalesHeader on SalesHeader.Document_No_ = SalesLine.Document_No_ 
where SalesLine.Document_No_ = id

实体框架也可以lazy load。我通常会回避延迟加载,因此我的解决方案是使用急切加载。

现在oodvm.SalesLine 也将拥有与 SalesLine 关联的 SalesHeader,并且可以像 oodvm.SalesLine[0].SalesHeader 一样访问。

在上述情况下,SalesHeader 将为每个 SalesLine 复制,就像在 EF 代表您执行的普通 SQL 中一样。如果您不想在视图模型中出现重复信息,则必须考虑在 EF 中使用 Projection 将查询结果转换为视图模型的单个 SalesHeader 项,或者您可以在代码中将 SalesHeader 设置为第一个您的 SalesLines 列表中的项目,或者您可以在 Razor 中循环上方的标题部分中执行相同的操作。

实际操作示例:

oodvm.SalesHeader = oodvm.SalesLine[0].SalesHeader;

Razor 中的示例:

<div>
<p>Sales Header</p>
<span>@Model.SalesLine[0].SalesHeader.Property</span>
...
@foreach...

或者,如果您在操作中填充了 SalesHeader...

<div>
<p>Sales Header</p>
<span>@Model.SalesHeader.Property</span>
...
@foreach...

使用projection,您可以编写一个包含所有上述所需项目的查询,并将其投影到您的视图模型对象中。它可能看起来像:

    oodvm = data_2.Sales_Line.Include(n=>n.SalesHeader)
.Where(n=> n.Document_No_ == id)
.Select(n=> new Ordre_Open_Details_VM {
      Sales_Header = n.SalesHeader.FirstOrDefault(),
      SalesLine = n
    }).ToList();

上面的行只是说明你会做什么。查找投影以获得更多指导。

【讨论】:

  • tnx 对于所有这些,让我试试 :) 只是分钟
  • 我试了这两个,我在 n => n.SalesHeader 下得到了红线:oodvm.SalesLine = data_2.Sales_Line.Include(n => n.SalesHeader).Where(n => n.Document_No_ == id).ToList(); oodvm.SalesPersonPurchasers = data_2.Salesperson_Purchasers.FirstOrDefault(h=>h.Code == oodvm.SalesHeader.Salesperson_Code); oodvm.SalesCommentLine = data_2.Sales_Comment_Line.FirstOrDefault(z => z.No_ == oodvm.SalesLine.Document_No_); oodvm.PurchaseLine = data_2.Purchase_Line.FirstOrDefault(t=>t.Document_No_ == oodvm.SalesLine.Købsordrenr_);
  • 我在 n.SalesHeader 下出现错误:oodvm = data_2.Sales_Line.Include(n => n.SalesHeader) .Where(n => n.Document_No_ == id) .Select(n => new Ordre_Open_Details_VM { Sales_Header = n.SalesHeader.FirstOrDefault(), SalesLine = n }).ToList();
  • 如果 Include 行有红线,请确保在控制器顶部有以下 using 语句: using System.Data.Entity;
  • 通过 cmets 和/或聊天解决此问题并不容易。我对您的最佳建议是将我所展示的内容作为说明性内容,阅读一般的 EF,急切加载,投影等......然后创建一个较小的代码示例,用于说只是加载一个列表带有销售标题的订单。一旦你把它记下来,剩下的你可以慢慢添加回来...... :-)
猜你喜欢
  • 2020-02-08
  • 1970-01-01
  • 1970-01-01
  • 2011-02-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2015-05-13
  • 1970-01-01
相关资源
最近更新 更多