J'ave structure de table comme ça
la description:
utilisateur a de nombreux profils utilisateur, la table user_profile joint les tables utilisateur et profil (il existe une relation multiple à utilisateur entre l'utilisateur et la table de profil).
utilisateur> un-à-plusieurs> user_profiles> un-à-un> profils
utilisateur> plusieurs profils d'utilisateurs> un profil
Problème:
Comment puis-je sélectionner un utilisateur avec un profil en utilisant linq.
échantillon:
var user=cbContext.user.include("user_profiles").include("profiles").Where(predicate).FirstOrDefault();
Trouvé la réponse
dbContext.Users
.Include(user => user.UserProfiles)
.ThenInclude(userProfiles => userProfiles.Profile)
.Where(predicate)
.FirstOrDefault();
Si vous avez une structure d'entité complète, le plusieurs-plusieurs est similaire à:
class User
{
public int Id {get; set;}
// every User has zero or more Profiles (many-to-many)
public virtual ICollection<Profile> Profiles {get; set;}
...
}
class Profile
{
public int Id {get; set;}
// every Profile belongs to zero or more Users (many-to-many)
public virtual ICollection<User> Userss {get; set;}
...
}
Si vos classes sont conçues comme cela et que vous voulez des "utilisateurs ... avec leurs profils", vous pouvez utiliser les collections et sélectionner les propriétés que vous prévoyez d'utiliser:
using (var dbContext = new MyDbContext(...))
{
var requestedUsers = dbContext.Users
.Where(user => ...) // only if you don't want all Users
.Select(user => new
{ // Select only the properties you plan to use:
Id = user.Id,
Name = user.Name,
...
Profiles = user.Profiles
.Where(profile => ...) // only if you don't want all profiles
.Select(profile => new
{
Name = profile.Name,
...
})
.ToList(),
})
L'une des parties les plus lentes d'une requête de base de données est le transport des données sélectionnées du système de gestion de base de données vers votre processus. Il est donc sage de limiter les données que vous transférez aux données que vous prévoyez d'utiliser.
Include
sélectionnera toutes les propriétés de l'objet inclus, y compris les clés primaires et étrangères. Include a Collection
sélectionnera la collection complète, même si vous prévoyez n'en utiliser que quelques-uns.
Conseil: utilisez uniquement
Include
si vous envisagez de modifier les données extraites. UtiliserSelect
est plus rapide.Select
uniquement les propriétés que vous comptez réellement utiliser
Utiliser (Groupe) Rejoindre si vous ne pouvez pas utiliser ICollection
J'ai compris de certains que vous ne pouvez pas utiliser le virtual ICollections
lorsque vous utilisez EF-core. Dans ce cas, vous devrez effectuer un groupeJoin vous-même
dbContext.Users
.Where(user => ...)
.GroupJoin(dbContext.UserProfiles, // GroupJoin the users with the UserProfiles
user => user.Id // from every user take the Id
userProfile => userProfile.UserId, // from every userProfile take the UserId
(user, userProfiles) => new // when thay match,
{ // take the user and its matching UserProfiles
UserId = user.Id, // again: select only properties you plan to use
UserName = user.Name,
...
// for the Profiles, do a new Join with the Profiles
Profiles = userProfiles.Join(dbContext.Profiles, // join with Profiles
userProfile => userProfile => profileId // from the userProfile take profileId
profile => profile.Id, // from the Profile take the Id
(userProfile, profile) => new // when they match, make an object
{ // again: use only properties you plan to use
ProfileId = profile.Id,
ProfileName = profile.Name,
...
})
.ToList(),
});
Attention: vous n'obtiendrez pas d'utilisateurs sans profils!
C'est une jointure interne.
Si vous souhaitez également des utilisateurs sans profils, utilisez Left-Outer-GroupJoin comme décrit ici dans Stackoverflow Faites défiler l'écran vers le bas pour obtenir la réponse la mieux classée, ce qui est bien meilleur que la réponse sélectionnée.
Outre votre propre réponse avec les lambdas et l'utilisation de ThenInclude
, qui est ma version préférée pour les requêtes simples avec des relations n à n, vous pouvez également utiliser des chaînes pour spécifier vos inclusions.
Il vous suffit d'écrire le "chemin" des propriétés séparées par des points .
comme ceci:
dbContext.Users
.Include("UserProfiles.Profile")
.Where(predicate)
.FirstOrDefault();
Cela fonctionne pour 1 à 1, 1 à plusieurs et plusieurs à plusieurs relations identiques.
C'est utile lorsque vous avez des inclusions profondes d'entités (mais vous perdez la vérification au moment de la compilation)