我如何表达"有很多通过"实体框架5中的关系?

时间:2013-10-23 19:44:20

标签: c# mysql entity-framework entity-framework-5

我正在尝试使用Entity Framework 5来查询现有的MySQL数据库。我使用代码优先创建一个基于代码的模型,该模型映射到this tutorial on MSDN之后的现有数据库。

我有两个表:usersbuddiesUseridnameemailBuddy有一个user_id和一个buddy_idUser有许多Buddies(也是Users)。 buddy_id列是返回Users表的外键。因此,每个User都有很多UsersBuddies

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public IList<User> Buddies { get; set; } 
}

这是我的数据库访问代码:

using (var db = new Models.fooContext())
{
    foreach (Models.user user in db.users)
    {
        var u = new User
        {
            Id      = user.id,
            Name    = user.name,
            Email   = user.email,
            Buddies = new List<User>()
        };

        // this is obviously very inefficient but I am just
        // trying to get anything to work
        foreach (Models.buddy buddy in db.buddies) // this line throws an exception
        {
            if (buddy.user_id == user.id)
            {
                var b = new User();
                // take buddy.user_id and find this user in the user table
                u.Buddies.Add(b);
            }
        }

        // serialize User and write it to a file here
    }
}

此代码在上面指定的行上抛出以下异常:

  

System.Data.EntityCommandExecutionException:执行命令定义时发生错误。有关详细信息,请参阅内部异常。“

内部异常是带有消息

MySql.Data.MySqlClient.MySqlException
  

已经有一个与此Connection关联的打开DataReader,必须先关闭它。

我的问题:

  1. 如何创建一种关系,告诉EF每个User有多个Buddies
  2. 一旦EF了解User有多个Buddies,我如何使用buddy_id查找User的{​​{1}}记录?

1 个答案:

答案 0 :(得分:11)

您有一种数据类型,您正在调用单独的名称。这有点令人困惑。但是,要首先使用代码,您只需在Custom DbContext类中使用以下流畅配置:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<user>().
      HasMany(c => c.Buddies).
      WithMany().
      Map(
       m =>
       {
          m.MapLeftKey("user_id");
          m.MapRightKey("buddy_id");
          m.ToTable("buddies");
       });
}

这假设你的用户类看起来像这样:

[Table("user")]
public class user
{
    public int id { get; set; }
    public string name { get; set; }
    public string email { get; set; }
    public virtual List<user> Buddies { get; set; }
}

如果您使用上述方法,您拥有的每个用户对象都会在其上显示名为Buddies的导航属性。在查询用户时,您需要急切加载好友用户,请执行以下操作:

context.users.Include("Buddies")

此外,要解决多个读者的问题。这是因为你没有从第一个循环中枚举查询(db.users)。为了解决这个问题,您可以像这样枚举查询:

var users = context.users.Include("Buddies").ToList();
foreach(var user in users)....

如果你使用上面的配置,你不需要尝试匹配id你只需从使用好友导航属性的用户获取好友列表(如果是新的空字段)(虚拟,懒惰加载),执行:

user.Buddies

正如你所看到的,你真的不需要'Model.buddy'(因为它只包含一个id映射) 实体框架将负责链接。但是,如果您并不总是在用户查询中包含好友,则可能需要该表。将通过以下方式查询LINQ:

var userBuddies = db.buddies.Where(buddy=>buddy.user_id == user.id).ToList();
//An enumerated list of user buddies 
//do stuff