【问题标题】:Storing a foreign key for the main primary key in each table在每个表中存储主主键的外键
【发布时间】:2020-05-25 14:13:54
【问题描述】:

假设我们有一个表UsersID 作为主键,并且用户有以下相关实体:

UserSubjects(SubjectId <PK>,UserId <FK>)
SubjectPapers(PaperId<PK>,SubjectId<FK>)

现在根据上表,出于安全原因,必须将userId 作为参数传递,以获取与用户相关的Subject 的所有SubjectPapers,而不仅仅是传递SubjectId

以该方法为例:

 public List<SubjectPaper> GetBySubject(int userId, int subjectId)
 {
     return _context.SubjectPapers
         .Include(k => k.UserSubject)
         .Where(k => k.SubjectId == subjectId && k.UserSubject.UserId == userId)
         .ToList();
 }

在上述方法中,用户必须包含在查询中,以验证他是否正在发出获取他的主题之一的请求。

如果SubjectPapers 理论上也有更多相关实体怎么办。存储UserId 外键是否会通过在两列(UserId 和 SubjectId)上添加非聚集索引来提高查询的性能?有没有副作用?还是有任何其他方法可以避免将父用户包含在每个相关实体中?任何建议表示赞赏。

【问题讨论】:

    标签: sql sql-server ef-core-2.0


    【解决方案1】:

    如果需要 UserId 来查找 Subject,那么 Subject 是一个“Weak Entity”,并且 UserID 应该是它的复合主键中的前导列。

    UserSubjects(UserId <PK,FK>,SubjectId <PK>)
    

    IE 喜欢

    public class User
    {
        public int UserId { get; set; }
        public virtual ICollection<Subject> Subjects { set; } = new HashSet<Subject>();
    }
    public class Subject
    {
        public int UserID { get; set; }
        public int SubjectId { get; set; }
        public virtual User UserId { get; set; }
    }
    

    并像这样配置:

    modelBuilder.Entity<Subject>().HasKey(s => new { s.UserID, s.SubjectId });
    modelBuilder.Entity<Subject>().Property(s => s.SubjectId).ValueGeneratedOnAdd();
    

    这优化了通过 UserID 检索并防止主题表需要多个索引。它在 (UserID,SubjectID) 上有一个聚集索引,而不需要在两列上有两个单独的索引。

    【讨论】:

    • 感谢您指出对UserSubjects 使用多个主键,但主要问题是第二个相关表SubjectPapers,它总是需要包含父表UserSubject验证UserId?
    • 这是一个建模决策。但是,如果您想用 UserID 检索那些孙行,是的。弱实体表的整个层次结构或“集群”获得复合主键。所以 SubjectPapers 将 (UserId,SubjectId,SubjectPaperId) 作为其键。
    • 太棒了!但在我上面使用的方法的情况下,我还将为UserId and SubjecId 引入一个非聚集索引
    • (UserId, SubjectId) 上的集群主键就足够了。索引的规则是每个键和每个外键都需要一个索引。在这里,一个单一的复合索引可以做到这两点。如果您希望仅通过 SubjectId 进行高效查找或唯一性,那么您可以在 SubjectId 上使用非聚集索引。
    • 这是一个三列的PK。而且它可能根本不需要任何非聚集索引。
    猜你喜欢
    • 2014-01-14
    • 2016-03-05
    • 2013-05-12
    • 1970-01-01
    • 2017-03-10
    • 1970-01-01
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    相关资源
    最近更新 更多