1

我正在尝试将我的 DbContext 与我目前使用的 winforms 应用程序分开,以更好地支持多用户环境以及即将推出的网站。在做了一些研究之后,我打算为 winforms 应用程序/网站实现数据访问层 (DAL) 以连接到并让最终用户使用断开连接的实体。我的问题是,当子集合中的一个实体已更新时,我将如何保存对我的实体的更新。

例如,如果我有以下结构(简化)

public class Company
{
    public int CompanyID { get; set; }
    public string CompanyName { get; set; }
    public ICollection<Employee> Employees { get; set; }  // Non-virtual as we aren't lazy-loading
}

public class Employee
{
    public int CompanyID { get; set; }
    public int EmployeeID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ICollection<Claim> Claims { get; set; }
}

public class Claim
{
    public DateTime ClaimDate { get; set; }
    public ICollection Documentation { get; set; }
}

public class Document
{
    public byte[] DocumentImage { get; set; }
    public string Name { get; set; }
    public DateTime CreateDate { get; set; }
}

在 winforms 应用程序中,我设置了多个 Binding Source 来显示员工的信息

例如:

employeeBinding.DataSource = typeof(Employee);   // Eventually set to an IEnumerable<Employee>
claimBinding.DataSource = employeeBinding;
claimBinding.DataMember = "Claims";
documentationBinding.DataSource = claimBinding;
documentationBinding.DataMember = "Documentation";

但是,通过像这样进行设置,我无法调用每个绑定源的“CurrentChanged”事件来保存每个实体,因为它已经更改(除非我在表单中存储了对前一个实体的引用)。所以我想做的是类似于下面的 DAL 并遍历每个子集合。

public void UpdateEmployee(Employee employee) 
{
   using (myContext context = new myContext())
   {
     context.Employees.Attach(employee);
     context.Entry<Employee>(employee).State = EntityState.Modified;

     foreach(var claim in employee.Claims) 
     {
       context.Entry<Claim>(claim).State = EntityState.Modified;
       foreach(var doc in claim.Documentation)
       {
         context.Entry<Document>(doc).State = EntityState.Modified;
       }
     }
     context.SaveChanges(); 
   }
}

然而,我觉得这条路线可能会因为一些更复杂的实体和关系而变得丑陋。有人可以帮我指出处理这个问题的最佳途径,还是我应该在代码中引用当前实体,以便当“CurrentChanged”事件触发时我可以更新每个单独的实体?

非常感谢。

4

2 回答 2

0

我可能是错的,但我不相信 DetectChanges 能够确定已对断开连接的实体进行了更改。附加实体后,它将具有“未更改”的 EntityState,因此在将其状态标记为“已修改”之前,DbContext 不会对其执行任何操作。此外,如以下 URL 中所示,无论如何都会为许多方法(包括“附加”)调用“DetectChanges”,并且不需要显式调用。

http://msdn.microsoft.com/en-us/data/jj556205.aspx

至于 BindingSource,我在说明 BindingSource 将设置为 typeof(Employee),就好像我在加载事件之前在构造函数中设置我的代码一样,我将在其中实际获取我的数据并将其数据源设置为 IEnumerable DAL 调用。如果我不这样做,我会在尝试绑定到“DataMember”属性时遇到问题,因为其他 BindingSources 将无法找到指示的属性。

我不相信您作为示例提供的代码解决了我遇到的有关正在更新的子集合的问题。使用 LinqPad 进行测试时,如果父实体也发生了变化,它们将被更新,但如果父实体的变化为零,则不会更新。这就是为什么我要遍历所有子集合并将它们标记为“已修改”。

于 2013-08-23T12:16:04.710 回答
0

当您使用实体框架时,您拥有 ChangeTracker,即使您正在使用此“断开连接的实体”,您也可以让 ChangeTracker 跟踪实体,为此您只需将它们附加到上下文并在您调用 SaveChanges 之前调用.DetectCHanges() 你真的不需要这个特定的代码,你可以为此使用泛型:

public void Update<TEntity>(TEntity entity) 
{
   using (myContext context = new myContext())
   {
     context.Set<TEntity>.Attach(entity);
     context.ChangeTracker.DetectChanges();
     context.SaveChanges(); 
   }
}

对该方法的调用将是:

Update<Employee>(employees);

另外我认为最好使用 BindingSouce 作为 DataSource,并将 BindingSource 的 DataSource 设置为 List 而不是 typeof(Employee)

于 2013-08-22T21:24:02.967 回答