Deci, baza de date are un tabel plin cu Posts
. Fiecare Post
pare a fi scris de zero sau mai multe (poate unul sau mai multe) de Utilizatori. Mi se pare, că aveți, de asemenea, un tabel de Users
. Fiecare User
a postat zero sau mai multe Posts
.
Mi se pare că există o mulți-la-mai-mulți relația dintre Users
și Posts
Fiecare Utilizator a postat zero sau mai multe Mesaje, fiecare Mesaj a fost postat de zero (unul?) sau mai mulți Utilizatori.
În mod normal, într-o bază de date ce va implementa o mulți-la-mai-mulți legătură cu o masa speciala: intersecția masă.
Nu utilizați tabelul de joncțiune. Baza ta de date nu este normalizat.
Poate problema ta actuală pot fi rezolvate fără a modifica baza de date, dar am văzut atât de multe probleme, va trebui să rezolve, poate nu acum, dar în viitorul apropiat: ce imens de muncă ar trebuie să faceți dacă doriți să ștergeți un utilizator? Cum a face tu a lua toate "Posturile care utilizatorul [10] s-a postat" Și ce dacă Utilizatorul [10] nu vrea să fie menționate în lista de publicații Post [23]? Cum pentru a preveni Utilizatorul respectiv [10] este menționat de două ori în Post[23]:
UserIds = 10, 3, 5, 10, 7, 10
Normalizarea bazei de date
Ia în considerare pentru a actualiza baza de date cu un nod de masă și a scăpa de string coloană Post.UserIds
. Acest lucru ar rezolva toate aceste probleme dintr-o dată.
class User
{
public int Id {get; set;}
public string Name {get; set;}
...
// every user has posted zero or more Posts:
public virtual ICollection<Post> Posts {get; set;}
}
class Post
{
public int Id {get; set;}
public string Title {get; set;}
public Datetime PublicationDate {get; set;}
...
// every Post has been posted by zero or more Users:
public virtual ICollection<User> Users {get; set;}
}
Și intersecția tabel:
public UsersPost
{
public int UserId {get; set;}
public int PostId {get; set;}
}
Notă: [UserId, PostId] este unic. Utilizați această o cheie primară
În entity framework coloanele din tabele sunt reprezentate de non-virtual properties. Virtual proprietăți reflectă relațiile între tabele (unu-la-multe, multe-la-multe)
Nota: o cheie externă este o adevărată coloană într-un tabel, prin urmare, o cheie externă este non-virtuale.
Pentru a configura mai multe-la-mai-mulți, puteți utiliza API Fluent:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// User - Post: many-to-many
modelBuilder.Entity<User>()
.HasMany<Post>(user => user.Posts)
.WithMany(post => post.Users)
.Map(userpost =>
{
userpost.MapLeftKey(nameof(UserPost.UserId));
userpost.MapRightKey(nameof(UserPost.PostId));
userpost.ToTable(nameof(UserPost));
});
// primary key of UserPost is a composite key:
modelBuilder.Entity<UserPost>()
.HasKey(userpost => new {userpost.UserId, userpost.PostId});
}
Revenind la problema ta
Odată ce ați implementat intersecția tabelul dvs. de date cererea va fi ușor:
int userId = ...
// get this User with all his Posts:
var userWithPosts= dbContext.Users
.Where(user => user.Id == userId)
.Select(user => new
{
// Select only the user properties that you plan to use
Name = user.Name,
...
Posts = user.Posts.Select(post => new
{
// Select only the Post properties that you plan to use
Id = post.Id
PublicationDate = post.PublicationDate,
...
})
.ToList(),
});
Sau, dacă nu doriți orice date de utilizator, începe cu Mesaje:
var postsOfUser = dbContext.Posts
.Where(post => post.Users.Any(user => user.Id == userId))
.Select(post => new {...});
Unii oameni nu le place să folosească virtual ICollections, sau folosesc o versiune de cadru entitate care nu acceptă acest lucru. În acest caz, veți avea de a face-vă:
int userId = ...
var postsOfThisUser = dbContext.UserPosts
// keep only the UserPosts of this user:
.Where(userPost => post.UserId == userId)
// join the remaining UserPosts with Posts
.Join(dbContext.Posts,
userpost => userpost.PostId, // from every UserPost get the foreign key to Post
post => post.Id, // from every Post, get the primary key
// parameter resultSelector: from every UserPost with matching Post make one new
(userPost, post) => new
{
Title = post.Title,
PublicationDate = post.PublicationDate,
...
}
}
Soluție fără a normalizat baza de date
Dacă nu poți convinge pe liderul de proiect pe care o bază de date corespunzătoare va preveni o mulțime de probleme în viitor, ia în considerare pentru a crea un SQL text care poate primi mesaje pentru tine.
Ta DbContext reprezintă implementarea curentă a bazei de date. Acesta a descris tabele și relații între tabele. Adăugarea unei metode pentru a prelua Posturile de un utilizator mi se pare o metodă legit pentru DbContext.
My SQL este un pic ruginit, vei ști mai bine decât mine cum să facă acest lucru în SQL. Cred că vei înțelege esențialul:
public IEnumerable<Post> GetPostsOfUser(int userId)
{
const string sqlText = "Select Id, ... from Posts where ..."
object[] parameters = new object[] {userId};
return this.Database.SqlQuery(sqlText, parameters);
}