实体框架核心关系问题(代码优先) - 重复列

Posted

技术标签:

【中文标题】实体框架核心关系问题(代码优先) - 重复列【英文标题】:Entity Framework Core Relationship Issue (code first) - duplicate columns 【发布时间】:2021-11-02 11:45:27 【问题描述】:

我正在使用代码优先方法(EF Core 5 + SQL Server)开发一个应用程序。

我有一些包含数据的表,然后是 2 个连接表。

我遇到的问题是 EF 以某种方式在连接表中创建了重复的列。例如。 SessionId 和 SessionId1。我不知道为什么。

这里有一些来自代码的sn-ps以便更好地理解:

会话表:

    public class Session
    
        public long Id  get; set; 
        public string Name  get; set; 
        public long EventId  get; set; 

        public virtual Event Event  get; set; 
        public virtual UserSessionRole UserSessionRole  get; set; 
    

事件表:

    public class Event
    
        public long Id  get; set; 
        public string Name  get; set; 
        public DateTime Date  get; set; 

        public virtual List<Session> Sessions  get; set; 
    

连接表:

    public class UserSessionRole
    
        public long Id  get; set; 
        public long SessionId  get; set; 
        public long RoleId  get; set; 
        public long UserId  get; set; 
        public long EventId  get; set; 

        public virtual Session Session  get; set; 
        public virtual Event Event  get; set; 
        public virtual Role Role  get; set; 
        public virtual User User  get; set; 
    

我使用 fluent API 来定义关系等。例如。会话设置:

// Map entities to tables  
            modelBuilder.Entity<Session>().ToTable("sessions");

            // Configure Primary Keys  
            modelBuilder.Entity<Session>().HasKey(u => u.Id);
            modelBuilder.Entity<Session>().Property(p => p.Id).ValueGeneratedOnAdd();

            // Configure indexes  
            modelBuilder.Entity<Session>().HasIndex(u => u.EventId);

            // Configure columns  
            modelBuilder.Entity<Session>().Property(ug => ug.Name).HasColumnType("nvarchar(255)").IsRequired();
            modelBuilder.Entity<Session>().Property(ug => ug.Description).HasColumnType("nvarchar(255)").IsRequired();
            modelBuilder.Entity<Session>().Property(ug => ug.DateTime).HasColumnType("datetime").IsRequired();
            modelBuilder.Entity<Session>().Property(ug => ug.VonageSessionId).HasColumnType("nvarchar(255)").IsRequired();

            // Configure relationships  
            modelBuilder.Entity<Session>().HasMany<UserSessionRole>().WithOne(r => r.Session).HasForeignKey(u => u.SessionId).OnDelete(DeleteBehavior.NoAction);

用户会话角色:

            // Map entities to tables  
            modelBuilder.Entity<UserSessionRole>().ToTable("usersessionroles");

            // Configure Primary Keys  
            modelBuilder.Entity<UserSessionRole>().HasKey(x => new  x.RoleId, x.SessionId, x.UserId );
            modelBuilder.Entity<UserSessionRole>().Property(p => p.Id).ValueGeneratedOnAdd();

在这种情况下,我得到重复的 SessionId 和重复的 RoleId,但不是 EventId。

任何人都知道我配置错了什么或者是否有任何我不知道的技巧?

【问题讨论】:

【参考方案1】:

我最终通过从 Session 中删除 Event 并明确定义 WithMany 关系解决了这个问题。我也是从另一边做的。

这行得通:

modelBuilder.Entity<UserSessionRole>().HasOne(x => x.Event).WithMany(s => s.UserSessionRoles).HasForeignKey(u => u.EventId).OnDelete(DeleteBehavior.NoAction);

这没有:

modelBuilder.Entity<UserSessionRole>().HasOne(x => x.Event).WithMany(s).HasForeignKey(u => u.EventId).OnDelete(DeleteBehavior.NoAction);

【讨论】:

【参考方案2】:

使用您的代码 sn-p 我可以理解的是您正在尝试创建一对多关系的事件和会话表,如果是这样我们可以避免连接表 (UserSessionRole) 并将 RoleId、UserId 带到会话表。

public class Event

    public long Id  get; set; 
    public string Name  get; set; 
    public DateTime Date  get; set; 

    public virtual ICollection<Session> Sessions  get; set; 

public class Session

    public long Id  get; set; 
    public string Name  get; set; 
    public long RoleId  get; set; 
    public long UserId  get; set; 
    public long EventId  get; set; 

    public virtual Event Event  get; set; 
    public virtual Role Role  get; set; 
    public virtual User User  get; set; 

如果你需要连接表(UserSessionRole)那么关系变成Event : UserSessionRole(一对多)和UserSessionRole : Session(一对一)就会变成这样,

public class Event

    public long Id  get; set; 
    public string Name  get; set; 
    public DateTime Date  get; set; 

    public virtual ICollection<UserSessionRole>SessionRoles get; set; 


// One to Many Relation between Event and UserSessionRole

public class UserSessionRole

    public long Id  get; set; 
    public long EventId  get; set; 
    public long RoleId  get; set; 
    public long UserId  get; set; 
    public long SessionId  get; set; 

    public virtual Session Session  get; set; 
    public virtual Event Event  get; set; 
    public virtual Role Role  get; set; 
    public virtual User User  get; set; 


// One to One Relation between UserSessionRole and Session

public class Session

    public long Id  get; set; 
    public string Name  get; set; 

    public virtual Session Session  get; set; 

【讨论】:

【参考方案3】:

由于你有连接表并且在 Session 和 Event 之间建立了多对多关系,所以从 Session 中移除 EventId,并且由于你使用的是 Net5,你也可以将事件集合添加到 Session 中

public class Session
    
        public long Id  get; set; 
        public string Name  get; set; 
      
        public virtual ICollection<Event> Events  get; set; 
        public virtual ICollection <UserSessionRole> UserSessionRoles  get; set; 
    
Event table:

    public class Event
    
        public long Id  get; set; 
        public string Name  get; set; 
        public DateTime Date  get; set; 

        public virtual ICollection <UserSessionRole> UserSessionRoles  get; set; 
        public virtual List<Session> Sessions  get; set; 
    

【讨论】:

我试过了,但没有解决问题,谢谢。 @Skynet 你必须相应地更新你的 Fluent API 并再次进行初始化迁移。

以上是关于实体框架核心关系问题(代码优先) - 重复列的主要内容,如果未能解决你的问题,请参考以下文章

理解实体框架核心外键关系

多对多关系实体框架核心db优先

实体框架代码优先:在具有不同连接列的实体中展平组合

实体框架4.1代码优先中的一对多关系

实体框架代码优先关系 - 如何定义两个对象之间的关系:两个实体之间的可选一对一

如何使用带有代码优先实体框架的 UnitOfWork 模式防止重复条目?