【问题标题】:Entity Framework Code First Many to many Insert实体框架代码优先多对多插入
【发布时间】:2012-12-06 17:00:32
【问题描述】:

我正在使用 EF 代码优先方法和流利的 api。我的申请中有一个注册表单,在其中注册候选人可以从下拉列表中选择多个选项(对注册表单上的下拉列表感兴趣),其中包含一组预定义的选项(将来可能会增加,但机会非常少)。当用户提交表单时,我想将此记录保存到数据库中。所以我创建了以下实体。

将保存注册候选人信息的参与者类

public class Participant
    {
        public Participant()
        {
            Interests = new Collection<Interest>();
        }
        [Key]
        public int Id { get; set; }
        [DisplayName("First Name")]
        [StringLength(50, ErrorMessage = "First name cannot be more than 50 characters")]
        [Required(ErrorMessage = "You must fill in first name")]
        public string FirstName { get; set; }

        [DisplayName("Last Name")]
        [StringLength(50, ErrorMessage = "Last name cannot be more than 50 characters")]
        [Required(ErrorMessage = "You must fill in last name")]
        public string LastName { get; set; }

        [Required(ErrorMessage = "You must indicate your full birthday")]
        [DisplayName("Birthday")]
        [DataType(DataType.DateTime)]
        public DateTime BirthDate { get; set; }

        [DisplayName("Gender")]
        [Required(ErrorMessage = "You must select gender")]
        public int Gender { get; set; }

        public string Address { get; set; }

        public int CountryId { get; set; }
        public Country Country { get; set; }

        [DisplayName("Zip code")]
        [StringLength(10, ErrorMessage = "Zip code cannot be more than 10 characters")]
        public string ZipCode { get; set; }

        public string Mobile { get; set; }

        public string PhotoUrl { get; set; }

        public int UserId { get; set; }
        public User User { get; set; }

        public virtual ICollection<Interest> Interests { get; set; }
}

注册表单上的“感兴趣”下拉菜单将被填充的兴趣类 *用户可以从“感兴趣”下拉列表中选择多个选项*

public class Interest
    {
        public Interest()
        {
            Participants = new Collection<Participant>();
        }
        public int Id { get; set; }
        public string InterestName { get; set; }
        public virtual ICollection<Participant> Participants { get; set; }
    }

为了保持每个参与者的兴趣,我在 DB 中创建了一个具有以下架构的 ParticipantInterests 表。 参与者兴趣 身份证号(PK) ParticipantId(来自 Participants 表的 FK) InterestId(外键兴趣表)

我在兴趣模型中添加了public virtual ICollection&lt;Participant&gt; Participants { get; set; }

public virtual ICollection<Interest> Interests { get; set; } in Participant model to form Many-To-Many association.

我的数据上下文类如下

public class STNDataContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Participant> Participants { get; set; }
        public DbSet<Country> Countries { get; set; }
        public DbSet<Interest> Interests { get; set; }
        public DbSet<Role> Roles { get; set; }
        public DbSet<SecurityQuestion> SecurityQuestions { get; set; }

        public DbSet<Tour> Tours { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Participant>().
                HasMany(p => p.Interests).
                WithMany().
                Map(
                    m =>
                    {
                        m.ToTable("ParticipantInterests");
                        m.MapLeftKey("ParticipantId");
                        m.MapRightKey("InterestId");
                    });
            modelBuilder.Entity<User>().HasRequired(u => u.Role);
            modelBuilder.Entity<Participant>().HasRequired(p => p.Country);
            modelBuilder.Entity<Participant>().HasRequired(p => p.Interests);
        }


        public virtual void Commit()
        {
            base.SaveChanges();
        }
    }

控制器操作代码

public virtual ActionResult Register(StudentRegisterViewModel studentRegisterViewModel)
        {
if (ModelState.IsValid)
            {
                if (_userService.IsUserExists(studentRegisterViewModel.Participant.User) == false)
                {
                    studentRegisterViewModel.Participant.User.Username = studentRegisterViewModel.Username;
                    studentRegisterViewModel.Participant.User.Email = studentRegisterViewModel.Email;
                    studentRegisterViewModel.Participant.User.DateCreated = DateTime.Now;
                    studentRegisterViewModel.Participant.User.Id = 3;
                    studentRegisterViewModel.Participant.User.IsApproved = false;
                    studentRegisterViewModel.Participant.User.RoleId = 2;
                    studentRegisterViewModel.Participant.CountryId = 1;
                    foreach (var interestItem in studentRegisterViewModel.SelectedInterests)
                    {
                        var interest = new Interest { Id = interestItem};
                        studentRegisterViewModel.Participant.Interests.Add(interest);
                    }

                    _participantService.CreatParticipant(studentRegisterViewModel.Participant);

                }
            }


            studentRegisterViewModel.Gender =
                Enum.GetNames(typeof(Gender)).Select(
                    x => new KeyValuePair<string, string>(x, x.ToString(CultureInfo.InvariantCulture)));
            studentRegisterViewModel.Interests = _interestService.GetAllInterests();
            return View(studentRegisterViewModel);
        }

当我尝试创建参与者时,我收到以下错误。 {"无法将值 NULL 插入到列 'InterestName'、表 'StudyTourNetworkDB.dbo.Interests';列不允许空值。INSERT 失败。\r\n语句已终止。"}

理想情况下,根据我的想法,它应该在 Participants 表中插入 Participant Information 并在 ParticipantsInterests 表中插入 Participants Interests。但它也试图在兴趣表中插入记录,这也不应该发生。请帮我解决这个问题。创建多对多关联可能是我做错了。

谢谢

【问题讨论】:

    标签: asp.net-mvc entity-framework many-to-many poco


    【解决方案1】:
    • ParticipantInterests 表中删除Id 列,并使ParticipantIdInterestId 成为复合主键。将它们保留为外键。

    • 将多对多映射更改为...

      //...
      HasMany(p => p.Interests).
      WithMany(i => i.Participants).
      //...
      

      ...并删除此映射线:

      modelBuilder.Entity<Participant>().HasRequired(p => p.Interests);
      
    • 将兴趣附加到上下文以避免 EF 尝试插入它:

      foreach (var interestItem in studentRegisterViewModel.SelectedInterests)
      {
          var interest = new Interest { Id = interestItem};
          context.Interests.Attach(interest);
          studentRegisterViewModel.Participant.Interests.Add(interest);
      }
      

      您必须将与上下文相关联的行带入您的服务类。我猜你的控制器中没有context。但希望你能明白。

    【讨论】:

    • 非常感谢您的快速回答。我还没有尝试过,但很快就会告诉你。感谢您的快速回复。
    • 是的,你完全正确。我在控制器中没有上下文,因为我正在使用存储库模式和工作单元模式。你能建议在这种情况下如何处理它吗?谢谢
    • 这是我的 ParticipantService ,然后是参与者存储库 public void CreatParticipant(Participant 参与者) { _participantRepository.Add(participant); _unitOfWork.Commit(); }
    • 私有STNDataContext _stnDataContext;私有只读 IDbSet _dbSet; protected Repository(IDatabaseFactory databaseFactory) { DatabaseFactory = databaseFactory; _dbSet = StnDataContext.Set(); } 受保护的 IDatabaseFactory 数据库工厂 { 获取;私人套装; } 公共 STNDataContext StnDataContext { 获取 { 返回 _stnDataContext ?? (_stnDataContext = new STNDataContext()); } } public void Add(T entity) { _dbSet.Add(entity); _stnDataContext.Commit(); }
    猜你喜欢
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多