另一个多对多的复杂性 - Entity Framework 4.1 DbContext

发布于 2024-12-09 20:18:21 字数 957 浏览 5 评论 0原文

我正在使用 DB First 方法,EF 4.1 和 DbContext POCO 代码生成。

我的数据库具有多对多关系,如下所示:

Employee

EmployeeId

EmployeeName

Account

AccountId

AccountName

EmployeeAccount

EmployeeId

AccountId

当我尝试更新员工,并将其帐户分配更改为预先存在的帐户,因此我基本上按如下方式执行此操作:

using(context)
{
  var query = from e in context.Employees.Include(f => f.Accounts)
              where e.EmployeeId == employeeId
              select;

  Employee emp = query.FirstOrDefault()
}

emp.EmployeeName = "Test";

emp.Accounts.Clear();

Account act = MethodThatLooksUpAccountByName("SomeAccountName");

emp.Accounts.Add(act);

using(context)
{
  context.Accounts.Attach(act);

  emp.State = EntityState.Modified;

  context.Employees.Attach(emp);

  context.SaveChanges();
}

生成的 SQL 正在对 [Employee] 表执行更新,对 [EmployeeAccount] 根本没有任何更新,不删除 不 插入。

I am using DB first method, EF 4.1 with DbContext POCO code gen.

My database has a many-to-many relationship as shown below:

Employee

EmployeeId

EmployeeName

Account

AccountId

AccountName

EmployeeAccount

EmployeeId

AccountId

The problem occurs when I am trying to update an Employee, and change their account assignment to a pre existing account, so I am basically doing this as below:

using(context)
{
  var query = from e in context.Employees.Include(f => f.Accounts)
              where e.EmployeeId == employeeId
              select;

  Employee emp = query.FirstOrDefault()
}

emp.EmployeeName = "Test";

emp.Accounts.Clear();

Account act = MethodThatLooksUpAccountByName("SomeAccountName");

emp.Accounts.Add(act);

using(context)
{
  context.Accounts.Attach(act);

  emp.State = EntityState.Modified;

  context.Employees.Attach(emp);

  context.SaveChanges();
}

The SQL being generated is executing an update on the [Employee] table, nothing for the [EmployeeAccount] at all, no delete no insert.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

×眷恋的温暖 2024-12-16 20:18:21

尝试删除(至少)最后一个Attach。您也不需要将状态设置为 Modified,因为您处于附加场景中(emp 是从数据库加载的),并且更改跟踪将识别发生了什么更改:

var query = from e in context.Employees.Include(f => f.Accounts)
            where e.EmployeeId == employeeId
            select;
Employee emp = query.FirstOrDefault()

emp.EmployeeName = "Test";
emp.Accounts.Clear();

Account act = MethodThatLooksUpAccountByName("SomeAccountName");
// next line is only necessary if MethodThatLooksUpAccountByName
// uses another context. If it uses the same context you can remove this line.
context.Accounts.Attach(act); 

emp.Accounts.Add(act);

context.SaveChanges();

这我认为应该有效。

更改问题中的代码后编辑

第二个上下文执行其自己的更改跟踪。因此它无法识别您已删除帐户并添加了新帐户。它应该按以下方式工作:

using(...context...)
{
    var query = from e in context.Employees.Include(f => f.Accounts)
                where e.EmployeeId == employeeId
                select;

    Employee emp = query.FirstOrDefault()
}

Account act = MethodThatLooksUpAccountByName("SomeAccountName");

using(...context...)
{
    context.Employees.Attach(emp);
    context.Accounts.Attach(act);

    emp.EmployeeName = "Test";
    emp.Accounts.Clear();
    emp.Accounts.Add(act);

    context.SaveChanges();
}

我有感觉,这不是你想要的。您是否在与上一个上下文无关的状态下完成了员工的更改(清除旧帐户并添加新帐户)?
多对多集合的问题是,您必须在要清除或更改旧的Account 集合的上下文中加载或附加它。无法通过设置任何标量属性或在任何实体上设置状态来触发链接表上的任何 DELETE 或 INSERT 语句。只有检测到集合中的更改,EF 才会导致更新链接表。

Try to remove (at least) the last Attach. You also don't need to set the state to Modified because you are in an attached scenario (emp is loaded from DB) and change tracking will recognize what did change:

var query = from e in context.Employees.Include(f => f.Accounts)
            where e.EmployeeId == employeeId
            select;
Employee emp = query.FirstOrDefault()

emp.EmployeeName = "Test";
emp.Accounts.Clear();

Account act = MethodThatLooksUpAccountByName("SomeAccountName");
// next line is only necessary if MethodThatLooksUpAccountByName
// uses another context. If it uses the same context you can remove this line.
context.Accounts.Attach(act); 

emp.Accounts.Add(act);

context.SaveChanges();

This should work in my opinion.

Edit after you changed the code in the question:

The second context performs its own change tracking. So it doesn't recognize that you have removed the accounts and added a new one. It should work the following way:

using(...context...)
{
    var query = from e in context.Employees.Include(f => f.Accounts)
                where e.EmployeeId == employeeId
                select;

    Employee emp = query.FirstOrDefault()
}

Account act = MethodThatLooksUpAccountByName("SomeAccountName");

using(...context...)
{
    context.Employees.Attach(emp);
    context.Accounts.Attach(act);

    emp.EmployeeName = "Test";
    emp.Accounts.Clear();
    emp.Accounts.Add(act);

    context.SaveChanges();
}

I have the feeling, it's not what you want. Did you have done the changes of the employee (clearing old accounts and adding new account) in a state detached from the last context?
The problem with many-to-many collection is that you must load or attach the old Account collection in the context where you want to clear or change it. There is no way to trigger any DELETE or INSERT statements on the link table by setting any scalar property or by setting a state on any entity. Only detection of changes in the collections will EF cause to update the link table.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文