我有一组基于实体框架(EF)的存储库,其中一些处理可以被软删除的实体(并非所有这些都可以)。实体由EF自动生成。到目前为止,我有:
可以软删除的实体实现ICanBeSoftDeleted接口:
public interface ICanBeSoftDeleted
{
bool IsDeleted { get; set; }
}
对于这些实体,我使用实现ISoftDeleteRepository的存储库:
public interface ISoftDeleteRepository<T> : IRepository<T> where T : class, ICanBeSoftDeleted
{
void SoftDelete(T entity);
void SoftDelete(Expression<Func<T, bool>> where);
}
我还有一个基类,SoftDeleteRepositoryBase,它扩展了RepositoryBase并添加了软删除方法:
public abstract class SoftDeleteRepositoryBase<T> : RepositoryBase<T> where T : class, ICanBeSoftDeleted
{
public virtual void SoftDelete(T entity)
{
entity.IsDeleted = true;
Update(entity);
}
public virtual void SoftDelete(Expression<Func<T, bool>> where)
{
var entitiesToDelete = GetMany(where).AsEnumerable();
foreach (T entity in entitiesToDelete)
{
this.Delete(entity);
}
}
}
一切正常。但是,此代码是分发给直接调用存储库的用户的内部库的一部分,我不希望它们更改“IsDeleted”属性,只读取它或删除调用该方法的实体。现在他们可以做到这一点,因为二传手是公开的。
如何更改代码设计才能执行此操作?我无法更改ICanBeSoftDeleted并删除setter,因为那样我就无法从SoftDeleteRepositories修改它。
由于
更新目前我通过从界面中删除“set”并使用反射设置存储库中的值来解决问题:
public virtual void Delete(T entity)
{
PropertyInfo propertyInfo = entity.GetType().GetProperty("IsDeleted");
propertyInfo.SetValue(entity, true);
Update(entity);
}
然而这对我来说感觉像是一个补丁,我不认为它解决了更大的设计问题......
答案 0 :(得分:1)
您必须将EF课程保留在墙后并映射到POCO;或者在将它们交给消费者时将它们键入界面(不会声明设置者)。
第二个选项使对象保持打开状态,以便通过反射设置已删除的标记。
编辑:对您发布的代码的进一步分析会导致以下问题:
您是否打算让API的消费者能够声明存储库?
仅暴露非通用存储库似乎更明智 - 例如您的API中的CustomerRepository,UserRepository,PurchaseRepository。
非通用API然后形成一个干净的边界,您可以从中将API类与API消费者的POCO分开。
答案 1 :(得分:0)
public bool IsDeleted
{
get
{
return this.isDeleted;
}
//you can use protected if you intend to inherit the property and override it
private set
{
this.isDeleted= value;
}
}
编辑: 这里我描述了一个属性的创建,该属性可用于检测是否从有效位置调用属性或功能。
您需要在类中使用受保护的变量来验证IsDeleted属性。为简单起见,我们假设它是一个字符串,并将其称为softDeleteKey。
您需要为该变量设置一个公共setter,现在我们称之为setSoftDeleteKey。
您需要一个私有函数来检查密钥的有效性,如果有效则返回true,如果无效则返回false。我们称之为validateSoftDeleteKey。
实现一个名为isSoftDeleteKeyValid的只读属性,该属性将调用3中描述的函数。
在IsDeleted属性中,检查isSoftDeleteKeyValid。如果返回false,则抛出异常。如果IsDeleted成功,则将softDeleteKey设置为无效值。
在SoftDelete方法中,在设置IsDeleted属性之前调用setSoftDeleteKey并使用有效值。如果发生异常,则使用无效值调用setSoftDeleteKey。
我希望这些想法可以帮到你。
答案 2 :(得分:0)
您可以通过检查实体是否是RepositoryBase中ICanBeSoftDeleted的实现来实现吗?
使用此处的扩展程序: http://bradhe.wordpress.com/2010/07/27/how-to-tell-if-a-type-implements-an-interface-in-net/
public static class TypeExtensions
{
//http://bradhe.wordpress.com/2010/07/27/how-to-tell-if-a-type-implements-an-interface-in-net/
public static bool IsImplementationOf(this Type baseType, Type interfaceType)
{
return baseType.GetInterfaces().Any(interfaceType.Equals);
}
}
public interface IRepository<T>
{
void Delete(T entity);
}
public class RepositoryBase<T> : IRepository<T> where T : class
{
public void Delete(T entity)
{
if (typeof(T).IsImplementationOf(typeof(ICanBeSoftDeleted)))
{
((ICanBeSoftDeleted)entity).IsDeleted = true;
//etc
}
else
{
//hard delete
}
}
}
public class Customer : ICanBeSoftDeleted
{
public bool IsDeleted { get; set; }
}
public class UOW
{
private IRepository<T> GetRepository<T>()
{
return (IRepository<T>)new RepositoryBase<T>();
}
public IRepository<Customer> CustomerRepository
{
get
{
return GetRepository<Customer>();
}
}
}
public interface ICanBeSoftDeleted
{
bool IsDeleted { get; set; }
}
答案 3 :(得分:0)
这个怎么样:
public interface ICanBeSoftDeleted
{
bool IsDeleted { get; }
}
public abstract class CanBeSoftDeleted : ICanBeSoftDeleted
{
private bool _IsDeleted;
public bool IsDeleted
{
get { return _IsDeleted; }
}
internal void SetIsDeleted(bool value) { _IsDeleted = value; }
}
然后模型可以继承抽象类