Таким образом, в вашей базе данных есть таблица, заполненная Posts
. Каждый Post
кажется, что опубликовано ноль или больше (может быть, один или несколько) Пользователи. Мне кажется, что у вас также есть таблица Users
. Каждый User
опубликовал ноль или более Posts
.
Мне кажется, что существует связь "многие ко многим" между Users
и Posts
: Каждый Пользователь опубликовал ноль или более сообщений; каждое сообщение было опубликовано нулем (одним?) или несколькими Пользователями.
Обычно в базе данных вы реализуете отношение "многие ко многим" с помощью специальной таблицы: таблицы соединений.
Вы не используете соединительный стол. Ваша база данных не нормализована.
Возможно, вашу текущую проблему можно решить без изменения базы данных, но я вижу так много проблем, которые вам придется решить, возможно, не сейчас, а в ближайшем будущем: какую огромную работу вам нужно будет выполнить, если вы хотите удалить пользователя? Как вы получаете все "Сообщения, которые опубликовал пользователь [10]", И что делать, если Пользователь [10] больше не хочет упоминаться в списке публикаций поста [23]? Как предотвратить, чтобы этот пользователь [10] дважды упоминался в посте[23]:
UserIds = 10, 3, 5, 10, 7, 10
Нормализовать базу данных
Подумайте о том, чтобы обновить базу данных таблицей соединений и избавиться от столбца string Post.UserIds
. Это решило бы все эти проблемы сразу.
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;}
}
И соединительный стол:
public UsersPost
{
public int UserId {get; set;}
public int PostId {get; set;}
}
Примечание: [Идентификатор пользователя, postID] уникален. Используйте этот первичный ключ
В entity framework столбцы таблиц представлены невиртуальными свойствами. Виртуальные свойства отражают отношения между таблицами (один ко многим, многие ко многим).
Примечание: внешний ключ-это реальный столбец в таблице, следовательно, внешний ключ не является виртуальным.
Чтобы настроить "многие ко многим", вы можете использовать Fluent API:
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});
}
Вернемся к вашей проблеме
Как только вы внедрили таблицу соединений, ваш запрос данных будет простым:
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(),
});
Или, если вам не нужны какие-либо пользовательские данные, начните с сообщений:
var postsOfUser = dbContext.Posts
.Where(post => post.Users.Any(user => user.Id == userId))
.Select(post => new {...});
Некоторым людям не нравится использовать виртуальные коллекции ICollections, или они используют версию entity framework, которая этого не поддерживает. В этом случае вам придется присоединиться самостоятельно:
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,
...
}
}
Решение без нормализованной базы данных
Если вы действительно не можете убедить руководителя проекта в том, что правильная база данных предотвратит множество проблем в будущем, подумайте о том, чтобы создать текст SQL, который будет содержать правильные сообщения для вас.
Ваш DbContext представляет текущую реализацию вашей базы данных. В нем описывались таблицы и отношения между таблицами. Добавление метода для извлечения сообщений пользователя кажется мне законным методом для DbContext.
Мой SQL немного заржавел, вы будете знать намного лучше меня, как это сделать в SQL. Я думаю, вы поймете суть:
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);
}