2

私はCodeFirstを初めて使用し、2人のユーザーが友達コレクションにお互いを持つことができるように友達コレクションを作成しようとしています。

これが私のユーザークラスです:

public class User
{
    public User()
    {
        if (FriendCollection == null) FriendCollection = new Collection<Friend>();
    }
    public long ID { get; set; }
    public virtual ICollection<Friend> FriendCollection { get; set; }
}

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {
        HasKey(x => x.ID);
    }
}

これが私の友達クラスです:

public class Friend
{
    public Friend()
    {
        DateAdded = DateTime.UtcNow;
    }
    public long ID { get; set; }
    public DateTime DateAdded { get; set; }
    public long UserID { get; set; }
    public virtual User User { get; set; }
}

public class FriendConfiguration : EntityTypeConfiguration<Friend>
{
    public FriendConfiguration()
    {
        HasKey(x => x.ID);
        HasRequired(x => x.User).WithMany(x => x.FriendCollection).HasForeignKey(x => x.UserID);
    }
}

これが私のエンティティクラスです:

    public Entities()
    {
        Database.SetInitializer<Entities>(new DropCreateDatabaseAlways<Entities>());
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Friend> Friends { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new UserConfiguration());
        modelBuilder.Configurations.Add(new FriendConfiguration());

        base.OnModelCreating(modelBuilder);
    }
}

そして、これが私のコンソールコードであり、理想的には私が達成したいことです。

        using (Entities db = new Entities ())
        {
            var u1 = new User();
            db.Users.Add(u1);

            var u2 = new User();
            db.Users.Add(u2);

            u1.FriendCollection.Add(new Friend { User = u2 });
            u2.FriendCollection.Add(new Friend { User = u1 });

            try
            {
                var cnt = db.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                    }
                }
            }

SaveChangesは、FriendクラスにUserオブジェクトを入力しようとすると、次のようなエラーをスローします。

多重度制約に違反しました。リレーションシップ「Entities.Friend_User」のロール「Friend_User_Target」の多重度は1または0..1です。

このようにUserIDに割り当てる場合:

u1.FriendCollection.Add(new Friend {UserID = u2.ID});

これにより、エンティティを保存できますが、正しくは保存できません。

コードをステップスルーすると、問題を特定できます。これが私が見つけたものです。

b.FriendCollection.Add(new Friend { UserID = a.ID });
//Friend.UserID = 1
db.SaveChanges();
//Friend.UserID = 2 matching the b.ID

これで、Friend.Userを呼び出し元のUserに割り当てた場合、エラーをスローせずに前の例とSaveChanges()に戻ることができます。例えば:

b.FriendCollection.Add(new Friend { User = b }); 
db.SaveChanges()

しかし、別のユーザーを割り当てようとすると、エラーが発生します。例えば:

b.FriendCollection.Add(new Friend { User = a }); 
db.SaveChanges()

私は得る:

多重度制約に違反しました。リレーションシップ「Entities.Friend_User」のロール「Friend_User_Target」の多重度は1または0..1です。

(FluentAPIを使用して)モデルを修正して、User.FriendCollectionに別のユーザーを割り当てる方法を教えてもらえますか?

4

1 に答える 1

0

マッピングが正しくありません。少なくとも、モデル内の関係の意味については正しくありません。

マッピングは、1 つのリレーションシップと 2 つのナビゲーション プロパティを作成しUser.FriendCollectionFriend.Userこの 1 つのリレーションシップの両端です。それらを逆プロパティとして定義しました。

ただし、これは、FriendB に FriendB を持つユーザー UserA がいる場合、その FriendB はFriendCollectionUserAUserでなければならず、他のユーザーではないことを意味します。あなたのモデルは、ユーザーがいわば自分の友達であることしか表現できません。コレクションに別のユーザーを追加しているため、例外が発生します。

私の意見では、エンティティFriendは友人=別のユーザーを表していませんが、実際には関係を表しています。これは、ユーザー間の多対多の関係の中間エンティティのようなものであり、この関係はFriendship(私はこのように呼びたいと思います)。

いずれにせよ、モデルには 2 つの関係が必要です。エンティティをそのままにしておくことができますが、次のマッピングを使用します。

public class UserConfiguration : EntityTypeConfiguration<User>
{
    public UserConfiguration()
    {
        HasKey(x => x.ID);
        HasMany(x => x.FriendCollection)
            .WithRequired();
    }
}

public class FriendConfiguration : EntityTypeConfiguration<Friend>
{
    public FriendConfiguration()
    {
        HasKey(x => x.ID);
        HasRequired(x => x.User)
            .WithMany()
            .HasForeignKey(x => x.UserID)
            .WillCascadeOnDelete(false);
    }
}

(悪名高い「複数のカスケード削除パス例外」を回避するには、リレーションシップの 1 つでカスケード削除を無効にする必要があります。)

2 番目と1 番目のマッピング用に、Friendテーブルに2 つの外部キーがあることに注意してください。最初のマッピングに追加することで、デフォルトの列名を変更できます。UserIDUser_IDMap(m => m.MapKey("SomeUserID"))

このマッピングにより、コンソール コードが機能するはずです。

于 2012-03-14T22:34:40.580 に答える