0

流暢なAPIでEFコードファーストアプローチを使用しています。アプリケーションに 1 つの登録フォームがあり、候補者を登録する際に、事前定義された一連のオプションを持つドロップダウン (サインアップ フォームのドロップダウンに興味がある) から複数のオプションを選択できます (将来的に増加する可能性がありますが、可能性は非常にまれです)。ユーザーがフォームを送信すると、このレコードをデータベースに保存したいと思います。そこで、次のエンティティを作成しました。

参加者 登録候補者情報が保存されるクラス

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; }
}

サインアップ フォームの [Interested In] ドロップダウンが入力されるインタレスト クラスユーザーは [Interested In] ドロップダウンから複数のオプションを選択できます

インタレストクラス

 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; private set; }
    }

各参加者の関心を保持するために、次のスキーマを使用して DB に ParticipantInterests テーブルを作成しました。ParticipantInterests Id (PK) ParticipantId (参加者テーブルからの FK) InterestId (FK 興味テーブル)

パブリック仮想 ICollection 参加者 { get; を追加しました。設定; インタレストモデルと

public virtual ICollection Interests { get; 設定; } 参加者モデルで多対多の関連付けを形成します。 私のデータコンテキストクラスは次のとおりです

public class STNDataContext : DbContext
    {
        public DbSet<Participant> Participants { get; set; }
        public DbSet<User> Users { 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>()
                .HasKey(p => p.Id);

            modelBuilder.Entity<User>()
                .HasOptional(u => u.Participant)
                .WithRequired();

            modelBuilder.Entity<Participant>()
            .HasMany(p => p.Interests)
            .WithMany(i => i.Participants)
            .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<User>().HasOptional(u => u.SecurityQuestion);
        }


        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;
                    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);
        }

参加者リポジトリ (DAL)

 public class ParticipantRepository : Repository<Participant>, IParticipantRepository 
    {
        public ParticipantRepository(IDatabaseFactory databaseFactory)
            : base(databaseFactory)
        {
        }
    }

参加者サービス (BLL)

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();
    }

}

参加者を作成しようとすると、次のエラーが発生します。

値 NULL を列 'InterestName'、テーブル 'StudyTourNetworkDB.dbo.Interests' に挿入できません。列はヌルを許可しません。INSERT が失敗しました。\r\nステートメントは終了しました。

理想的には、私の考えでは、参加者テーブルに参加者情報を挿入し、参加者インタレストテーブルに参加者の関心を挿入する必要があります。しかし、Interests テーブルにもレコードを挿入しようとしていますが、これは起こるべきではありません。この問題の解決を手伝ってください。多対多の関連付けを作成することで間違っている可能性があります。

ありがとう

注 : Interests コレクションがコンテキストに追加/アタッチされないため、問題は理解できましたが、リポジトリ パターンと作業単位を使用して Interest コレクションを同じコンテキストに追加する方法がわかりませんでした。

解決策を教えてください。前もって感謝します

4

1 に答える 1

0

You are correct in that your Interest objects are being re-added, because the copies held in your model are not being tracked by EF and therefore it thinks they are new. Instead, you will need to look up the versions from your repository, and add those instead.

Instead of:

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;

Try something like:

// 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;

Note that with a many-to-many relationship, you don't need to set both sides - in your example you were filling in the Participant field of the Interest entity - this will be set automatically by EF since you're adding it to the Interests property of the Participant.

于 2012-12-10T08:35:19.447 に答える