【问题标题】:Write this SQL query to Entity Framework lambda expression or other way将此 SQL 查询写入实体框架 lambda 表达式或其他方式
【发布时间】:2019-02-27 04:22:07
【问题描述】:

db.DbEnquiryModules - 如何将此查询编写为 lambda 表达式或 linq?

SELECT  
    tenq.EnquiryID
    ,tenq.EnquiryNo
    ,tenq.CompanyID
    ,tenq.EnquiryDate
    ,tenq.ClientID
    ,tenq.Address
    ,tenq.ContactPerson
    ,tenq.Email
    ,tenq.Mobile
    ,tenq.Landline
    ,tenq.SourceID
    ,tenq.PriorityID
    ,tenq.AreaID
    ,tenq.status
    ,tenq.Remark
    ,tenq.IsDeleted
    ,tenq.CreatedDate
    ,tenq.CreatedBy
    ,tenq.ModifiedDate
    ,tenq.ModifiedBy
    ,Y.FollowupDate AS LastFollowup
    ,Y.NextFollowup AS NextFollowup
    ,srno2
INTO
    #tmp 
FROM
    tblEnquiryModule tenq
LEFT JOIN 
   (SELECT 
        ROW_NUMBER() OVER (PARTITION BY EnquiryModuleID ORDER BY FollowupId DESC) SRno2,
        * 
    FROM
        tblFollowup) Y ON Y.EnquiryModuleID = EnquiryID
                       AND Y.srno2 <=2  ----------Last followUp
WHERE
    tenq.CompanyID = @companyid


--

DELETE a
FROM #tmp a
JOIN #tmp b ON a.EnquiryID = b.EnquiryID
            AND b.srno2 = 2
WHERE a.srno2 = 1 

SELECT * FROM #tmp 

我有两个带有查询的表,它的 followup.above 查询返回查询及其最后跟进日期(如果存在)和下一个跟进日期

我的实体

public class DTOEnquiryModule
{   [Key]
    public int EnquiryID { get; set; }
    public string EnquiryNo { get; set; }
    public int CompanyID { get; set; }
    public DateTime? EnquiryDate { get; set; }
    public string Mobile { get; set; }
    public string Landline { get; set; }
    public string status { get; set; }
    public int? ModifiedBy { get; set; }}  

public class DTOFollowup
{
    [Key]
    public int FollowupId { get; set; }
    public int EnquiryModuleID { get; set; }
    [ForeignKey("EnquiryModuleID")]
    public DTOEnquiryModule EnquiryModule { get; set; }
    public DateTime FollowupDate { get; set; }
    public string FollowupRemark { get; set; }
    public DateTime? NextFollowup { get; set; }
    public string NextFollowupRemark { get; set; }
}

查询表

|EnquiryID|EnquiryNo|EnquiryDate            |status 
|1        |EN1      |2019-02-19 00:00:00.000|ongoing
|2        |EN2      |2019-02-20 00:00:00.000|ongoing
|3        |EN3      |2019-02-23 00:00:00.000|ongoing

跟进表

FollowupId|EnquiryModuleID|FollowupDate           |FollowupRemark|NextFollowup 
1         |1              |2019-02-20 00:00:00.000|NA            |NULL
2         |2              |2019-02-21 00:00:00.000|NA            |2019-02-23 00:00:00.000
3         |2              |2019-02-23 00:00:00.000|NA            |NULL
4         |3              |2019-02-24 00:00:00.000|NA            |2019-02-26 00:00:00.000
5         |3              |2019-02-26 00:00:00.000|NA            |2019-02-28 00:00:00.000
6         |3              |2019-02-28 00:00:00.000|NA            |NULL

我想要下面的结果表

|EnquiryID|EnquiryNo|EnquiryDate            |status |NextFollowup           |LastFollowup
|1        |EN1      |2019-02-19 00:00:00.000|ongoing|NULL                   |2019-02-20 00:00:00.000
|2        |EN2      |2019-02-20 00:00:00.000|ongoing|2019-02-23 00:00:00.000|2019-02-21 00:00:00.000
|3        |EN3      |2019-02-23 00:00:00.000|ongoing|2019-02-28 00:00:00.000|2019-02-26 00:00:00.000

每当我添加新的跟进时,需要更新以前的跟进详细信息以维护历史记录并通过查询 ID 获取最新的跟进。

我想显示最后一次跟进和下一次跟进日期的查询列表

【问题讨论】:

  • 如果您使用实体框架,请编辑您的问题并向我们展示您的类(相关部分),尤其是虚拟属性和键。用文字描述您的要求也会有所帮助(“给我所有的询问以及他们最后的跟进日期和......”)
  • Harald Coppoolse 请检查

标签: c# entity-framework linq linq-to-sql entity-framework-6


【解决方案1】:

