partial class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
}
我的通用存储库为TEntity
类似
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>()
}
我可以访问
Repository<User>().Get();
许多存储库执行相同的操作集,因此它很有用,但现在我想扩展Repository<User>
以支持一些额外的行为。
partial class Repository<User> : IRepository<User>
{
public user DoMagicFunction()
{
}
}
这样我就可以使用
这样的存储库了Repository<User>().DoMagicFunction();
如何为某些Tentity
扩展相同的泛型类以扩展新行为而不是修改它。
我可以像创建另一个UserRepository
来支持新功能一样,但访问者将成为
UserRepository.DoMagicFunction();
但我希望它像
Repository<User>().DoMagicFunction();
答案 0 :(得分:8)
您可以使用扩展方法:
public static class ExtensionMethods {
public static User DoMagicFunction(this Repository<User> repository) {
// some magic
return null; //or another user
}
}
因此,这将以一种语法上很好的方式将函数添加到Repository<User>
个对象。
如果您不仅要支持User
s,而且支持支持User
s 的子类,则可以使该函数具有通用性:
public static class ExtensionMethods {
public static TEntity DoMagicFunction<TEntity>(this Repository<TEntity> repository)
where TEntity : User {
// some magic
return null; //or another TEntity
}
}
答案 1 :(得分:1)
如果您想扩展任何存储库,您可以这样做。
public static class RepositoryExtension
{
public static void MagicMethod<TEntity>(this IRepository<TEntity> repo) where TEntity: class
{
....
}
}
对于特定的存储库(例如用户存储库),您可以使用类似的过程
public static class RepositoryExtension
{
public static void MagicMethod(this IRepository<User> repo)
{
....
}
}
答案 2 :(得分:1)
C#有一个名为Extension Methods的语言功能,您可能在不知道的情况下从.NET框架中使用它们(例如linq extensions methods)。在不破坏代码功能的情况下,使用扩展方法扩展类甚至接口是很常见的。以下是您案例的示例。
假设您有一个通用的IRepository
接口:
public interface IRepository<TEntity> where TEntity : class, IEntity
{
IQueryable<TEntity> Entities { get; }
}
此界面符合SOLID principles,,尤其是 O
和I
原则。
现在假设IEntity
看起来像这样:
public interface IEntity
{
int Id { get; }
}
现在你可以想象一个经常可重复使用的扩展方法,如下所示:
public static class RepositoryExtensions
{
// similar to your MagicFunction
public static TEntity GetById<TEntity>(this IRepository<TEntity> repository, int id)
where TEntity : class, IEntity
{
return repository.Entities.Single(entity => entity.Id == id);
}
}
以类似的方式,您还可以扩展Repository
类
public static class RepositoryExtensions
{
public static TEntity GenericMagicFunction<TEntity>(this Repository<TEntity> repository)
{
//do some stuff
}
}
你现在可以像这样消费:
var repository = new Repository<User>();
var user = repository.GenericMagicFunction();
您还可以限制扩展方法:
public static class RepositoryExtensions
{
public static User DoMagicFunction(this Repository<User> repository)
{
//do some stuff
}
}
但是这样做会破坏它的目的,你宁愿在Repository<User>
类中实现它。
如果您的系统和架构使用Dependency Injection,则可能向您的消费类注入IRepository<User>
。因此,我提供的第一个或第二个扩展方法示例最有意义。
答案 3 :(得分:1)
扩展方法不是可行的方法,因为实现该方法的代码只能访问它们扩展的类的公共/内部成员,并且您可能希望存储库的DataContext是私有的。
在我看来,你的方法需要稍微改变。
如果您将来想要将Delete方法添加到通用存储库,但是您有一些永远不应删除的实体,该怎么办?您最终会得到一个类似于 @NgModule({
imports: [BrowserModule, FormsModule, HttpModule, AppRoutingModule, PaginationModule.forRoot(), ModalModule.forRoot()],
declarations: [AppComponent, ConfigurationsComponent, CreateConfigurationComponent, PageNotFoundComponent],
bootstrap: [AppComponent],
providers: [ConfigurationsService, CreateConfigurationService, ImageMapper]
})
export class AppModule { }
的存储库实例,您必须记住它永远不会调用delete,否则您将不得不创建一个PurchaseOrder
的后代抛出{ {1}}如果被叫。两者都是糟糕的实现。
相反,您应该完全删除Repository<T>
界面。保留您的InvalidOperationException
类,但为每个只有您需要的方法的实体明确定义存储库接口。
IRepository<T>
当您需要在存储库中使用其他方法时,将它们添加到您的IPurchaseOrderRepository并创建Repository<T>
的后代
public class Repository<TKey, TEntity>......
{
public TEntity Get<TEntity>(TKey key)....
public void Delete(TEntity instance)....
...etc...
}
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
// Note: No delete is exposed
}
MyDependencyInjection.Register<IPurchaseOrderRepository, Repository<PurchaseOrder, int>>();
答案 4 :(得分:1)
Extension method是此案例的最佳选择。
注意:我没有选中,但您应该检查Dependency Injection是否正常工作。
您可以使用以下代码进行测试:
public class Employee
{
}
public class User
{
}
public interface IRepo<TEntity> where TEntity : class
{
TEntity Get(int id);
DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate);
DbContext GetContext();
}
public class Repo<TEntity> : IRepo<TEntity> where TEntity : class
{
DbContext _context;
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>();
}
public DbContext GetContext()
{
return _context;
}
}
public static class RepoExtensions
{
public static ChangeTracker DoMagic(this Repo<User> userRepo)
{
return userRepo.GetContext().ChangeTracker;
}
}
public static class Test
{
public static void DoTest()
{
Repo<User> repoUser = new Repo<User>();
repoUser.DoMagic();
Repo<Employee> repoEmployee = new Repo<Employee>();
//repoEmployee.DoMagic();
}
}