使用LINQ和SubSonic进行对象映射我正在使用SubSonic3.0.0.3ActiveRecord构建一个小项目,我遇到了一个我似乎无法解决的问题。这是LINQ查询:varresult=fromrinRelease.All()leti=Install.All().Count(x=>x.ReleaseId==r.Id)wherer.ProductId==productIdselectnewReleaseInfo{NumberOfInstalls=i,Release=newRelease{Id=r.Id,ProductId=r.ProductId,ReleaseNumber=r.ReleaseNumber,RevisionNumber=r.RevisionNumber,ReleaseDate=r.ReleaseDate,ReleasedBy=r.ReleasedBy}};ReleaseInfo对象是一个自定义类,如下所示:publicclassReleaseInfo{publicReleaseRelease{get;放;}publicintNumberOfInstalls{得到;放;Release和Install是SubSonic生成的类。当我监视结果时,Release属性为空。如果我简化此查询并观察结果,则该值不为空。varresult=fromrinRelease.All()leti=Install.All().Count(x=>x.ReleaseId==r.Id)其中r.ProductId==productId选择新版本{Id=r.Id,ProductId=r.ProductId,ReleaseNumber=r.ReleaseNumber,RevisionNumber=r.RevisionNumber,ReleaseDate=r.ReleaseDate,ReleasedBy=r.ReleasedBy};这是我的LINQ查询问题还是SubSonic限制?我认为问题可能在于您基本上是在复制ORM的功能。理解的关键是这一行:fromrinRelease.All()这行返回数据库中每个项目的完全填充的发布记录列表。永远不需要在查询的其他任何地方创建新版本——只需返回SubSonic已经为您填充的版本!使用此逻辑,您应该能够执行如下操作:varresult=fromrinRelease.All()selectnewReleaseInfo{Release=r,NumberOfInstalls=Install.All().Count(x=>x.ReleaseId==r.Id)};也就是说,您应该查看Install.All()调用,因为这可能非常低效。这将做的是从数据库中提取每个安装,将这些安装混合到对象中,然后比较.NET中每个记录的ID以检查记录是否符合该标准。您可以使用SubSonic中的.Find方法仅从数据库层返回某些记录,这应该有助于显着提高性能。即便如此,膨胀的对象仍然很昂贵,您可能需要在这里考虑视图或存储过程。但作为简单的第一步,以下应该有效:varresult=fromrinRelease.All()selectnewReleaseInfo{Release=r,NumberOfInstalls=Install.Find(x=>x.ReleaseId==r.Id)。数数()};我想我已经找到了这个问题的实际答案。我一直在研究SubSonic源代码,发现在将数据读取器映射到对象时有两种类型的对象投影:一种用于匿名类型和分组,一种用于其他所有类型:这是一个片段:SubSonic的第269–298行。Linq.Structure.DbQueryProviderIEnumerable结果;类型type=typeof(T);//这太hacky了-问题是下面的投影仪使用了Expression.Convert,这是一个瓶颈//它比我们的ToEnumerable慢了大约10倍。但是,我们的ToEnumerable会偶然发现Anon类型和分组//因为它不知道如何实例化它们(我试过了-不够聪明)。所以我们在这里做了一些诡计。if(type.Name.Contains("AnonymousType")||type.Name.StartsWith("Grouping`")||type.FullName.StartsWith("System.")){varreader=_provider.ExecuteReader(cmd);结果=项目(阅读器,查询.Projector);}else{using(varreader=_provider.ExecuteReader(cmd)){//使用我们的阅读器内容//感谢PascalLaCroix的帮助...varresultType=typeof(T);如果(结果类型.IsValueType){结果=reader.ToEnumerableValueType();}else{恢复lt=reader.ToEnumerable();}}}返回结果;事实证明,SubSonicToEnumerable将尝试将数据读取器中的列名称与您尝试投影到MyLinqSQL查询的对象中的属性相匹配,如下所示:SELECT[t0].[Id],[t0]。[ProductId],[t0].[ReleaseDate],[t0].[ReleasedBy],[t0].[ReleaseNumber],[t0].[RevisionNumber],[t0].[c0]FROM(SELECT[t1].[Id],[t1].[ProductId],[t1].[ReleaseDate],[t1].[ReleasedBy],[t1].[ReleaseNumber],[t1].[RevisionNumber],(选择计数(*)FROM[dbo].[Install]ASt2WHERE([t2].[ReleaseId]=[t1].[Id]))ASc0FROM[dbo].[Release]ASt1)ASt0WHERE([t0].[ProductId]=2)注意[t0]。[c0]与我的属性名称NumberOfInstalls不同。所以c0的值永远不会投射到我的对象中。修复:您可以简单地删除if语句并使用慢10倍的投影,一切都会正常进行。我们有一个错误的预测,在某些情况下会失败——我认为它已经被修补了,但我需要更多的测试。我邀请您尝试最新的-我想我们已经修复了它...抱歉这么含糊,但是3.0.0.1和3.0.0.3之间有一个错误,我找不到它。这在3.0.0.4中修复了吗?我很生气找到这篇文章。经过2天的尝试弄清楚为什么我的预测不起作用-除非属性名称与查询完全匹配-我终于来了。我非常依赖SSSimpleRepository,现在回头已经太晚了。像这样的错误是致命的。有机会解决吗?我现在走的是慢10倍的路线,这样我至少可以为我的客户腾出时间。想要更快的方法才能正常工作:)以上就是《C#学习教程:ObjectMappingwithLINQandSubSonic》的全部内容,如果对大家有用,需要进一步了解C#学习教程,希望大家多多包涵更多关注—本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
