20

好きなユーザーのコレクションを持つことができるユーザーがいます...

別のユーザーは、好きなユーザーのコレクションを持つことができます....

ユーザー A がユーザー B を好きで、ユーザー B がユーザー A を好きなら、彼らはたむろするようになります。連絡先情報をお互いに送信する必要があります。このようなモデルを Entity Framework Code First で表現するにはどうすればよいでしょうか?

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

    public int? UserLikeId { get; set; }
    public virtual UserLike UserLike { get; set; }
}

public class UserLike
{
    public int UserLikeId { get; set; }

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

    public virtual ICollection<User> LikeUsers { get; set; }
}

このモデルは正しいですか?私はこれを機能させることができません。

私は別の方法を試しましたが、それもうまくいきません...

ユーザーのコレクションをユーザーテーブルに追加しようとしました。

例:

public virtual ICollection<User> userlike { get; set; }

public class User
{
    public int UserId { get; set; }
    public virtual ICollection<UserLike> UserLikes { get; set; }
}

public class UserLike
{
    public int UserLikeId { get; set; }

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

    public int LikeUserId { get; set; }
    public virtual User LikeUser { get; set; }
}

ユーザーと好きな人を追加しようとすると、このエラーが発生します。

関係「UserLike_LikeUser」のロール「UserLike_LikeUser_Target」に対する競合する変更が検出されました。

そのようなモデルを表現する最良の方法は何ですか?

4

1 に答える 1

26

リレーションシップを記述するために別のエンティティは実際には必要ありません。以下のオブジェクト モデルでうまくいきます。

public class User
{
    public int UserId { get; set; }
    public string Name { get; set; }

    public int? ThisUserLikesId { get; set; }
    public virtual User ThisUserLikes { get; set; }
    public virtual ICollection<User> LikeThisUser { get; set; }
}

public class Context : DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
                    .HasOptional(u => u.ThisUserLikes)
                    .WithMany(u => u.LikeThisUser)
                    .HasForeignKey(u => u.ThisUserLikesId);
    }
}

ここで、手元に UserId があり、このユーザーが好きな他のユーザーを見つけたいとします。このユーザーも彼を好きです。

using (var context = new Context())
{
    // For a given user id = 1
    var friends = (from u in context.Users
                   where u.UserId == 1
                   from v in u.LikeThisUser
                   where v.UserId == u.ThisUserLikesId
                   select new 
                   { 
                       OurUser = u, 
                       HerFriend = v 
                   })
                   .SingleOrDefault();

    ExchangeContactInfo(friends.OurUser, friends.HerFriend);
}                


更新 1:

自己参照型の多対多の関連付けは、結合テーブルを使用してデータベースにマップされます。これには、異なるオブジェクト モデルと流暢な API が必要です。

public class User
{
    public int UserId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<User> ThisUserLikes { get; set; }
    public virtual ICollection<User> UsersLikeThisUser { get; set; }
}

public class Context : DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
                    .HasMany(u => u.ThisUserLikes)
                    .WithMany(u => u.UsersLikeThisUser)
                    .Map(c => 
                    {
                        c.MapLeftKey("UserId");
                        c.MapRightKey("OtherUserId");
                        c.ToTable("UserLikes");
                    });
    }
}


更新 2:

この投稿で説明したように、多対多の関連付けにはペイロード (EventId など) を含めることはできません。その場合は、介在するクラスへの 2 つの 1 対多の関連付けに分割する必要があります。このクラス (UserLike) を正しく作成して、自己参照多対多関連付けに付加された追加情報を表していることがわかりますが、正確に 2 つの多対 1 を定義する必要があるため、この中間クラスからの関連付けは正しくありません。次のオブジェクト モデルで示したように、UserLike から User への関連付け:

public class User
{        
    public int UserId { get; set; }
    public string Email { get; set; }       

    public virtual ICollection ThisUserLikes { get; set; }
    public virtual ICollection UsersLikeThisUser { get; set; }
}       

public class UserLike
{
    public int UserLikeId { get; set; }
    public int LikerId { get; set; }
    public int LikeeId { get; set; }
    public int EventId { get; set; }

    public User Liker { get; set; }
    public User Likee { get; set; }
    public virtual Event Event { get; set; }
}

public class Event
{
    public int EventId { get; set; }
    public string Name { get; set; }
}  

public class Context : DbContext 
{
    public DbSet Users { get; set; } 
    public DbSet Events { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
                    .HasMany(u => u.ThisUserLikes)
                    .WithRequired(ul => ul.Liker)
                    .HasForeignKey(ul => ul.LikerId);
        modelBuilder.Entity()                        
                    .HasMany(u => u.UsersLikeThisUser)
                    .WithRequired(ul => ul.Likee)
                    .HasForeignKey(ul => ul.LikeeId)
                    .WillCascadeOnDelete(false);
    }
}

これで、次の LINQ クエリを使用して、お互いが好きなすべてのユーザーを取得できます。

using (var context = new Context())
{                
    var friends = (from u1 in context.Users
                   from likers in u1.UsersLikeThisUser
                   from u2 in u1.ThisUserLikes 
                   where u2.LikeeId == likers.LikerId
                   select new
                   {
                       OurUser = u1.UserId,
                       HerFriend = u2.LikeeId 
                   })
                   .ToList();
}

お役に立てれば。

于 2011-06-17T14:16:02.890 に答える