Por lo que su base de datos tiene una tabla llena de Posts
. Cada Post
parece ser publicado por cero o más (tal vez uno o más) de los Usuarios. A mí me parece, que también dispone de una tabla de Users
. Cada User
ha publicado cero o más Posts
.
A mí me parece que hay muchos-a-muchos de relación entre Users
y Posts
: Cada Usuario haya publicado cero o más de los Puestos; cada Post ha sido publicado por cero (uno?) o más Usuarios.
Normalmente en una base de datos que permitiría la implementación de muchos-a-muchos relación con una mesa especial: la tabla de unión.
No utilice la tabla de unión. Su base de datos no está normalizada.
Tal vez su actual problema puede ser resuelto sin necesidad de cambiar la base de datos, pero veo tantos problemas que se han de resolver, tal vez no ahora, pero en el futuro: ¿qué inmenso trabajo que debe hacer si desea eliminar un usuario? ¿Cómo conseguir que todos "los mensajes que el usuario [10] ha publicado" ¿Y si el Usuario [10] no quieren ser mencionado ya en la publicación de la lista de Post [23]? Cómo evitar que el Usuario [10] se menciona dos veces en el Post[23]:
UserIds = 10, 3, 5, 10, 7, 10
Normalizar la base de datos
Considere la posibilidad de actualizar la base de datos con una tabla de unión y deshacerse de la columna de cadena Post.UserIds
. Esto podría resolver todos estos problemas a la vez.
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;}
}
Y la tabla de unión:
public UsersPost
{
public int UserId {get; set;}
public int PostId {get; set;}
}
Nota: [UserId, PostId] es único. Uso de la clave principal
En el marco de entidades de las columnas de las tablas están representados por los no-propiedades virtuales. Las propiedades virtuales que reflejan las relaciones entre las tablas (uno-a-muchos, muchos-a-muchos)
Nota: una clave externa es una verdadera columna de una tabla, por lo tanto, una clave externa es no-virtual.
Para configurar muchos-a-muchos, puede utilizar la API Fluida:
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});
}
De regreso a su problema
Una vez que haya implementado la tabla de unión de su solicitud de datos va a ser fácil:
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(),
});
O, si usted no desea que los datos de usuario, inicie con los Puestos de:
var postsOfUser = dbContext.Posts
.Where(post => post.Users.Any(user => user.Id == userId))
.Select(post => new {...});
A algunas personas no les gusta usar el virtual ICollections, o que utilice una versión de entity framework que no es compatible con esta. En ese caso, usted tendrá que hacer la combinación ti mismo:
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,
...
}
}
Solución sin necesidad de base de datos normalizado
Si realmente no puedes convencer a tu jefe de proyecto que una adecuada base de datos evitará un montón de problemas en el futuro, considere la posibilidad de crear un texto SQL que obtener el adecuado puestos para usted.
Su DbContext representa la implementación actual de la base de datos. Se describen las tablas y las relaciones entre las tablas. La adición de un método para recuperar los Posts de un usuario, me parece una de fiar método para la DbContext.
Mi SQL es un poco oxidado, usted sabe mejor que yo cómo hacer esto en SQL. Supongo que usted va a obtener la esencia:
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);
}