我正在构建一个存储库,我在很多地方看到了两个不在存储库外公开 IQueryable 的原因。
1) 首先是因为不同的 LINQ 提供程序可能有不同的行为,这种差异应该包含在存储库中。
2) 第二个是防止服务级别开发人员修改数据库查询,从而意外导致性能问题。
我想问题 2 只能通过将所有查询逻辑保留在存储库中并且不允许任何形式的外部查询构建来避免吗?但这对我来说似乎有点不切实际。
问题 1 似乎可以通过使用数据对象模式来解决。
例如public IEnumerable<T> FindBy(Query query)
我的问题是,为什么我不直接传递一个 lambda 表达式,因为它独立于提供者,似乎可以为我提供与查询对象相同的功能,以及相同的分离级别?
例如public IEnumerable<T> FindBy(Expression<Func<T,bool>> predicate)
有什么理由不这样做吗?它是否违反了某些规则?最佳实践?我应该知道什么?
最佳答案
IQueryable<T> .在您编写另一段“存储库代码”之前,您将从阅读 Ayende 的文章 Architecting in the Pit of Doom - The Evils of the Repository Abstraction Layer 中受益匪浅。
Generic List of OrderBy Lambda 中另一个问题的所有代码除了用不必要和不熟悉的抽象来掩盖现有的有效 API 之外,没有做任何事情。
关于您的两个问题,
LINQ 提供程序的行为确实不同,但只要您传递的谓词可以由 LINQ 提供程序处理,这就无关紧要。否则,您仍然会遇到同样的问题,因为您传递的是 Expression。 , 它被传递给 IQueryable无论如何最终。如果IQueryProvider实现不能处理你的谓词,那么它就不能处理你的谓词。 (如果您需要在无法翻译的进一步过滤之前进行评估,您可以随时调用 ToList())。
修改查询可能会导致性能问题,但更有可能公开急需的功能。此外,与为避免暴露 IQueryable 而提取比您需要的记录更多的记录所导致的性能问题相比,次优 LINQ 查询引起的性能问题可能要小得多。或者通过实际上不做任何事情的臃肿抽象级别系统地过滤任何数据访问逻辑(第一个威胁更为重要)。一般来说,这不会成为问题,因为大多数领先的 LINQ 提供商会在翻译过程中优化您的查询逻辑。
如果您想对前端隐藏您的查询逻辑,那么不要尝试创建通用存储库。使用实际的业务特定方法封装查询。现在,我可能错了,但我假设您对存储库模式的使用是受领域驱动设计的启发。如果是这种情况,那么使用存储库的原因是允许您创建一个主要关注域模型的持久性无知域。然而,使用这种通用存储库除了将语义从 Create Read Update Delete至 Find Add Remove Save .那里没有嵌入任何真正的业务知识。
考虑一个
的意义(和可用性)interface IPersonRepository
{
Person GetById(int id);
IEnumerable<Person> FindByName(string firstName, string lastName);
}
相对于
interface IRepository<T> {
IEnumerable<T> FindBy(Query<T> query);
}
此外,您能否指出使用 IRepository<T> 的好处?完全没有(而不是 IQueryable<T> )?
此外,请考虑使用通用方法,您实际上根本没有封装查询逻辑。您最终在外部构建它,这将导致更多额外的不必要代码。
*关于建议不要使用 IQueryable<T> 的资源的另一条注释, 是否值得查看它们的发布日期。曾经有一段时间,LINQ 提供程序的可用性非常有限(仅限于早期的 EF 和 LINQ-to-SQL)。当时暴露一个IQueryable<T>将导致与 Microsoft ORM 的一些更流行的替代品不兼容(LINQ-to-NHibernate 早已实现)。目前,LINQ 支持在严肃的 ORM .NET 库中几乎无处不在
关于c# - 存储库/IQueryable/查询对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11964578/
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL