Frame de l'entité 4.1 Code Premier auto-référence One-to-plusieurs et plusieurs associations
Question
J'ai un utilisateur qui peut avoir une collection d'utilisateurs qu'il aime ...
Un autre utilisateur peut avoir une collection d'utilisateurs qu'il aime ...
Si l'utilisateur A aime l'utilisateur B et si l'utilisateur B aime l'utilisateur A, il peut passer du temps. J'ai besoin de vous envoyer leurs coordonnées. Comment représenter d'abord un tel modèle dans le code Framework Entity?
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; }
}
Ce modèle est-il correct? Je ne peux pas faire fonctionner cela.
J'ai essayé une autre façon mais cela ne fonctionne pas aussi ...
J'ai essayé d'ajouter une collection d'utilisateurs à la table utilisateur.
Pour ex:
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; }
}
J'obtiens cette erreur lorsque j'essaie d'ajouter l'utilisateur et qui ils aiment:
Des modifications contradictoires du rôle «userlike_likeuser_target» de la relation «userlike_likeuser» ont été détectées.
Quelle est la meilleure façon de représenter un tel modèle?
La solution
Vous n'avez pas vraiment besoin d'une entité distincte pour décrire la relation, le modèle d'objet ci-dessous fera l'affaire:
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);
}
}
Disons maintenant que vous avez un utilisateur dans votre main et que vous souhaitez trouver l'autre utilisateur qui aime cet utilisateur que cet utilisateur l'aime également:
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);
}
Mise à jour 1:
Une association de plusieurs à plusieurs références sera cartographiée à la base de données à l'aide d'une table de jointure qui nécessite un modèle d'objet différent et une API fluide:
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");
});
}
}
Mise à jour 2:
Comme je l'ai expliqué dans ce post, une association de plusieurs à plusieurs ne peut pas avoir de charge utile (par exemple eventID), et si c'est le cas, nous devons le décomposer à deux associations un à plusieurs avec une classe intermédiaire et je peux voir que vous avez correctement créé Cette classe (comme l'utilisateur) représente les informations supplémentaires attachées à votre association auto-référencée de plusieurs à plusieurs, mais les associations de cette classe intermédiaire ne sont pas correctes car nous devons définir exactement 2 associations de plusieurs à un, de l'utilisateur à l'utilisateur comme J'ai montré dans le modèle d'objet suivant:
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);
}
}
Vous pouvez maintenant utiliser la requête LINQ suivante pour récupérer tous les utilisateurs qui s'aiment:
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();
}
J'espère que cela t'aides.