Asp.net mvc 多对多实体框架和存储库模式插入/更新
我正在使用EF代码优先的方法和fluent api。我在我的申请表中有一个登记表,在登记表中,候选人可以从下拉列表中选择多个选项(对登记表上的下拉列表感兴趣),其中有一组预定义的选项(将来可能会增加,但机会非常少)。当用户提交表单时,我想将这些记录保存到数据库中。所以我创建了以下实体 保存注册候选人信息的参与者类Asp.net mvc 多对多实体框架和存储库模式插入/更新,asp.net-mvc,entity-framework,ef-code-first,many-to-many,repository-pattern,Asp.net Mvc,Entity Framework,Ef Code First,Many To Many,Repository Pattern,我正在使用EF代码优先的方法和fluent api。我在我的申请表中有一个登记表,在登记表中,候选人可以从下拉列表中选择多个选项(对登记表上的下拉列表感兴趣),其中有一组预定义的选项(将来可能会增加,但机会非常少)。当用户提交表单时,我想将这些记录保存到数据库中。所以我创建了以下实体 保存注册候选人信息的参与者类 public class Participant { public Participant() { Interests
public class Participant
{
public Participant()
{
Interests = new Collection<Interest>();
}
[Key, ForeignKey("User")]
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 virtual User User { get; set; }
public virtual ICollection<Interest> Interests { get; set; }
public string MedicalConditions { get; set; }
}
数据库工厂
public class DatabaseFactory : Disposable, IDatabaseFactory
{
private STNDataContext _stnDataContext;
public DatabaseFactory()
{
Database.SetInitializer<STNDataContext>(null);
}
public STNDataContext Get()
{
return _stnDataContext ?? (_stnDataContext = new STNDataContext());
}
protected override void DisposeCore()
{
if (_stnDataContext != null)
_stnDataContext.Dispose();
}
}
当我尝试创建参与者时,我得到以下错误
无法将值NULL插入表“StudyTourNetworkDB.dbo.Interests”的列“InterestName”;列不允许空值。INSERT失败。\r\n语句已终止
理想情况下,按照我的想法,它应该在参与者表中插入参与者信息,并在参与者列表中插入参与者兴趣。但它正试图在兴趣表中插入记录,这是不应该发生的。请帮我解决这个问题。我创建多对多协会可能是做错了
谢谢
注意:我可以理解这个问题,因为兴趣集合没有添加/附加到上下文中,但我无法找到如何使用存储库模式和工作单元将兴趣集合添加到同一上下文中。
请给我提供解决方案。提前感谢您的兴趣对象正在被重新添加,这是正确的,因为EF没有跟踪模型中保存的副本,因此认为它们是新的。相反,您需要从存储库中查找版本,然后添加这些版本 而不是:
var interests = new List<Interest>();
foreach (var interestItem in studentRegisterViewModel.SelectedInterests)
{
var interest = new Interest { Id = interestItem };
interest.Participants.Add(studentRegisterViewModel.Participant);
interests.Add(interest);
studentRegisterViewModel.Participant.Interests.Add(interest);
}
studentRegisterViewModel.Participant.Interests = interests;
请注意,对于多对多关系,您不需要设置双方-在您的示例中,您填写的是兴趣实体的参与者字段-这将由EF自动设置,因为您将其添加到参与者的兴趣属性中。请将您的代码减少到最低限度。你的问题被淹没在一堵文字墙中。嘿,谢谢你的快速回答。现在我得到了这个错误。一个实体对象不能被多个IEntityChangeTrackerHey的实例引用。谢谢你的回答。您的解决方案可以工作,但它现在给了我这个错误一个实体对象不能被多个IEntityChangeTracker实例引用。任何解决办法。再次感谢像您的存储库使用单独的DBContext这样的工具-工作单元应该在它们之间共享,以便它们的实体来自相同的上下文。很抱歉,Richards仍然无法找到解决此问题的方法。你能帮忙吗?
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;
var interests = new List<Interest>();
foreach (var interestItem in studentRegisterViewModel.SelectedInterests)
{
var interest = new Interest { Id = interestItem };
interest.Participants.Add(studentRegisterViewModel.Participant);
interests.Add(interest);
studentRegisterViewModel.Participant.Interests.Add(interest);
}
studentRegisterViewModel.Participant.Interests = interests;
_participantService.CreatParticipant(studentRegisterViewModel.Participant);
var user = _userService.GetUser(studentRegisterViewModel.Participant.User.Username);
}
}
studentRegisterViewModel.Gender =
Enum.GetNames(typeof(Gender)).Select(
x => new KeyValuePair<string, string>(x, x.ToString(CultureInfo.InvariantCulture)));
studentRegisterViewModel.Interests = _interestService.GetAllInterests();
return View(studentRegisterViewModel);
}
public class ParticipantRepository : Repository<Participant>, IParticipantRepository
{
public ParticipantRepository(IDatabaseFactory databaseFactory)
: base(databaseFactory)
{
}
}
public class ParticipantService : IParticipantService
{
private readonly IParticipantRepository _participantRepository;
private readonly IUnitOfWork _unitOfWork;
public ParticipantService(IParticipantRepository participantRepository, IUnitOfWork unitOfWork)
{
this._participantRepository = participantRepository;
this._unitOfWork = unitOfWork;
}
public void CreatParticipant(Participant participant)
{
_participantRepository.Add(participant);
_unitOfWork.Commit();
}
}
public class DatabaseFactory : Disposable, IDatabaseFactory
{
private STNDataContext _stnDataContext;
public DatabaseFactory()
{
Database.SetInitializer<STNDataContext>(null);
}
public STNDataContext Get()
{
return _stnDataContext ?? (_stnDataContext = new STNDataContext());
}
protected override void DisposeCore()
{
if (_stnDataContext != null)
_stnDataContext.Dispose();
}
}
public class UniOfWork : IUnitOfWork
{
private readonly IDatabaseFactory _databaseFactory;
private STNDataContext _stnDataContext;
public UniOfWork(IDatabaseFactory databaseFactory)
{
this._databaseFactory = databaseFactory;
}
public STNDataContext StnDataContext
{
get { return _stnDataContext ?? (_stnDataContext = _databaseFactory.Get()); }
}
public void Commit()
{
StnDataContext.Commit();
}
}
var interests = new List<Interest>();
foreach (var interestItem in studentRegisterViewModel.SelectedInterests)
{
var interest = new Interest { Id = interestItem };
interest.Participants.Add(studentRegisterViewModel.Participant);
interests.Add(interest);
studentRegisterViewModel.Participant.Interests.Add(interest);
}
studentRegisterViewModel.Participant.Interests = interests;
// Look up the actual EF entities which match your selected items. You'll
// probably need to adapt this to make it work
var selectedInterestIds = studentRegisterViewModel.SelectedInterests.Select(i => i.Id);
var interests = _interestService.GetAllInterests().Where(i => selectedInterestIds.Contains(i.Id));
studentRegisterViewModel.Participant.Interests = interests;