1. 程式人生 > 實用技巧 >Entity Framework 新增記錄時關聯表資料重複新增

Entity Framework 新增記錄時關聯表資料重複新增

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;