Entity Framework 4.1 Сначала создайте самоссылающиеся ассоциации "Один ко многим" и "Многие ко многим"
Вопрос
У меня есть Пользователь, у которого может быть коллекция пользователей, которые ему нравятся...
У другого пользователя может быть коллекция пользователей, которые ему нравятся....
Если Пользователю A нравится Пользователь B, и если Пользователю B нравится Пользователь A, то они могут пообщаться.Мне нужно отправить друг другу их контактную информацию.Как нам сначала представить такую модель в коде Entity Framework?
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; }
}
Верна ли эта модель?Я не могу заставить это сработать.
Я пробовал другой способ, но и он не сработал...
Я попытался добавить коллекцию user в таблицу user.
Для бывших :
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_Target' отношения 'UserLike_LikeUser'.
Каков наилучший способ представить такую модель?
Решение
На самом деле вам не нужна отдельная сущность для описания взаимосвязи, приведенная ниже объектная модель сделает свое дело:
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);
}
}
Теперь предположим, что у вас на руках есть идентификатор пользователя и вы хотите найти другого пользователя, которому нравится этот пользователь, которому он также нравится:
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), и если это так, то мы должны разбить ее на две ассоциации "один ко многим" для промежуточного класса, и я вижу, что вы правильно создали этот класс (UserLike) для представления дополнительной информации, прикрепленной к вашей самоссылающейся ассоциации "многие ко многим", но ассоциации из этого промежуточного класса неверны, поскольку нам нужно определить ровно 2 ассоциации "многие к одному" от 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();
}
Надеюсь, это поможет.