简体   繁体   English

如何使用EF合并来自两个相关模型的相关数据?

[英]How to combine related data from two related models using EF?

Concept 概念

I have two models that are related in one to many relationship. 我有两个相互关联的模型。 the first model basically stores patients information ( PatReg ). 第一个模型基本上存储患者信息( PatReg )。 the second Model join partners together ( PatPar ). 第二个模型将合作伙伴( PatPar )联合在一起。 ie (FileId=1 Sam, FileId=2 Victoria, FileId=3 jessica, FileId=4 monica) info are all stored in PatReg . 即(FileId = 1 Sam,FileId = 2 Victoria,FileId = 3 jessica,FileId = 4 monica)信息都存储在PatReg in order to say that Sam is a partner to Victoria and Jessica I join them in PatPar the following fashion: 为了说Sam是Victoria和Jessica的合伙人,我以以下方式加入PatPar

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

the following states these two models. 下面说明这两个模型。

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; }
    }

Getting Related Data I m using an API controller in my project, the way I query my record is as follows, 在项目中使用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);
    }

Resulting JSON 结果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,
        }]
    }
}

I want my JSON output for patPar list to look like the following for each record, 我希望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,
            }]

The problem, the value fullname exists in the Main model PatReg but can be read via linking records instead of fileId to fileId , fileId to parFileId . 问题是, fullname的值存在于Main模型的PatReg但是可以通过链接记录而不是fileIdfileIdfileIdparFileIdparFileId

in another words, How can I add the fullname value in PatPar along with the other values even if it does not exist in the model? 换句话说,即使模型中不存在fullname值,我如何将其与其他值一起添加到PatPar中? do I need a property for it? 我需要property吗?

Update for clarification 更新以澄清

I m doing basically Three selections 我基本上是在做三个选择

first I select the record from PatReg using Id second PatPar has related data and are getting selected using the same Id 首先,我使用IdPatReg选择记录;第二, PatPar具有相关数据,并且正在使用相同Id

My issue is the fullname , I need to include it in PatPar but with a different key selection 我的问题是fullname ,我需要将其包括在PatPar中,但要选择其他键

Third Selection should goes as parFileId in PatPar to FileID in PatReg 第三个选择应该去为parFileIdPatParFileIDPatReg

the equivalent SQL is 等效的SQL是

first selection: 首选:

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

Second and third selection: 第二和第三选择:

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

Update 更新资料

Desired JSON is 所需的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,
            }]
    }
}

It's a good practice to use DTOs(Data Transfer Objects) to transfer data between two endpoints. 使用DTO(数据传输对象)在两个端点之间传输数据是一个好习惯。 This way you can specify what properties you want to share, edit your model as you wish and you can get rid of those noisy properties that you wont use. 这样,您可以指定要共享的属性,根据需要编辑模型,并摆脱那些您不会使用的嘈杂属性。 In this case you can add a class like below : 在这种情况下,您可以添加如下所示的类:

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;}
}

and then in your linq query you can select your PatPar as PatPatDto : 然后在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();

Instead of setting properties manually you can use a library like AutoMapper 您可以使用像AutoMapper这样的库来代替手动设置属性

my seggestion is to make an anonymous type from the virtual property when we use the related table: 我的分类是在使用相关表时从虚拟属性中创建匿名类型:

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();

Thanks Ege Tuncoz 感谢Ege Tuncoz

I added the DTO , 我添加了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;}
}

then in my controller I ran a loop to add the desired value for each record in the DTO. 然后在我的控制器中运行一个循环,为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);
         }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM