我有支持软删除的EF Code First解决方案,因此我们将实体标记为IsDeleted而不是从数据库中删除它们。 我想收集相关对象的集合(延迟加载),因此标记为已删除的实体不会返回给API用户。
这是我使用的简单方法:
public class FilteredCollection<T> : ICollection<T> where T : DeletableEntity
{
private List<T> _listWithDeleted = new List<T>();
protected IEnumerable<T> FilteredItems
{
get { return _listWithDeleted.Where(e => e.IsDeleted == false); }
}
protected bool _IsReadOnly;
public virtual T this[int index]
{
get
{
return FilteredItems.ToList()[index];
}
set
{
FilteredItems.ToList()[index] = value;
}
}
public virtual int Count
{
get
{
return FilteredItems.Count();
}
}
public virtual bool IsReadOnly
{
get
{
return _IsReadOnly;
}
}
public virtual void Add(T entityObject)
{
_listWithDeleted.Add(entityObject);
}
public virtual bool Remove(T entityObject)
{
if (FilteredItems.Contains(entityObject))
{
entityObject.IsDeleted = true;
return true;
}
else
{
return false;
}
}
public bool Contains(T entityObject)
{
return FilteredItems.Contains(entityObject);
}
public virtual void CopyTo(T[] entityObjectArray, int index)
{
var list = FilteredItems.ToList();
list.CopyTo(entityObjectArray, index);
}
public virtual void Clear()
{
foreach (var item in _listWithDeleted)
{
item.IsDeleted = true;
}
}
public virtual IEnumerator<T> GetEnumerator()
{
return FilteredItems.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return FilteredItems.GetEnumerator();
}
}
我已经实现了ICollection,因此它在内部过滤对象。我使用此类而不是ICollection,因此过滤后的实体将返回给我。 我做了一些测试,看起来效果很好,但我对这个解决方案感到不舒服。
请您告诉我这种方法的缺点,或者如果您知道更好的方法,请提出建议。
事先感谢,
-Petro
答案 0 :(得分:1)
这是错误的解决方案,因为它会在您的应用程序中进行过滤。如果您的数据库将增长并且将有越来越多的软删除项目,您将始终需要在应用过滤器之前加载所有这些项目。这很快就会成为非常大的性能问题。
你应该在数据库中进行过滤,但这与懒惰和急切的加载相反。解决方案可以是条件映射(只有未映射的已删除项目),但它不允许映射IsDeleted
属性 - 您必须使用存储过程软删除您的实体,而不能先使用代码映射
首先结合使用EF代码+软删除,您应该完全避免延迟和急切加载,并使用单独的查询来获取过滤数据或使用显式加载。