我正在使用一个数据库,设计人员决定用IsHistorical位列标记每个表。没有考虑正确的建模,我无法改变架构。
在开发与导航属性交互的CRUD屏幕时,这会引起一些摩擦。我不能简单地拿一个产品然后编辑它的EntityCollection我必须手动编写IsHistorical检查到处都是它让我疯了。
添加也很可怕,因为到目前为止,我已经编写了所有手动检查以查看添加是否只是软删除,因此我可以只切换IsHistoric而不是添加重复的实体。
我考虑过的三个选项是:
修改t4模板以包含IsHistorical检查和同步。
拦截ObjectContext中的删除和添加,切换IsHistorical列,然后同步对象状态。
订阅AssociationChanged事件并在那里切换IsHistorical列。
有没有人有这方面的经验或者可以推荐最无痛的方法?
注意:是的,我知道,这是糟糕的建模。我已经阅读了有关软删除的相同文章。它很臭,我必须处理这个要求,但我这样做。我只想要最轻松的方法来处理软删除,而无需为我的数据库中的每个导航属性编写相同的代码。
注意#2 LukeLed的答案在技术上是正确的,虽然迫使你陷入一个非常糟糕的穷人ORM,无图形的模式。问题在于,现在我需要从图中删除所有“已删除”的对象,然后在每个对象上调用Delete方法。那不是真的会省去那么多手工仪式编码。现在我没有编写手动IsHistoric检查,而是收集已删除的对象并循环遍历它们。
答案 0 :(得分:8)
我在我的代码中使用通用存储库。你可以这样做:
public class Repository<T> : IRepository<T> where T : EntityObject
{
public void Delete(T obj)
{
if (obj is ISoftDelete)
((ISoftDelete)obj).IsHistorical = true
else
_ctx.DeleteObject(obj);
}
您的List()
方法也会按IsHistorical进行过滤。
修改强>
ISoftDelete
界面:
public interface ISoftDelete
{
bool IsHistorical { get; set; }
}
实体类可以很容易地标记为ISoftDelete,因为它们是部分的。部分类定义需要添加到单独的文件中:
public partial class MyClass : EntityObject, ISoftDelete
{
}
答案 1 :(得分:5)
我确信你知道,当你无法修改架构时,这个问题不会有很好的解决方案。鉴于你不喜欢Repository选项(不过,我想知道你是不是有点急于解雇它),这是我能想到的最好的选择:
ObjectContext.SavingChanges
ObjectStateManager
搜索已删除状态的对象。如果它们具有IsHistorical
属性,请设置该属性,并将对象的状态更改为已修改。当涉及到协会/关系时,这可能会变得棘手,但我认为它或多或少会做你想要的。
答案 2 :(得分:0)
我使用存储库模式也使用与LukLed类似的代码,但我使用反射来查看 IsHistorical 属性是否存在(因为它是一个商定的命名约定):
public class Repository<TEntityModel> where TEntityModel : EntityObject, new()
{
public void Delete(TEntityModel entity)
{
// see if the object has an "IsHistorical" flag
if (typeof(TEntityModel).GetProperty("IsHistorical") != null);
{
// perform soft delete
var historicalProperty = entity.GetType().GetProperty("IsHistorical");
historicalProperty.SetValue(entity, true, null);
}
else
{
// perform real delete
EntityContext.DeleteObject(entity);
}
EntityContext.SaveChanges();
}
}
然后使用简单:
using (var fubarRepository = new Repository<Fubar>)
{
fubarRepository.Delete(someFubar);
}
当然,在实践中,您通过传递PK而不是实例化实体来扩展它以允许删除。