当前位置: 首页 > 编程语言 > C#

实现IQueryableWrappers来转换结果对象分享

时间:2023-04-11 01:18:55 C#

实现IQueryableWrappers来转换结果对象更新2013-08-22:看完“构建IQueryable提供者系列”(感谢链接!)我进一步学习了一个少量。我相应地更新了代码。它仍然不能完全工作。如果我对本教程的理解正确,则在请求多个元素时调用GetEnumerator(例如,通过对可查询函数或任何聚合函数的ToList()调用)。因此,包装器的所有GetEnumerator实现都是在提供程序上调用Execute并传递可查询表达式。在另一种情况下,如果只请求一个元素,则直接调用Execute。queryable的表达式也反映了它是单个元素还是多个元素。这是对的吗?不幸的是,现在我在源查询提供程序上调用Execute时收到InvalidOperationException,提示“序列包含多个元素”。这是什么意思?我只是传递表达式而不进行任何翻译,因为涉及与上面相同的类型。代码中IEnumerable的翻译位可能不完整,但现在我什至没有达到这一点。我正在尝试使用单个基础IQueryable作为数据源来实现一个简单的IQueryable包装器,该包装器为每个结果对象调用一个转换函数。我认为这将是相对微不足道的,因为包装器唯一要做的就是翻译。但我无法让我的实施工作。看看下面我到目前为止所得到的。对于某些查询,它正在工作,但我在某个时候收到StackOverflowExceptionInvalidOperationException。我想这是因为我的可查询和我的查询提供者之间存在循环关联。但我不明白如何正确实施。这里是我的问题和想法:1.为什么IQueryable有一个Provider并且可以再次返回IQueryable?这不是需要无穷无尽的递归吗?2、IEnumerator为什么不能实现?为什么FirstOrDefault不使用枚举器来获取元素?当我调试应用程序时,查询器上的FirstOrDefault()未调用GetEnumerator()。3.由于没有在每种情况下使用枚举器,那么调用翻译函数的正确位置在哪里?QueryProvider的执行方法似乎是正确的地方。但是在某些情况下我是否还需要在枚举器中进行翻译调用?更新:我知道我需要提供我自己的IEnumerable实现,提供一个TranslatingEnumerator并从我的Execute方法返回这个枚举。为了让枚举器GetEnumerator调用Execute(见下文)。请求枚举器的LINQ代码似乎确保表达式实际返回一个IEnumerable。关于代码的一些旁注:背景:我在我的数据访问层实现了我自己的从DbContext接收的实体分离,以防止我的业务层联系实际实体-由于EF的一些错误和其他要求我不能直接使用EF分离实体。谢谢你的帮助!IQueryable实现internalclassTranslatingQueryable:IQueryable{privatereadonlyIQueryProvider_provider;私人只读IQueryable_source;内部TranslatingQueryable(TranslatingQueryProvider提供者,IQueryable来源){Guard.ThrowIfArgumentNull(提供者,“提供者”);Guard.ThrowIfArgumentNull(来源,"来源");_provider=提供者;_source=来源;}internalTranslatingQueryable(FunctranslateFunc,IQueryabledatabaseQueryable):this(newTranslatingQueryProvider(translateFunc,databaseQueryable.Provider),databaseQueryable){}publicIEnumeratorGetEnumerator(){return((IEnumerable)Provider.Execute(Expression)).GetEnumerator();}IEnumeratorIEnumerable.GetEnumerator(){返回((IEnumerable)Provider.Execute(Expression)).GetEnumerator();}publicExpressionExpression{get{return_source.Expression;}}publicTypeElementType{get{returntypeof(TBusinessEntity);}}publicIQueryProviderProvider{get{ret瓮_提供者;}}}IQueryProvider实现publicclassTranslatingQueryProvider:IQueryProvider{privatereadonlyFunc_translateFunc;私有只读IQueryProvider_databaseQueryProvider;publicTranslatingQueryProvider(FunctranslateFunc,IQueryProviderdatabaseQueryProvider){_translateFunc=translateFunc;_databaseQueryProvider=databaseQueryProvider;}publicIQueryableCreateQuery(Expressionexpression){vardatabaseQueryable=_databaseQueryProvider.CreateQuery(expression);返回新的TranslatingQueryable(this,databaseQueryable);}publicIQueryableCreateQuery(Expressionexpression){vardatabaseQueryable=_databaseQueryProvider.CreateQuery(expression);返回新的TranslatingQueryable(this,databaseQueryable);}publicobjectExecute(Expressionexpression){returnExecute(expression);}publicTResultExecute(Expressionexpression){//TODO如果请求枚举,此调用将抛出InvalidOperationExceptionvardatabaseResult=_databaseQueryProvider.Execute(表达式);vardatabaseEnumerable=databaseResultasIEnumerable;if(databaseEnumerable!=null){if(typeof(TResult).IsAssignableFrom(typeof(IEnumerable))){thrownewInvalidOperationException();}return(TResult)(object)newTranslatingEnumerable(databaseEnumerable,_translateFunc);}else{return(TResult)_translateFunc(databaseResult);}}私有类TranslatingEnumerable:IEnumerable{privatereadonlyTranslatingEnumerator_enumerator;publicTranslatingEnumerable(IEnumerabledatabaseEnumerable,FunctranslateFunc){_enumerator=newTranslatingEnumerator(translateFunc,databaseEnumerable.GetEnumerator());}publicIEnumeratorGetEnumerator(){return_enumerator;}}}IEnumerator实现internalclassTranslatingEnumerator:IEnumerator{privatereadonlyFunc_translateFunc;私有只读IEnumerator_databaseEnumerator;内部翻译枚举器(FunctranslateFunc,IEnumeratordatabaseEnumerator){_translateFunc=translateFunc;_databaseEnumerator=数据库枚举器;}publicboolMoveNext(){return_databaseEnumerator.MoveNext();}publicvoidReset(){_databaseEnumerator.Reset();当前的);}}objectIEnumerator.Current{get{returnCurrent;好的,我最好回答一下为什么IQueryable有一个可以再次返回IQueryable的Provider的问题?这不是需要无穷无尽的递归吗?您想为此实例返回一个IQueryableSomeEnumerable.Where(x=>x.Field==something).Select(x=>x.SomeOtherField)如果您熟悉该链接,想想为什么JQuery不实现IEnumerator?为什么FirstOrDefault不使用枚举器来获取元素?当我调试应用程序GetEnumerator()时,FirstOrDefault()不会在我的Queryable上调用,因为IQueryable有2个特殊属性QueryProvider和QueryExpression:IQueryable和IEnumerable有什么区别?由于在每种情况下都没有使用枚举器,因此调用翻译函数的正确位置在哪里?QueryProvider的执行方法似乎是正确的地方。但是在某些情况下我是否还需要在枚举器中进行翻译调用?执行是正确的地方,你必须解析表达式树,因为提供者在执行时不知道要做什么。我还添加了这个链接,它在我实现自己的查询提供程序时帮助了我很多。http://blogs.msdn.com/b/mattwar/archive/2008/11/18/linq-links。aspx你可以做的是获取一个dbReader并使用作者在这篇文章中所做的相同方式将其转换为实际对象,而不是读者将你的DBEntity转换为你的BusinessEntity,但我不确定这是否可能.因为每次添加linq子句(Select,Where...)它都会创建一个返回类型的新查询,所以如果你有一个DBEntity实体“实体”并且你做实体。select(x=>x.someField)和一些字段是int类型,现在它是IQueryable,现在你的模型不起作用,因为它期待int并且它正在获取DBEntitity到目前为止,我发现了为什么每次实体异常:实体框架的IQueryable基础结构的实现与构建IQueryable提供程序系列pt中描述的模式非常不同。1.因此,任何使用底层数据库查询获取对象的翻译IQueryable实现都必须使用相同的模式-翻译GetEnumerator()方法只是在底层数据库查询上调用GetEnumerator()并将其注入新的TranslatingEnumerator。以上就是C#学习教程:ImplementingIQueryablewrappertoconverttheresultobject分享的全部内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。涉及侵权,请点击维权联系管理员删除。如需转载请注明出处: