2015-07-18 157 views
0

我有一个C#程序,它将数据库中的产品列表加载到产品对象列表中。用户可以通过我的程序界面添加新产品,编辑产品和删除产品。相当标准的东西。我的问题涉及跟踪这些更改并将其保存回数据库。在了解细节之前,我知道使用Entity Framework或NHiberate之类的东西可以解决跟踪添加和编辑的问题,但我认为这不会解决跟踪删除的问题。除了想要将大型代码转换为使用实体框架或NHiberate之外,我还想知道为了我自己的好奇而回答这个问题。保存数据库实体

为了跟踪编辑,我在做产品上的阶级是这样,我设置IsDirty标志一个属性更改的任何时间:

class Product 
{ 
    public bool IsDirty { get; set; } 
    public bool IsNew { get; set; } 

    // If the description is changed, set the IsDirty property 
    public string Description 
    { 
     get 
     { 
     return _description; 
     } 
     set 
     { 
     if (value != _description) 
     { 
      this.IsDirty = true; 
      _description = value; 
     }   
     } 
    } 
    private string _description; 

    // ... and so on 
} 

当我创建一个新的产品对象,我设置它的IsNew标志,以便程序知道在下次用户保存时将其写入数据库。一旦我成功将产品写入数据库,我就清除它的IsNew和IsDirty标志。

为了跟踪其删除,我做了一个列表类,跟踪已删除的项目:

class EntityList<T> : List<T> 
{ 
    public List<T> DeletedItems { get; private set; } 

    EntityList() 
    { 
     this.DeletedItems = new List<T>(); 
    } 

    // When an item is removed, track it in the DeletedItems list 
    public new bool Remove(T item) 
    { 
     this.DeletedItems.Add(item); 
     base.Remove(item); 
    } 
} 

// ... 

// When I work with a list of products, I use an EntityList instead of a List 
EntityList<Product> products = myRepository.SelectProducts(); 

每一次我的产品列表保存到数据库中,我经历了所有的产品在EntityList的迭代。 DeletedItems属性并从数据库中删除这些产品。一旦列表成功保存,我将清除DeletedItems列表。

所有这些工作,但它似乎我可能做了太多的工作,特别是跟踪删除的项目,并记住每次创建一个新的产品对象时设置IsNew标志。我无法在Product的构造函数中设置IsNew标志,因为如果从数据库加载Product对象,我不想设置该标志。我也不会感到兴奋,因为我必须在任何地方使用我的EntityList类而不是使用List。

看起来这种情况非常普遍,但我一直无法通过我的研究找到一种优雅的方式。所以我有两个问题:

1)假设我没有使用Entity Framework之类的东西,是否有更好的方法来跟踪添加,编辑和删除,然后将这些更改持久化到数据库?

2)我是否正确地说,即使使用实体框架或NHiberate,我仍然必须编写一些额外的代码来跟踪我的删除项目?

回答

0

在EF中,DbContext对象包含所有跟踪对其所知对象的更改的逻辑。如果可以SaveChanges它会计算出发生了哪些更改,并执行相应的操作将这些更改提交到数据库。除了在要添加或删除记录时通知DbContext以外,您不需要执行与对象状态相关的任何操作。

更新:

当查询DbSet你获得由EF内部跟踪的对象。在SaveChanges期间,将这些对象的当前状态与其原始状态进行比较,并将那些已更改的对象放入队列中以在数据中进行更新。

插入:

当您添加一个新的对象到相关DbSet它的SaveChanges通话过程中标记为插入。该对象被登记在变更跟踪,这是DB-生成的字段(例如自动递增的ID)被更新等

删除:

从数据库中删除记录您对相关致电RemoveDbSet和EF将在下一个SaveChanges呼叫期间执行该操作。

因此,您不必担心为了数据库而跟踪这些更改,这些都是为您处理的。您可能需要知道自己的利益 - 有时能够为更改颜色着色是很好的事情。

以上对于Linq2SQL以及其他可能的ORM和数据库接口层也是如此,因为它们的主要目的是允许您访问数据,而无需编写大量代码来完成可以抽象的事情。

0
  1. 有没有更好的方法来追踪增加,编辑和删除,然后坚持那些对数据库的更改?

两个Entity FrameworkNHibernate选择不对实体本身负责通知,也没有跟踪其变化*。所以这不是一个不好的选择。从设计模式的角度来看,它肯定是一个不错的选择(单一责任)。

它们分别存储数据在上下文或会话中从数据库加载时的快照。此外,这些快照有状态说明它们是新的,更新的,删除的还是未更改的。还有一些进程可以比较实际值和快照并更新实体状态。当需要保存更改时,将评估状态并生成适当的CRUD语句。

这一切都非常复杂,你自己实现。而且我甚至没有提到实体国家的完整性及其相互关联。但是,当然,这是可行的,一旦你决定遵循相同的模式。数据层通知/跟踪更改(而不是实体本身)的优点是DAL知道哪些更改与数据存储相关。并非所有属性都映射到数据库表,但实体不知道。

  1. 我仍然需要编写一些额外的代码来跟踪我删除的项目吗?

号双方或映射器具有持久性的无知的概念。您基本上只使用内存中的对象,可能会从列表中删除它们(嵌套在所有者实体或表示数据库表的列表中),并且ORM知道如何将实体的内存中状态与数据库同步。


*实体框架曾经有过自跟踪实体,但他们被弃用。

+0

由于实体框架正在存储我的数据的快照,这会产生多少开销?它是否实质上存储了每个对象两次(当前的工作副本和原始副本),因此使用的内存量增加了一倍? –

+0

它将副本存储为值列表,工作副本是实现的对象以及您使用的对象。这是开销吗?这是整个过程中不可或缺的一部分。无论如何,总是建议使用短期的上下文(或会话),否则它们会变得非常沉重而且很慢。 –