我正在做一些研发工作,因此正在研究设计模式.我最近一直在阅读规范模式,并参考了这篇伟大的文章.
我对代码的简洁性和清洁度很感兴趣,但我开始比较使用其他技术实现相同的清洁度.
考虑以下服务层的接口合同:
public interface IFooDataService
{
ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification);
ICollection<Foo> GetFooByPredicate(Func<Foo,bool> predicate);
ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs);
}
Run Code Online (Sandbox Code Playgroud)
所以,一些初步要点:
现在,进入实施:
public ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification)
{
return fooDataRepository
.Find()
.Where(f => specification.IsSatisfiedBy(f))
.ToList();
}
public ICollection<Foo> GetFooByPredicate(Func<Foo, bool> predicate)
{
return fooDataRepository
.Find()
.Where(predicate)
.ToList();
}
public ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs)
{
return fooDataRepository
.Find()
.WhereMeetsSearchCriteria(searchArgs)
.ToList();
}
Run Code Online (Sandbox Code Playgroud)
实施要点:
那么,话虽如此,在什么条件下你会使用上述3种技术之一?
我对规范模式的看法:
我对扩展方法(管道和过滤器)的看法:
我对谓词方法的看法:
architecture extension-methods design-patterns specification-pattern pipes-filters
我目前正在建立一个新项目,我遇到了一些问题,我需要一点点输入.
这就是我在考虑的问题:
我想要一个通用的存储库
我不想从我的存储库返回IQueryable.
我想将我的查询封装在规范中.
我已经实现了规范模式
它需要易于测试
现在这是我陷入困境的地方,我的问题是哪种方式是使用一个或多个规范调用find方法的最优雅方式:
(流利): bannerRepository.Find().IsAvailableForFrontend().IsSmallMediaBanner()
或者用我的规范将查询表达为lambdas
(波长): bannerRepository.Find.Where(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner)
或者可能是其他一些方式?最重要的是,实现MVC前端的人应该具有良好的存储库直观体验.
我希望实现的是保持som灵活性,以便能够结合规范,并提供"过滤"的经验与规范,但不会泄漏IQueryable到控制器,但更像是一个ISpecifiable,只允许使用规范而不是Linq修改查询.但我是否只是以这种方式将查询逻辑泄漏给控制器?
我试图掌握规范模式,我对它有点困惑.我真的觉得它对我的具体要求没有帮助.我想知道如果我更喜欢扩展方法来解决我的复杂问题,那会是什么问题?例如
public static class ProductExtensions
{
public static IQueryable<Product> InStocks(this IQueryable<Product> query)
{
return query.Where(p => p.InStock && !p.IsDeleted /*others goes here*/);
}
}
Run Code Online (Sandbox Code Playgroud)
我发现用扩展方法包装我的长规格而不是使用spesification模式很有帮助.这有什么问题?
我正在尝试将规范模式应用于我的验证逻辑.但我在异步验证方面遇到了一些问题.
假设我有一个AddRequest需要验证的实体(有2个字符串属性FileName和Content).
我需要创建3个验证器:
验证FileName是否包含无效字符
验证内容是否正确
异步验证数据库中是否存在具有FileName的文件.在这种情况下,我应该有类似的东西Task<bool> IsSatisfiedByAsync
但我怎么能同时实现IsSatisfiedBy和IsSatisfiedByAsync?我应该创建2个接口ISpecification,IAsyncSpecification或者我可以在一个接口中创建吗?
我的版本ISpecification(我只需和)
public interface ISpecification
{
bool IsSatisfiedBy(object candidate);
ISpecification And(ISpecification other);
}
Run Code Online (Sandbox Code Playgroud)
AndSpecification
public class AndSpecification : CompositeSpecification
{
private ISpecification leftCondition;
private ISpecification rightCondition;
public AndSpecification(ISpecification left, ISpecification right)
{
leftCondition = left;
rightCondition = right;
}
public override bool IsSatisfiedBy(object o)
{
return leftCondition.IsSatisfiedBy(o) && rightCondition.IsSatisfiedBy(o);
}
}
Run Code Online (Sandbox Code Playgroud)
要验证文件是否存在,我应该使用:
await _fileStorage.FileExistsAsync(addRequest.FileName);
Run Code Online (Sandbox Code Playgroud)
IsSatisfiedBy如果我确实需要那个异步,我怎么能写那个支票呢?
例如,这里是FileName的验证器(1)
public …Run Code Online (Sandbox Code Playgroud) c# design-patterns domain-driven-design specification-pattern async-await
我已经使用Linq实现了规范模式,如下所述https://www.packtpub.com/article/nhibernate-3-using-linq-specifications-data-access-layer
我现在想要增加急切负载的能力,并且不确定最好的方法.
链接示例中的通用存储库类:
public IEnumerable<T> FindAll(Specification<T> specification)
{
var query = GetQuery(specification);
return Transact(() => query.ToList());
}
public T FindOne(Specification<T> specification)
{
var query = GetQuery(specification);
return Transact(() => query.SingleOrDefault());
}
private IQueryable<T> GetQuery(
Specification<T> specification)
{
return session.Query<T>()
.Where(specification.IsSatisfiedBy());
}
Run Code Online (Sandbox Code Playgroud)
并且规范实现:
public class MoviesDirectedBy : Specification<Movie>
{
private readonly string _director;
public MoviesDirectedBy(string director)
{
_director = director;
}
public override
Expression<Func<Movie, bool>> IsSatisfiedBy()
{
return m => m.Director == _director;
}
}
Run Code Online (Sandbox Code Playgroud)
这很好用,我现在想要添加能够加载的能力.我理解NHibernate的热切加载可以通过在查询上使用Fetch来完成.
我正在寻找的是是否在规范中封装急切的加载逻辑或将其传递到存储库,以及实现此目的所需的Linq /表达式树语法(即如何完成它的示例).
linq nhibernate specification-pattern repository-pattern eager-loading
有时您需要定义一些业务规则,规范模式是一个有用的工具。例如:
public class CanBorrowBooksSpec : ISpecification<Customer>
{
public bool Satisfies(Customer customer)
{
return customer.HasLibraryCard
&& !customer.UnpaidFines.Any();
}
}
Run Code Online (Sandbox Code Playgroud)
然而,我经常发现我需要将这些规则“推送”到 SQL 中以提高性能或满足记录分页列表之类的要求。
然后,我必须为规则编写代码两次,一次使用 CLR 代码,一次使用 SQL(或 ORM 语言)。
您如何组织这样的代码?
最好将代码放在同一个类中。这样,如果开发人员正在更新业务规则,他们忘记更新两组代码的可能性就较小。例如:
public class CanBorrowBooksSpec : ISpecification<Customer>
{
public bool Satisfies(Customer customer)
{
return customer.HasLibraryCard
&& !customer.UnpaidFines.Any();
}
public void AddSql(StringBuilder sql)
{
sql.Append(@"customer.HasLibraryCard
AND NOT EXISTS (SELECT Id FROM CustomerUnpaidFines WHERE CustomerId = customer.Id)");
}
}
Run Code Online (Sandbox Code Playgroud)
然而,这对我来说似乎很难看,因为我们现在将担忧混合在一起。
另一种替代方案是使用 Linq-To-YourORM 解决方案,因为 LINQ 代码可以针对集合运行,也可以转换为 SQL。但我发现,除了最琐碎的场景之外,这种解决方案几乎不可能实现。
你做什么工作?
我正在使用这种形式的规格:
public static Expression<Func<User, bool>> IsSuperhero
{
get
{
return x => x.CanFly && x.CanShootLasersFromEyes;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我可以在表单中使用此规范:
var superHeroes = workspace.GetDataSource<User>().Where(UserSpecifications.IsSuperhero);
Run Code Online (Sandbox Code Playgroud)
但是我不确定如何对这样的关联对象使用规范:
var loginsBySuperheroes = workspace.GetDataSource<Login>().Where(x => x.User [ ??? ]);
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点,还是我需要重新考虑我的规范实施?
我尝试使用 CQRS 以 DDD 方式实现一些应用程序。我使用 asp.net core 应用程序,以及 Microsoft(在微服务书中)我使用 Mediatr。我想实现文章的过滤。为此,人们建议使用规范模式并将所有规范存储在域中(什么层应包含 DDD 中的查询)。
但是如果我使用dapper,我该如何处理解析表达式呢?对于 EF,这不是问题,但对于原始 SQL,却是问题。我认为不值得将表达式树解析器和转换器实现为 SQL。更简单的方法是在 Domain 中存储一些 FilterModel,然后通过在基础设施模型中遍历该模型来构建 SQL 或 SphinxQl。该解决方案符合 DDD 原则吗?我将不胜感激的建议)
我为我的 .net core 项目应用了规范模式。我还为包含、排序、分页等创建了自定义规范。
我sort使用 queryString 从 api url 获取值并将其传递给自定义规范类。在本课程中,我添加了一些switch case用于确定哪一列应该orderBy或orderByDescending
但该表中的列太多。那么有什么方法可以将该sort变量同时应用于所有列吗?或者我必须将所有列写入switch?
这是我的自定义规范类。
public class PersonsWithGroupsAndPrivileges : BaseSpecification<Person>
{
public PersonsWithGroupsAndPrivileges(string sort) : base()
{
AddInclude(x => x.Group);
AddInclude(x => x.Privilege);
if(!string.IsNullOrEmpty(sort))
{
switch (sort)
{
case "gender": ApplyOrderBy(x => x.Gender); break;
case "genderDesc": ApplyOrderByDescending(x => x.Gender); break;
case "roomNo": ApplyOrderBy(x => x.RoomNo); break;
case "roomNoDesc": ApplyOrderByDescending(x => x.RoomNo); break;
default: ApplyOrderBy(x => x.Name); break;
}
} …Run Code Online (Sandbox Code Playgroud) 我正在尝试利用Ardalis.Specification库在我的 asp.net 6 项目中应用规范模式。
安装库后,我创建了以下规范
public class ProductByIdsSpec : Specification<Product, ProductMenuItem>
{
public ClientRecordByIdsSpec(IEnumerable<int> ids)
{
if (ids == null || !ids.Any())
{
return;
}
Query.Where(x => ids.Contains(x.Id));
// some how I need to map Product to ProductMenuItem so only the needed columns are pulled from the database.
}
}
Run Code Online (Sandbox Code Playgroud)
我不想Product从数据库中提取每个值,而是只想通过将数据投影到ProductMenuItem. 上述规范返回以下错误
SelectorNotFoundException Ardalis.Specification.SelectorNotFoundException:规范必须定义选择器
如何定义实体(即Product)和结果对象(即ProductMenuItem)之间的映射?
我尝试添加Select()定义但给了我同样的错误
public class ProductByIdsSpec : Specification<Product, ProductMenuItem>
{
public ClientRecordByIdsSpec(IEnumerable<int> ids)
{
if …Run Code Online (Sandbox Code Playgroud) c# specifications specification-pattern asp.net-core ardalis-specification
c# ×7
.net ×2
linq ×2
.net-core ×1
architecture ×1
asp.net-core ×1
async-await ×1
nhibernate ×1
orm ×1
repository ×1
sql ×1