2

我有一个名为 account 的复杂类型,其中包含许可证列表。许可证又包含一个域列表(域是一个简单的 id + url 字符串)。

在我的存储库中,我有这段代码

    public void SaveLicense(int accountId, License item)
    {

        Account account = GetById(accountId);
        if (account == null)
        {
            return;
        }


        if (item.Id == 0)
        {
            account.Licenses.Add(item);
        }
        else
        {
            ActiveContext.Entry(item).State = EntityState.Modified;
        }


        ActiveContext.SaveChanges();
    }

当我尝试保存更新的许可证(带有修改的域)时,会发生直接属于许可证的字符串得到更新就好了。

但是没有域得到更新。


我应该提到我所做的是允许用户在用户界面中添加和删除域。任何新域的 id=0 和任何已删除的域都不在列表中。

所以我想要的是

  1. 列表和数据库中的任何域且未更改 - 没有任何反应
  2. 列表和数据库中的任何域,但在列表中已更改 - 数据库已更新
  3. 任何 id=0 的域都应该插入(添加)到数据库中
  4. 任何不在列表中但在数据库中的域都应该被删除

我玩了一些但没有成功,但我偷偷地怀疑我在更大的范围内做错了什么,所以如果我在设计方面误解了某些东西,或者只是错过了一些东西,我希望得到提示。

4

2 回答 2

3

不幸的是,更新对象图 - 具有其他相关实体的实体 - 是一项相当困难的任务,并且 Entity Framework 没有非常复杂的支持来使其变得容易。

问题在于,将实体的状态设置为Modified(或通常设置为任何其他状态)只会影响您传入的实体DbContext.Entry以及它的标量属性。它对其导航属性和相关实体没有影响。

您必须手动处理此对象图更新,方法是加载当前存储在数据库中的实体(包括相关实体),并将您在 UI 中所做的所有更改合并到该原始图中。您的else案例可能如下所示:

//...
else
{
    var licenseInDb = ActiveContext.Licenses.Include(l => l.Domains)
        .SingleOrDefault(l => l.Id == item.Id)

    if (licenseInDb != null)
    {
        // Update the license (only its scalar properties)
        ActiveContext.Entry(licenseInDb).CurrentValus.SetValues(item);

        // Delete domains from DB that have been deleted in UI
        foreach (var domainInDb in licenseInDb.Domains.ToList())
            if (!item.Domains.Any(d => d.Id == domainInDb.Id))
                ActiveContext.Domains.Remove(domainInDb);

        foreach (var domain in item.Domains)
        {
            var domainInDb = licenseInDb.Domains
                .SingleOrDefault(d => d.Id == domain.Id);
            if (domainInDb != null)
                // Update existing domains
                ActiveContext.Entry(domainInDb).CurrentValus.SetValues(domain);
            else
                // Insert new domains
                licenseInDb.Domains.Add(domain);
        }
    }
}
ActiveContext.SaveChanges();
//...

您还可以尝试这个名为“GraphDiff”的项目,该项目旨在以通用方式为任意分离的对象图完成这项工作。

另一种方法是跟踪 UI 层中某些自定义字段中的所有更改,然后在数据回发时评估跟踪的状态更改以设置适当的实体状态。因为您在 Web 应用程序中,这基本上意味着您必须在用户更改值、添加新项目或删除项目时跟踪浏览器中的更改(很可能需要一些 Javascript)。在我看来,这个解决方案更难实施。

于 2013-05-25T19:13:17.517 回答
0

这应该足以做你想做的事情。如果您对代码有更多疑问,请告诉我。

public void SaveLicense(License item)
{        
    if (account == null)
    {
        context.Licenses.Add(item);
    }

    else if (item.Id > 0)
           {

               var currentItem = context.Licenses                        
                   .Single(t => t.Id == item.Id);

               context.Entry(currentItem ).CurrentValues.SetValues(item);                    
            }

    ActiveContext.SaveChanges();
 }
于 2013-05-25T18:38:43.897 回答