【问题标题】:How to combine related data from two related models using EF?如何使用 EF 组合来自两个相关模型的相关数据?
【发布时间】:2017-09-05 07:02:42
【问题描述】:

概念

我有两个以一对多关系相关的模型。第一个模型主要存储患者信息(PatReg)。第二个模型加入合作伙伴一起(PatPar)。 即(FileId=1 Sam,FileId=2 Victoria,FileId=3 jessica,FileId=4 monica)信息都存储在PatReg。为了说明 Sam 是 Victoria 和 Jessica 的合作伙伴,我以 PatPar 的方式加入了他们:

  FileId= 1 FileId=2
  FileId= 1 FileId=3

以下说明了这两种模型。

public class PatReg
    {
        public Int64 FileId { get; set; }
        [Required, Display(Name = "First Name")]
        public string FName { get; set; }
        [Required, Display(Name = "Middle Name")]
        public string MName { get; set; }
        [Required, Display(Name = "Last Name")]
        public string LName { get; set; }
        [Display(Name = "Full Name"), NotMapped]
        public string fullname
        {
            get { return FName + " " + MName + " " + LName; }
        }
        [Required, Display(Name = "Date of Birth")]
        [DataType(DataType.Date)]
        public DateTime Dob { get; set; }
        public ICollection<PatPar> PatPar { get; set; }
    }

    public class PatPar

    {
        [Key]
        public Int64 RecId { get; set; }
        [Display(Name = "Patient File Id"), Required]
        public Int64 FileId { set; get; }
        [Display(Name = "Partner File Id"), Required]
        public Int64 ParFileId { set; get; }
        [Display(Name = "Start Date"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true), Required]
        public DateTime SDate { set; get; }
        [Display(Name = "End Date"), DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime? EDate { set; get; }
    }

获取相关数据 我在我的项目中使用API controller,查询记录的方式如下,

    [HttpGet("{id}")]
    public async Task<IActionResult> GetPatReg([FromRoute] long id)
    {

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
         var patReg = await _context.PatReg.SingleOrDefaultAsync(m => m.FileId == id);     // here I get my Main Record
        var patRegPar = await _context.PatPar  // here I get related Records
            .Where(m => m.FileId == id)
            .ToListAsync();
        if (patReg == null)
        {
            return NotFound();
        }

        var DataRes = new {
            sdata = patReg                
        };

        return Ok(DataRes);
    }

生成的JSON

{
    "sdata": {
        "fileId": 1708010001,
        "fName": "Json",
        "mName": "S",
        "lName": "Makenzi",
        "fullname": "Json S Abu Makenzi",
        "dob": "1984-04-26T00:00:00",
        "patPar": [{
            "recId": 2,
            "fileId": 1708010001,
            "parFileId": 1708010002,
            "sDate": "1999-12-12T00:00:00",
            "eDate": null,
        }, {
            "recId": 3,
            "fileId": 1708010001,
            "parFileId": 1708010003,
            "sDate": "1955-12-14T00:00:00",
            "eDate": null,
        }]
    }
}

我希望 patPar 列表的 JSON 输出对于每条记录如下所示,

"patPar": [{
                "recId": 2,
                "fullname": "Json S Abu Makenzi",
                "fileId": 1708010001,
                "parFileId": 1708010002,
                "sDate": "1999-12-12T00:00:00",
                "eDate": null,
            }, {
                "recId": 3,
                "fullname": "Sarah S Maz",
                "fileId": 1708010001,
                "parFileId": 1708010003,
                "sDate": "1955-12-14T00:00:00",
                "eDate": null,
            }]

问题,fullname 存在于主模型PatReg 中,但可以通过链接记录而不是fileIdfileIdfileIdparFileId 来读取。

换句话说,我如何在PatPar 中添加fullname 值以及其他值,即使它在模型中不存在?我需要property 吗?

更新说明

我基本上在做三个选择

首先我使用IdPatReg中选择记录 第二个PatPar 具有相关数据,并且使用相同的Id 被选中

我的问题是 fullname,我需要将它包含在 PatPar 中,但选择不同的键

第三个选择应为PatPar 中的parFileIdPatReg 中的FileID

等效的 SQL 是

第一个选择:

SELECT FileId, FName, LName, Dob FROM PatReg Where FileId=id 

二选三:

SELECT        PatReg.FileId, PatReg.FName, PatReg.MName, PatReg.LName, PatPar.EDate, PatPar.ParFileId, PatPar.SDate, PatReg_1.FName AS PFName, PatReg_1.MName AS PMName, PatReg_1.LName AS PLName
FROM            PatPar INNER JOIN
                         PatReg ON PatPar.FileId = PatReg.FileId INNER JOIN
                         PatReg AS PatReg_1 ON PatPar.ParFileId = PatReg_1.FileId

更新

所需的 JSON 是

{
    "sdata": {
        "fileId": 1708010001,
        "fName": "**",
        "mName": "**",
        "lName": "**",
        "fullname": "***",
        "dob": "1984-04-26T00:00:00",
        "patPar": [{
                "recId": 2,
                "fullname": "*****",
                "fileId": 1708010001,
                "parFileId": 1708010002,
                "sDate": "1999-12-12T00:00:00",
                "eDate": null,
            }, {
                "recId": 3,
                "fullname": "*****",
                "fileId": 1708010001,
                "parFileId": 1708010003,
                "sDate": "1955-12-14T00:00:00",
                "eDate": null,
            }]
    }
}

【问题讨论】:

    标签: c# json entity-framework


    【解决方案1】:

    使用 DTO(数据传输对象)在两个端点之间传输数据是一种很好的做法。通过这种方式,您可以指定要共享的属性,根据需要编辑模型,并且可以摆脱那些您不会使用的嘈杂属性。在这种情况下,您可以添加如下所示的类:

    public class PatParDto
    
    {
        public int RecId { get; set; }
        public int FileId { get; set; }
        public int ParFileId { get; set; }
        public DateTime SDate { get; set; }
        public DateTime? EDate { get; set; }
    
        public string FullName {get; set;}
    }
    

    然后在您的 linq 查询中,您可以选择您的 PatPar 作为 PatPatDto :

    var patRegPar = await _context.PatPar
                .Where(m => m.FileId == id)
                .Select(m => new PatParDto {
    
                 //Here you can set properties 
                 FullName = patReg.fullname,
                 RecId = m.RecId
    
                })
                .ToListAsync();
    

    您可以使用 AutoMapper 之类的库来代替手动设置属性

    【讨论】:

    • "fullname" 存在于PatReg 而不是PatPar 中,并且为了得到它应该在哪里声明应该像where(c.ParFileId==id)
    • 是否需要两个 DTO 才能获得如上所示的输出?或者我可以使用 DTO 在 PatReg 模型中填充 public ICollection&lt;PatPar&gt; PatPar { get; set; }
    • 我会为每个要表示的表创建 1 个 DTO 类,在本例中为 2 个。在您的 PatRegDto 中,您可以使用 List&lt;PatPar&gt; 为简单起见。
    • 如何将这些 DTO 连接在一起?
    • 是的 foreach 应该这样做。而且您不应该使用 NotMapped 数据注释,因为您不会直接使用这些 DTO 来创建或更新您的数据库。相反,您需要将这些 DTO 映射到您的 EF 模型,然后创建、更新等
    【解决方案2】:

    当我们使用相关表时,我的 seggestion 是从虚拟属性中创建一个匿名类型:

    var patRegPar = await _context.PatPar  // here I get related Records
            .Include(c=>c.PatReg)
            .Where(m => m.FileId == id)
            .Select(t=>new{ recId = t.recId , fullname = t.PatReg.fullname , ... })
            .ToListAsync();
    

    【讨论】:

      【解决方案3】:

      谢谢Ege Tuncoz

      我添加了DTO

      public class PatParDto
      
      {
          public int RecId { get; set; }
          public int FileId { get; set; }
          public int ParFileId { get; set; }
          public DateTime SDate { get; set; }
          public DateTime? EDate { get; set; }
      
          public string FullName {get; set;}
      }
      

      然后在我的控制器中,我运行一个循环来为 DTO 中的每条记录添加所需的值。

           [HttpGet("{id}")]
              public async Task<IActionResult> GetPatReg([FromRoute] long id)
              {
      
                          if (!ModelState.IsValid)
                          {
                              return BadRequest(ModelState);
                          }
                          var patReg = await _context.PatReg
                              .Where(m => m.FileId == id)
                              .ToListAsync();
      
                          var patpar = await _context.PatPar.Select(m => new PatParDto {
                              RecId = m.RecId,
                              FileId = m.FileId,
                              ParFileId = m.ParFileId,
                              SDate = m.SDate,
                              EDate = m.EDate,
                          }).ToListAsync();
                          for (int i = 0; i < patpar.Count; i++)
      
                          {
                              patpar[i].FullName = (from a in _context.PatReg
                              where (a.FileId == patpar[i].ParFileId)
                                                    select new { a.fullname }
                                                    ).Single().fullname;  
      
                                          or 
      
                              patpar[i].FullName = _context.PatReg.Where(a => 
                              a.FileId == patpar[i].ParFileId)
                                             .Select(t=>new {t.fullname })
                                             .Single().fullname;                                    
      
                          }
      
      
                          if (patReg == null)
                          {
                              return NotFound();
                          }
      
                          var DataRes = new {
                              sdata = patReg,
                              test= patpar
                          };
      
                          return Ok(DataRes);
               }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-02
        • 1970-01-01
        • 2017-10-21
        • 1970-01-01
        • 2017-05-09
        • 2015-11-14
        • 1970-01-01
        • 2019-03-19
        相关资源
        最近更新 更多