简体   繁体   English

EF Core 不在子表中插入外键

[英]EF Core does not insert foreign key in child table

I have the following classes:我有以下课程:

public class PresentingComplaintModel
{ 
    // for presenting complaints only
    [Key]
    public int ComplaintId { get; set; }
    public string Complaint { get; set; }
    public int? PatientId { get; set; }
    public Patient Patient { get; set; }
    public DateTime CreationDate { get; set; }
    public List<PatientComplaintQuestionAnswers> PatientComplaintQuestionAnswers { get; set; }
}

This class has a one-to-many relation to this class:此类与此类具有一对多关系:

public class PatientComplaintQuestionAnswers
{ 
    [Key]
    public int Id { get; set; }
    public int? PresentingComplaintQuestionId { get; set; }
    public PresentingComplaintQuestionModel PresentingComplaintQuestionModel { get; set; }
    public bool Answer { get; set; }
    public int ComplaintId { get; set; } //from PresentingComplaintModel
    public PresentingComplaintModel PresentingComplaintModel {get;set;}
}

This class has two foreign keys: PresentingComplaintQuestionId and ComplaintId .这个类有两个外键: PresentingComplaintQuestionIdComplaintId The problem is when I insert a PresentingComplaintModel object into the database, the child table ( PatientComplaintQuestionAnswers ) receives data but the ComplaintId is always set to 0. Which means that the ComplaintId is not being populated from the primary key of the PresentingComplaintModel class.问题是当我将PresentingComplaintModel对象插入数据库时​​,子表 ( PatientComplaintQuestionAnswers ) 接收数据但ComplaintId始终设置为 0。这意味着ComplaintId不是从PresentingComplaintModel类的主键中填充的。

I expect this to have non-zero primary key value.我希望这具有非零主键值。 How to fix this problem?如何解决这个问题?

PresentingComplaintModel is hydrated as follows. PresentingComplaintModel的水合如下。 Here ComplaintId is always 0 as a new record is being created.此处ComplaintId始终为 0,因为正在创建新记录。

PresentingComplaintModel complaint = new();
List<PresentingComplaintQuestionModel> MasterQuestions { get; set; }
public PatientComplaintQuestionAnswers selectedItem1 { get; set; }

protected override async Task OnInitializedAsync()
{
    complaint.PatientComplaintQuestionAnswers = new List<PatientComplaintQuestionAnswers>();
    complaint.Complaint = "";
    complaint.CreationDate = DateTime.Now;
    complaint.PatientId = AppState.SelectedPatient.PatientId;
    MasterQuestions = await DataService.GetPresentingComplaintQuestionsAsync(); //get master questions.

    foreach (var q in MasterQuestions)
    {
        var ans = new PatientComplaintQuestionAnswers();
        ans.ComplaintId = complaint.ComplaintId;
        ans.PresentingComplaintQuestionId = q.PresentingComplaintQuestionId;
        ans.Answer = false;
        ans.PresentingComplaintQuestionModel = q;
        ans.PresentingComplaintModel = complaint; //reciprocal hydrating. see https://stackoverflow.com/questions/72293081/efcore-does-not-insert-foreign-key-in-child-table/72293303#72293303
        complaint.PatientComplaintQuestionAnswers.Add(ans);
    }
}

And then saved to DB:然后保存到数据库:

var res = await DataService.UpdatePresentingComplaintAsync(complaint);
...
...
public async Task<bool> UpdatePresentingComplaintAsync(PresentingComplaintModel complaint)
{
    int res = 0;

    using (var scope = _scopeFactory.CreateScope())
    {
        var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();

        try
        {
            context.PresentingComplaints.Update(complaint);
            res = await context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
        }
    }

    if (res > 0)
        return true;
    else
        return false;
}

And on the database side I see these insertions.在数据库方面,我看到了这些插入。 Note that the ComplaintId column has all 0s in it:请注意, ComplaintId列中全为 0:

数据库截图

Usually this is a lack of "reciprocal" hydrating.通常这是缺乏“互惠”保湿。

public class MyParent()
{
    public MyParent()
    {
         this.TheKids = new List<MyChild>();
    }

