如何在Code第一种方法中加入两个表

时间:2012-03-10 14:21:15

标签: asp.net-mvc entity-framework c#-4.0 ef-code-first

我有两个表,用户和友谊。我想加入这两个表,以便具有所有朋友的UserID的列OurFriends将具有User中的一些属性。那就是我想让每个朋友都拥有他们所有的属性。 输出将如下所示 他们的朋友名字姓LastName UserPicture

我需要这个linq和lambda表达式。

用户:

public class User
{

    public String UserID { get; set; }
    public string FirstName { get; set; }
    public String LastName { get; set; }

    public string Description { get; set; }
    public string UserPicture { get; set; }
    public string Gender { get; set; }
    public String Interest { get; set; }
    public DateTime DateOfBirth { get; set; }
    public String Email { get; set; }

友谊

 public class FriendShip
{

    public int FriendShipID { get; set; }
    public string TheirFriends { get; set; }

    public String UserID { get; set; }
}

1 个答案:

答案 0 :(得分:3)

您可以使用以下内容:

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"

但这不是使用这种模型的实体框架方式。您实际上应该在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列,UserIDTheirFriends而是构建一个复合键)而不是您的实体模型。 User是您唯一的实体。然后你可以更轻松地实现相同的结果:

var usersWithFriends = context.Users.Include(u => u.Friends).ToList();

不仅更少的代码行,而且更容易阅读和理解。当查询转换为SQL时,EF将关心数据库中的复杂连接和分组。

修改

您可以通过将现有用户添加到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
}