所以你有EnquiriesFollowUps 的表。每个Enquiry 有零个或多个FollowUps,每个FollowUp 恰好属于一个`查询,使用外键:简单的一对多关系。

如果您关注entity framework code first conventions,,您将会有类似的课程:

class Enquiry
{
    public int Id {get; set; }
    public string EnquiryNo { get; set; }
    public DateTime? EnquiryDate { get; set; }
    public string status { get; set; }
    ...

    // every Enquiry has zero or more FollowUps (one-to-many)
    public virtual ICollection<FollowUp> FollowUps {get; set;}
}

class FollowUp
{
    public int Id {get; set; }
    public DateTime FollowupDate { get; set; }
    ...

    // every FollowUp belongs to exactly one Enquiry, using foreign key
    public int EnquiryId {get; set;}
    public virtual Enquiry Enquiry {get; set;}
}

为了完整性,DbContext:

class MyDbContext : DbContext
{
    public DbSet<Enquiry> Enquiries {get; set;}
    public DbSet<FollowUp> FollowUps {get; set;}
}

因为我遵循了约定,所以这就是实体框架检测表、表中的列以及表之间的关系所需要知道的全部内容。只有当你想要不同的标识符时,你才需要属性或流畅的 API。 其中重要的部分是我使用虚拟属性指定了一对多

在实体框架中,列由非虚拟属性表示;虚拟属性表示表之间的关系(一对多,多对多,...)

您的要求:“当我添加了新的跟进时,需要更新以前的跟进详细信息”。

我被加了?需要更新之前的跟进吗?也许你应该提高你的需求技能。

我认为您的意思如下:

要求向我提供所有查询的(某些属性),包括最新的 FollowUpDate 和最新但唯一的 FollowupDate(出于某种原因,您决定将其称为最后日期)。

如果 Inquiry 只有一个 Followup,我需要 EnquiryDate 和 FollowUpdate。如果 Inquiry 没有后续,我只想要 EnquiryDate。

因此,符合条件的 FollowUpdates 的集合是 EnquiryDate + 所有 FollowUpdates。按降序排列它们并取前两个。

var result = dbContext.Enquiries.Select(enquiry => new
{
    EnquiryId = enquiry.Id,
    EnquiryNo = enquiry.EnquiryNo,
    EnquiryDate = enquiry.EnquiryDate,
    Status = enquiry.Status,

    // For the followups: take the followUp dates as nullable DateTime
    // and add the EnquiryDate
    FollowUps = enquiry.FollowUps
        .Select(followUp => followUp.FollowUpdate)
        .Cast<DateTime?>()
        .Concat(new DateTime?[] {enquiry.EnquiryDate})

        // take the two newest ones; we don't want null values
        .Where(date => date != null)
        .OrderByDescending(date => date)
        .Take(2)
        .ToList(),
})

// move this to local process, so you can use FollowUps to get Next / Last
.AsEnumerable()
.Select(fetchedData => new
{
    EnquiryId = fetchedData.EnquiryId,
    EnquiryNo = fetchedData.EnquiryNo,
    EnquiryDate = fetchedData.EnquiryDate,
    Status = fetchedData.Status,

    // FollowUps are ordered in Descending order. FirstOrDefault is the newest!
    NextFollowUp = enquiry.FollowUps.FirstOrDefault(),
    LastFollowUp = enquiry.FollowUps.LastOrDefault(),
}

实体框架知道您的一对多关系。它将您对 ICollection 的使用转换为 GroupJoin

如果需要,您可以让您的数据库管理系统选择 NextFollowUp 和 LastFollowUp。传输的数据数量将相同,因此这不会加快您的处理速度。

有些人不喜欢使用virtual ICollection 来获取“与他们的跟进的询问”。您可以自己参加 GroupJoin:

result = dbContext.Enquiries.GroupJoin(dbContext.FollowUps,
    enquiry => enquiry.Id,           // from each enquiry take the primary key
    followUp => followUp.EnquiryId,  // from each followUp take the foreign key

    // result selection: use each enquiry with all its matching followUps to make a new
    (enquiry, followUpsOfThisEnquiry) => new
    {
        EnquiryId = enquiry.Id,
        ... etc.

保持数据库规范化

您决定在数据库中添加一个 DateTime 列 NextFollowUp。这不是一个好的选择。

Id | FollowUpDate | NextFollowUpDate
01 |  2019-02-13  |  2019-02-14
20 |  2020-02-29  |     null

在我看来,FollowUp [20] 是 FollowUp 1 的下一个 FollowUp。如果我更改 FollowUp [20] 的日期会发生什么:

Id | FollowUpDate | NextFollowUpDate
01 |  2019-02-13  |  2019-02-14
20 |  2019-02-14  |     null

这仍然正确吗? [20]突然不是[01]的下一个了吗?每当您更改日期时,您都必须检查所有 FollowUps 以查看它是否指向此 FollowUp。

那么下面的呢:

Id | FollowUpDate | NextFollowUpDate
04 |  2019-02-13  |  2019-02-14
05 |  2019-02-14  |     null
06 |  2019-02-14  |     null

[04] 的下一个是谁?

请记住,后续行动由其主键而非日期来标识。跟进的日期可能会改变。但是,这不会改变后续行动本身。

Id | FollowUpDate | NextFollowUpId
04 |  2019-02-13  |      05
05 |  2019-02-20  |      06
06 |  2019-02-14  |     null

在介绍之后,您可以安全地更改 FollowUp 的任何属性,当然除了它的主键。在您决定介绍“下一次跟进”的背景之前,您应该自己考虑一下它是什么:它是下一个日期吗?那你就不需要外键了,可以按日期时间排序

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多