【问题标题】:Why is in adding a collection with its own ID in an entity, i always get the principal ID instead of the collection's id?为什么在实体中添加具有自己 ID 的集合时,我总是得到主体 ID 而不是集合的 ID?
【发布时间】:2019-09-10 16:00:44
【问题描述】:

我正在将一个集合添加到现有的数据集中。我有一个学生,其科目仍然是null。所以我正在做的是将post 收藏到那个学生中。

这是我的code

[HttpPost("{id}/subjects")]
public async Task<ActionResult<object>> PostStudentSubject(string id, Subject item)
{
    // this is to get whole subject model using id
    Subject subj = await _context.Subjects.FindAsync(item.Id);

    // this is to get student model through the given id in parameter
    Student stud = await _context.FirstOrDefaultAsync(p => p.Id == id);

    if (stud == null){
        return NotFound();
    }

    // this is to remove the "subj" to avoid an Exception:
    // "The property 'Id' is part of the object's key information and cannot be modified"
    _context.Subjects.Remove(subj);
    await _context.SaveChangesAsync();

    // and this is now to add a new object Subject to the
    // collection of subjects in the student
    stud.Subjects.Add(new Subject { Id = subj.Id });
    // some subject properties are omitted...
    await _context.SaveChangesAsync();

    return Ok(stud);
}

它返回 OK 但 Swagger 响应返回这些:

服务器响应

代码 -> 未记录,详细信息 -> 错误:OK

回复

代码 -> 200,描述 -> 成功

可见的问题主题的ID会变成学生的ID。为什么会这样?我在哪一部分得到这个?

主题

    public class Subject
    {
        [Key]
        public string Id { get; set; }

        // some codes omitted ...

        [ForeignKey("Id")]
        public Student student {get; set;}
    }

学生

    public class Student
    {
        [Key]
        public string Id { get; set; }

        // some codes omitted ...

        public IList<Subject> Subjects {get; set;} = new List<Subject>();
    }

【问题讨论】:

  • 您能否为您的学生和学科映射以及实体定义包括任何映射/配置?这听起来好像您的主题被配置为与学生的一对一。或者 FK 映射配置错误。
  • @StevePy 我已经添加了
  • 外键属性是你的问题。在代码示例的解决方案中避免了这一点......

标签: c# entity-framework asp.net-web-api


【解决方案1】:

问题是外键:

    [ForeignKey("Id")]
    public Student student {get; set;}

Subject 表应该有一个 StudentId 列指向适用的学生。实际上,您是在告诉 Subject 它的 PK 应该是学生 ID。 (就像一对一的关系)

如果这是代码优先,则在 EF 中:

public class Subject
{
    [Key]
    public string Id { get; set; } // ID for the Subject

    // some codes omitted ...

    public string StudentId { get; set; } // FK to the student.
    [ForeignKey("StudentId")]
    public Student student {get; set;}
}

但是,学生和学科之间的关系可能应该是多对多的,其中许多学生可以与许多相同的学科相关联。 (一个学生有很多科目,一个科目有很多学生)

为此,您需要一个名为 StudentSubjects 之类的链接表。

StudentSubjects
StudentId [PK] [FK -> Students]
SubjectId [PK] [FK -> Subjects]

EF 可以自动管理这个表,只要它只包含复合键而不包含其他字段。否则,您需要将其定义为实体并手动提供映射。

public class Student
{
   [Key]
   public int Id { get; set; } 

   public virtual ICollection<Subject> Subjects { get; set; } = new List<Subject>();
}

public class Subject
{
   [Key]
   public int Id { get; set; } 

   public virtual ICollection<Student> Students { get; set; } = new List<Student>();
}

如果 CodeFirst 这应该设置一个 StudentSubjects(或 SubjectStudents)表来管理关系。否则可以映射 HasMany.WithMany 并定义表格,左右键关系...

即对于学生 EntityTypeConfiguration

// EF6 Syntax. EF Core will be a tad different /w IEntityTypeConfiguration<Student> implementation.

public class StudentConfiguration : EntityTypeConfiguration<Student>
{
   public StudentConfiguration()
   {
      HasMany(x => x.Subjects)
         .WithMany(x => x.Students)
         .Map(x => x.ToTable("StudentSubjects").MapLeftKey("StudentId").MapRightKey("SubjectId"));
   }
}

我强烈建议不要对 PK 使用字符串。它们对于存储和索引来说非常大,您无法使用 DB 端标识或默认值,例如 NewSequentialId() [GUIDs]

【讨论】:

  • 我的解决方案是删除 ForeignKey 属性。我使用了Single Navigation 而没有ForeignKey
  • 对于课程的学生引用,每个课程实例将只有一个学生的引用,当您尝试将其添加到第二个学生时,您最终可能会“移动”该课程。否则,您将拥有具有相同详细信息的不同 PK 的重复课程,该课程中的每个学生都有一个。如果有其他相关问题,请走开。 :)
猜你喜欢
  • 2015-07-13
  • 1970-01-01
  • 1970-01-01
  • 2014-07-11
  • 2011-12-03
  • 2021-01-07
  • 2016-02-14
  • 2014-08-18
  • 2015-03-18
相关资源
最近更新 更多