EF Core 7代码优先外键异常:插入时触发标识列写入错误
问题描述
确定问题出在OnModelCreating方法中,但不清楚缺失了什么配置。尝试创建两个DbSet,让SocialMediaUrls通过外键关联SocialMediaTypes,但向SocialMediaUrls插入数据时,代码却试图向SocialMediaTypes中插入内容,不符合预期。
实体类代码
public class SocialMediaUrls { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public Guid? ProfileId { get; set; } public SocialMediaTypes? SocialMediaTypes { get; set; } [Required] public string Url { get; set; } = string.Empty; [Required] public bool isActive { get; set; } } public class SocialMediaTypes { [Key] public int SocialMediaTypesId { get; set; } [Required] public string Name { get; set; } public string? Url { get; set; } = string.Empty; public string? PlaceholderText { get; set; } = string.Empty; public string? IconUrl { get; set; } = string.Empty; [Required] public bool isPaymentApp { get; set; } [Required] public bool isActive { get; set; } }
新增/更新逻辑代码
public async Task<SocialMediaUrls> AddUpdateProfileSocialMediaAsync(SocialMediaUrls ProfileSocialMedia) { var foundSocialMedia = await _context.SocialMediaUrls.FirstOrDefaultAsync(e => e.Id == ProfileSocialMedia.Id); if (foundSocialMedia != null) { foundSocialMedia.Url = ProfileSocialMedia.Url; foundSocialMedia.SocialMediaTypesId = ProfileSocialMedia.SocialMediaTypesId; await _context.SaveChangesAsync(); return foundSocialMedia; } else { try { var addedEntity = await _context.SocialMediaUrls.AddAsync(ProfileSocialMedia); await _context.SaveChangesAsync(); return addedEntity.Entity; } catch (Exception ex) { throw; } } }
DbContext代码
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<SocialMediaUrls>().HasIndex(s => s.Id).IsUnique(true); modelBuilder.Entity<SocialMediaTypes>().HasIndex(s => s.SocialMediaTypesId).IsUnique(true); modelBuilder.Entity<SocialMediaTypes>().HasData( new SocialMediaTypes { SocialMediaTypesId = 1, Name = "Website", IconUrl= "Website.png", isActive = true, Url="", PlaceholderText="", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 2, Name = "Facebook", IconUrl = "Facebook.png", isActive = true, Url = "www.facebook.com/", PlaceholderText = "link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 3, Name = "Twitter", IconUrl = "Twitter.png", isActive = true, Url = "www.twitter.com/", PlaceholderText = "username or link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 4, Name = "Instagram", IconUrl = "Instagram.png", isActive = true, Url = "www.instagram.com/", PlaceholderText = "username or link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 5, Name = "YouTube", IconUrl = "YouTube.png", isActive = true, Url = "www.youtube.com/", PlaceholderText = "link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 6, Name = "LinkedIn", IconUrl = "LinkedIn.png", isActive = true, Url = "www.linkedin.com/in/", PlaceholderText = "username or link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 7, Name = "Snapchat", IconUrl = "Snapchat.png", isActive = true, Url = "www.snapchat.com/add/", PlaceholderText = "username or link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 8, Name = "TikTok", IconUrl = "TikTok.png", isActive = true, Url = "www.tiktok.com/@", PlaceholderText = "username or link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 9, Name = "Twitch", IconUrl = "Twitch.png", isActive = true, Url = "www.twitch.tv/", PlaceholderText = "username or link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 10, Name = "Pinterest", IconUrl = "Pinterest.png", isActive = true, Url = "www.pinterest.com/", PlaceholderText = "link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 11, Name = "Vimeo", IconUrl = "Vimeo.png", isActive = true, Url = "www.vimeo.com/", PlaceholderText = "username or link", isPaymentApp = false }, new SocialMediaTypes { SocialMediaTypesId = 12, Name = "CashApp", IconUrl = "CashApp.png", isActive = true, Url = "www.cash.app/$", PlaceholderText = "username or link", isPaymentApp = true }, new SocialMediaTypes { SocialMediaTypesId = 13, Name = "Venmo", IconUrl = "Venmo.png", isActive = true, Url = "www.venmo.com/", PlaceholderText = "link", isPaymentApp = true }, new SocialMediaTypes { SocialMediaTypesId = 14, Name = "PayPal", IconUrl = "PayPal.png", isActive = true, Url = "www.paypal.me/", PlaceholderText = "username or link", isPaymentApp = true } ); }
已尝试的配置
modelBuilder.Entity<SocialMediaUrls>() .HasOne(s => s.SocialMediaTypes) .WithMany() .OnDelete(DeleteBehavior.Restrict);
解决方案
1. 补充外键属性
在SocialMediaUrls类中显式添加外键字段,让EF Core明确关联关系:
public class SocialMediaUrls { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public Guid? ProfileId { get; set; } // 添加显式外键属性 public int? SocialMediaTypesId { get; set; } public SocialMediaTypes? SocialMediaTypes { get; set; } [Required] public string Url { get; set; } = string.Empty; [Required] public bool isActive { get; set; } }
2. 正确配置实体关系
在OnModelCreating中指定外键,明确关联规则:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置一对多关系,指定外键 modelBuilder.Entity<SocialMediaUrls>() .HasOne(s => s.SocialMediaTypes) .WithMany() .HasForeignKey(s => s.SocialMediaTypesId) .OnDelete(DeleteBehavior.Restrict); // 种子数据保留不变 modelBuilder.Entity<SocialMediaTypes>().HasData( // 你的种子数据... ); }
3. 调整新增逻辑
插入SocialMediaUrls时,只设置SocialMediaTypesId外键值,不要传入SocialMediaTypes实例(避免EF误判为新实体):
// 示例:创建新的SocialMediaUrls对象时直接用已存在的类型ID var newSocialMedia = new SocialMediaUrls { ProfileId = someGuid, SocialMediaTypesId = 1, // 对应已存在的SocialMediaTypesID Url = "https://example.com", isActive = true }; await _context.SocialMediaUrls.AddAsync(newSocialMedia); await _context.SaveChangesAsync();
如果必须传入SocialMediaTypes实例,需要先将其附加到上下文,标记为已存在:
if (ProfileSocialMedia.SocialMediaTypes != null) { // 告诉EF该实体已存在,不需要插入 _context.Attach(ProfileSocialMedia.SocialMediaTypes); } var addedEntity = await _context.SocialMediaUrls.AddAsync(ProfileSocialMedia); await _context.SaveChangesAsync();
内容的提问来源于stack exchange,提问作者Dave Koppe
相关产品推荐
相关产品推荐

