Вы можете использовать следующее:
var usersWithFriends = context.Users
.GroupJoin(context.FriendShips, u => u.UserID, f => f.UserID, (u, f) => new
{
User = u,
Friends = f.Join(context.Users, f1 => f1.TheirFriends, u1 => u1.UserID,
(f1, u1) => u1)
})
.ToList();
Результатом является коллекция анонимных объектов, и каждый элемент имеет свойство User
с пользователем и коллекцию Friends
, которая содержит всех пользователей, которые являютсядрузья данного пользователя.Из-за GroupJoin
результат также содержит пользователей без друзей (коллекция Friends
в этом случае пуста).Примерно так:
Element[0]:
User -> "Jim"
Friends -> "John" + "Diana"
Element[1]:
User -> "John"
Friends -> empty
Element[2]:
User -> "Diana"
Friends -> "John"
Но это не способ Entity-Framework для работы с такой моделью.На самом деле у вас должно быть свойство навигации в вашем User
классе:
public class User
{
[Key]
public string UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
//...
public ICollection<User> Friends { get; set; }
}
И отношения между многими пользователями:
modelBuilder.Entity<User>()
.HasMany(u => u.Friends)
.WithMany()
.Map(x =>
{
x.MapLeftKey("UserID");
x.MapRightKey("TheirFriends");
x.ToTable("FriendShips");
});
FriendShips
будет простотаблица соединений в базе данных (без столбца FriendShipID
, вместо этого UserID
и TheirFriends
создает составной ключ), а не объект в вашей модели.User
ваша единственная сущность.Тогда вы могли бы достичь того же результата намного проще:
var usersWithFriends = context.Users.Include(u => u.Friends).ToList();
Не только меньше строк кода, но и намного проще для чтения и понимания.EF позаботится о сложном объединении и группировке в базе данных при переводе запроса в SQL.
Edit
Вы можете добавить отношения (= строки в таблице ссылокFriendShips
) добавив существующего пользователя в коллекцию Friends
:
using (var context = new MyContext())
{
var user = context.Users.Single(u => u.UserID == "John");
var friend = context.Users.Single(u => u.UserID == "Diana");
user.Friends = new HashSet<User>();
user.Friends.Add(friend);
context.SaveChanges(); // will write a new row into the join table
}
Аналогично, вы можете удалить связь (удалить строку из таблицы объединения):
using (var context = new MyContext())
{
var user = context.Users.Include(u => u.Friends)
.Single(u => u.UserID == "John");
var friend = user.Friends.Single(u => u.UserID == "Diana");
user.Friends.Remove(friend);
context.SaveChanges(); // will delete a row from the join table
}
Это такжевозможно без запроса пользователей из базы данных, так как у вас есть значения первичного ключа:
using (var context = new MyContext())
{
var user = new User { UserID = "John" };
var friend = new User { UserID = "Diana" };
context.Users.Attach(user);
context.Users.Attach(friend);
user.Friends = new HashSet<User>();
user.Friends.Add(friend);
context.SaveChanges(); // will write a new row into the join table
}
using (var context = new MyContext())
{
var user = new User { UserID = "John" };
var friend = new User { UserID = "Diana" };
user.Friends = new HashSet<User>();
user.Friends.Add(friend);
context.Users.Attach(user);
// attaching friend is not necessary, it is already attached with user
user.Friends.Remove(friend);
context.SaveChanges(); // will delete row from the join table
}