    public long MyParentKey {get; set;} /* PK */


    public ICollection<MyChild> TheKids {get;set;}
}

public class MyChild()
{
  public long MyChildKey {get; set;} /* PK */
  public long MyParentKey {get;set;} /* FK to MyParent */

  public MyParent TheMyParent {get;set;} /* navigation property to MyParent */
}

When you hydrate "do not exist in the db yet" entities.. you gotta do some "reciprocal"当您水合“数据库中尚不存在”实体时..您必须做一些“互惠”

MyParent p1 = new MyParent();

MyChild c1 = new MyChild();

/* most people do this */
p1.TheKids.Add(c1);

/* the "reciprocal" that is sometimes missed */
c1.TheMyParent = p1;

(or it can be vice-versa, the child gets "TheMyParent" set, but the child is not added to the MyParent.TheKids collection) (或者反之亦然,孩子获得“TheMyParent”集,但孩子没有添加到 MyParent.TheKids 集合中)

Give that a try (make sure all reciprocals are set)试试看(确保设置了所有倒数)

Note, I have NOT set MyChild.MyParentKey.注意,我没有设置 MyChild.MyParentKey。

I would do it this way if the MyParent does not exist yet.如果 MyParent 尚不存在,我会这样做。

.. ..

EF allows for a "short cut" of using FK scalars...IF they are known. EF 允许使用 FK 标量的“捷径”......如果它们是已知的。

For example.例如。

public class Employee()
{
  public long EmployeeKey {get; set;} /* PK */
  public string LastName {get; set;} 
  public string FirstName {get; set;} 
  public long ParentDepartmentKey {get;set;} /* FK to Department */

  public Department ParentDepartment {get;set;} /* navigation property to Department */
}

If I had the above class, and when I added a new Employee..and the Employee had to have its department set to an EXISTING department.如果我有上述课程,并且当我添加一个新员工时......并且员工必须将其部门设置为现有部门。

then I could do something like然后我可以做类似的事情

Employee emp = new Employee();
emp.LastName = "Smith";
emp.FirstName = "Mary";

emp.ParentDepartmentKey = 333; /* an already existing Department */

This way, I do NOT have to fully hydrate the emp.ParentDepartment OBJECT (navigation property) to add the Employee.这样,我不必完全水合 emp.ParentDepartment OBJECT(导航属性)来添加 Employee。

So you need to be aware of "what exist and what does not yet exist" when populating your object-graph before giving it to your EF dbcontext and persisting the changes.因此,在将对象图提供给您的 EF dbcontext 并持久化更改之前,您需要了解“存在什么和不存在什么”。

Ok, I found the fix.好的,我找到了解决方法。 It seems that EFCore is not setting up the foreign key column properly in this case.在这种情况下,似乎 EFCore 没有正确设置外键列。 So I modified the PatientComplaintQuestionAnswers class with explicit ForeignKey attributes:所以我用明确的 ForeignKey 属性修改了 PatientComplaintQuestionAnswers 类:

public class PatientComplaintQuestionAnswers
{ 
    [Key]
    public int Id { get; set; }
    public int? PresentingComplaintQuestionId { get; set; }
    public PresentingComplaintQuestionModel PresentingComplaintQuestionModel { get; set; }
    public bool Answer { get; set; }
    public int ComplaintId { get; set; } //from PresentingComplaintModel
    public PresentingComplaintModel PresentingComplaintModel {get;set;}
}

To

public class PatientComplaintQuestionAnswers
    { //patient answers these questions in the patient presenting complaint form
        [Key]
        public int Id { get; set; }
        [ForeignKey("PresentingComplaintQuestionModel")]
        public int? PresentingComplaintQuestionId { get; set; }
        public PresentingComplaintQuestionModel PresentingComplaintQuestionModel { get; set; }
        public bool Answer { get; set; }
        [ForeignKey("PresentingComplaintModel")]
        public int ComplaintId { get; set; } //from PresentingComplaintModel
        public PresentingComplaintModel PresentingComplaintModel {get;set;}
    }

This fixed the relations and no extraneous columns were generated by EFCore either.这修复了关系,并且 EFCore 也没有生成任何无关的列。

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

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