代码之家  ›  专栏  ›  技术社区  ›  Marek Karbarz

带有快照更改检测的实体框架中的POCO

  •  2
  • Marek Karbarz  · 技术社区  · 14 年前

    我有一组由Visual Studio 2010生成的poco类(即从DB模式生成的现成的poco模板)。对于给定的用例,我允许用户加载一个实体(CRM联系人)并对其进行操作-在回发之间添加电话号码(它本身是一个与外键相关的独立实体)和地址(也是一个独立实体)等。我将修改后的实体存储在视图状态(我不想立即保存对数据库的更改)。当用户点击保存按钮时,问题就出现了。主CRM联系人将保存完好(检测并保存任何更改),但不会保存任何相关属性-无论是新添加的还是修改的ef都会忽略它。

    如何强制实体框架检测我的相关属性发生了更改?我用这个来保存我的主要联系人:

    //contact is an instance of CRMContact retrieved from ViewState
    if (contact.Id == 0) {
        CRMEntities.CRMContacts.AddObject(contact);
    } else {
        CRMContact orig = CRMEntities.CRMContacts.Where(c => c.Id == contact.Id).FirstOrDefault();
        CRMEntities.CRMContacts.ApplyCurrentValues(contact);
    }
    
    CRMEntities.SaveChanges(SaveOptions.DetectChangesBeforeSave | SaveOptions.AcceptAllChangesAfterSave);
    

    这对联系实体很有用,但对我的相关实体不适用。要添加和/或更新电话号码和电子邮件,我需要添加什么?

    请注意,我不想使用基于代理的更改跟踪。

    谢谢

    2 回复  |  直到 14 年前
        1
  •  2
  •   Marek Karbarz    14 年前

    经过反复的尝试和错误,我设法把一些有用的东西放在一起。注意,我不知道这是否是正确的方法。这是来自项目不同部分的代码。 IAHeader 是一个主要实体, IAAttachment IAComment 都通过外键链接到头:

    public static void Save(IAHeader head) {
        IAHeader orig = new IAHeader();
        if (head.Id == 0) {
            IAData.Entities.IAHeaders.AddObject(head);
        } else {
            orig = IAData.Entities.IAHeaders.Where(h => h.Id == head.Id).FirstOrDefault();
            IAData.Entities.IAHeaders.ApplyCurrentValues(head);
    
            foreach (IAComment comm in head.Comments.ToList()) {
                if (comm.Id == 0) {
                    comm.IAHeader = null; //disassociate this entity from the parent, otherwise parent will be re-added
                    comm.IAId = head.Id;
                    IAData.Entities.IAComments.AddObject(comm);
                } else {
                    IAComment origComm = orig.Comments.Where(c => c.Id == comm.Id).First();
                    IAData.Entities.IAComments.ApplyCurrentValues(comm);
                }
            }
    
            foreach (IAAttachment att in head.Attachments.ToList()) {
                if (att.Id == 0) {
                    att.IAHeader = null; //disassociate this entity from the parent, otherwise parent will be re-added
                    att.IAId = head.Id;
                    IAData.Entities.IAAttachments.AddObject(att);
                } else {
                    IAAttachment origAtt = orig.Attachments.Where(a => a.Id == att.Id).First();
                    IAData.Entities.IAAttachments.ApplyCurrentValues(att);
                }
            }
        }
        IAData.Entities.SaveChanges(SaveOptions.DetectChangesBeforeSave | SaveOptions.AcceptAllChangesAfterSave);
    }
    

    很明显,可以进行很多改进,但这正是我迄今为止提出的,适用于我的场景。最让我困惑的重要部分是必须将导航属性与我的主实体分离,否则我要么得到“实体键已存在”错误,要么主实体将被保存两次。

        2
  •  0
  •   Craig Stuntz    14 年前

    我看不出你在哪里改变了任何相关的值。这个 docs for ObjectContext.ApplyCurrentValues 说:

    复制 标量值 从提供的对象到具有相同键的ObjectContext中的对象。

    (增加了重点。)

    既然你没有做其他的改变,我想说没有什么可以发现的。