Entity Framework 新增記錄時關聯表資料重複新增
阿新 • • 發佈:2020-10-05
1.問題還原:有一張User表和School表,關係是一對多,在新增一個User的時候,都建立一條School記錄。
表結構
public class UserDto : BaseDto { /// <summary> /// 登入賬號 /// </summary> public string LoginName { get; set; } [DisplayName("密碼*"), Required, StringLength(20, MinimumLength = 5, ErrorMessage = "長度在5-20個字元之間")] public string Password { get; set; } [DisplayName("真實姓名")] public string RealName { get; set; } [DisplayName("所屬學校Id")] public int? SchoolId { get; set; } [DisplayName("所屬學校")] public SchoolDto School { get; set; } }public class SchoolDto:BaseDto { public string SchoolName { get; set; } public string SchoolNo { get; set; } public List<UserDto> Users { get; set; } } //外來鍵關係建立 public class UserConfig:EntityTypeConfiguration<UserEntity> { /// <summary>/// 使用者表配置 /// </summary> public UserConfig() { ToTable("user"); HasKey(item => item.Id); Property(item => item.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); HasOptional(item => item.School).WithMany(item => item.Users).HasForeignKey(item => item.SchoolId); } }
封裝的方法
School的GetOne的獲取方法
/// <summary> /// 獲取單條符合條件的 school 資料 /// </summary> /// <param name="exp">條件表示式</param> /// <returns></returns> public SchoolDto GetOne(Expression<Func<SchoolDto, bool>> exp) { using (var scope = _dbScopeFactory.CreateReadOnly()) { var db = GetDb(scope); var dbSet = GetDbSet(db); var where = exp.Cast<SchoolDto, SchoolEntity, bool>(); //var entity = dbSet.AsNoTracking().FirstOrDefault(where); var entity = dbSet.FirstOrDefault(where); return AutoMapperProfile.ExamMapper.Map<SchoolEntity, SchoolDto>(entity); } }
User的Add方法
public int Add(UserDto dto) { using (var scope = _dbScopeFactory.Create()) { var db = GetDb(scope); var dbSet = GetDbSet(db); var entity = AutoMapperProfile.ExamMapper.Map<UserEntity>(dto); //dbSet.Attach(entity);建議用這種方式,可以把 entity 和entity關聯的物件都加入跟蹤 //var adapter = scope.DbContexts.Get<CorrectingExamPaper.Data.ExamPaperContext>()
// as System.Data.Entity.Infrastructure.IObjectContextAdapter; //adapter.ObjectContext.AttachTo("Schools", entity.School); dbSet.Attach(entity); dbSet.Add(entity); scope.SaveChanges(); return entity.Id; } }
測試程式碼:
UserService userService = new UserService(); ISchoolService schoolService = new SchoolService(); [TestMethod] public void AddOneUserTest() { SchoolDto school = schoolService.GetOne(item => item.Id == 3); UserDto userdto1 = new UserDto() { //Id=1, LoginName = "asuzhou111" + new Random(2).Next(1, 1000), Password = "1234226", RealName = "t4", School = school, SchoolId = school.Id }; userService.Add(userdto1); }
如果出現新增User,總是新增關聯外表School記錄的情況,請確認兩點:
1.Add時候的Context 和GetOne的時候的Context是否是同一個;
2.Get出來的school是否在Add時候的Context的跟蹤管理狀態;
dbSet.Attach(entity);這句話可以把entity.School物件也能跟蹤到,就不會出現新增User,同時也新增School的情況了。
此方法同樣適用與多對多;
如果是一對多關係在User的Add方法中加這句也可以解決此問題,但是下面方法不適用與多對多
//dbSet.Attach(entity);建議用這種方式,可以把 entity 和entity關聯的物件都加入跟蹤
//var adapter = scope.DbContexts.Get<CorrectingExamPaper.Data.ExamPaperContext>()
// as System.Data.Entity.Infrastructure.IObjectContextAdapter;