问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

Entity Framework怎么GroupBY多个字段

发布网友 发布时间:2022-04-13 14:41

我来回答

1个回答

热心网友 时间:2022-04-13 16:10

一、使用存储过程的必要性我们知道EF通过元数据,即概念模型(ConceptModel)、存储模型(StorageModel)和概念/存储映射(C/SMapping),和状态追踪(StateTracking)机制可以为基于模型的操作自动生成SQL。对于一些简单的项目开发,这是非常理想的,因为他们完全可以不用关注数据存储层面的东西,你可以采用一些完全不具有数据库知识的开发者。但是理想总归是理想,对于企业级开发来说,我们需要的是对数据库层面数据的操作有自己的控制。在这方面,我们可以随便举两个典型的场景:逻辑删除:对于一些重要的数据,我们可能需要让它们永久保存。当我们试图“删除”这些数据的时候,我们并不是将它们从数据表中移除(物理删除),而是为这条记录作一个已经被删除的标记;并发处理:为了解决相同的数据在获取和提交这段时间内被另一个用户修改或者删除,我们往往SQL层面增加并发控制的逻辑。比较典型的做法是在每一个表中添加一个VersionNo这样的字段,你可以采用TimeStamp,也可以直接采用INT或者GUID。在执行Update或者Delete的SQL中判断之前获取的VersionNo是否和当前的一致。让解决这些问题,就不能使用EF为我们自动生成的SQL,只有通过使用我们自定义的存储过程。二、实现存储过程自动匹配的必要条件本篇文章提供的存储过程自动映射机制是通过代码生成的方式完成的。说白了,就是读取原来的.edmx模型文件,通过分析在存储模型中使用的数据表,导入基于该表的CUD存储过程;然后再概念/存储映射节点中添加实体和这些存储过程的映射关系。那实现这样的代码生成,需要具有如下三个固定的映射规则。数据表名-存储过程名:这个映射关系帮助我们通过存储模型中的实体名找到对应CUD三个存储过程(如果实体是数据表);数据表列名-存储过程参数名:当存储过程被执行的时候,通过这个映射让概念模型实体某个属性值作为对应的参数;存储过程参数名-版本:当进行参数赋值的时候,通过这个映射决定是使用Original或者Current版本。在实际的开发过程中,这样的标准存储过程一般都是通过代码生成器生成的(在我的文章《创建代码生成器可以很简单:如何通过T4模板生成代码?[下篇]》中有过相应的实现),它们具有这样的映射关系。基于这三种映射关系,我定义了如下一个名为IProcereNameConverter的接口。其中OperationKind是我自定义的一个表示CUD操作类型的枚举。1:publicinterfaceIProcereNameConverter2:{3:stringGetProcereName(stringtableName,OperationKindoperationKind);4:stringGetColumnName(stringparameterName);5:DataRowVersionGetVersion(stringparameterName);6:}7:8:publicenumOperationKind9:{10:Insert,11:Update,12:Delete13:}按照我们当前项目采用的命名规范,我定义了如下一个默认的DefaultNameConverter。它体现的是这样的映射关系,比如有个数据表明为T_USER(大写,单词之间用“_”隔开,并以T_为前缀),它对应的CUD存储过程名分别为:P_USER_I、P_USER_U和P_USER_D(大写,以代表存储过程的P_为前缀,后缀_I/U/D表示CUD操作类型,中间为去除前缀的表名)。如果列名为USER_ID,参数名为p_user_id(小写,加p_前缀)。如果需要用Original值为参数赋值,需要将p_前缀改成o_前缀(o_user_id)。1:publicclassDefaultNameConverter:IProcereNameConverter2:{3:publicstringGetProcereName(stringtableName,OperationKindoperationKind)4:{5:switch(operationKind)6:{7:caseOperationKind.Insert:8:returnstring.Format("P_{0}_I",tableName.Substring(2));9:caseOperationKind.Update:10:returnstring.Format("P_{0}_U",tableName.Substring(2));11:default:12:returnstring.Format("P_{0}_D",tableName.Substring(2));13:}14:}15:16:publicstringGetColumnName(stringparameterName)17:{18:returnparameterName.Substring(2).ToUpper();19:}20:21:publicDataRowVersionGetVersion(stringparameterName)22:{23:if(parameterName.StartsWith("o"))24:{25:returnDataRowVersion.Original;26:}27:else28:{29:returnDataRowVersion.Current;30:}31:}32:}三、通过T4生成新的.edmx模型我们采用的基于T4的代码生成,了解EF的应该对T4不会感到陌生了。如果对代码生成感兴趣的话,可以看看我的文章《与VS集成的若干种代码生成解决方案[博文汇总(共8篇)]》。这里利用借助于T4ToolBox这个开源工具箱,并采用SQLServerSMO获取存储过程信息。所有涉及到的文本转化都实现在如下一个ProcereMappingTemplate类型中,由于内容较多,具体实现就忽略了,有兴趣的朋友可能下载源代码。ProcereMappingTemplate具有两个构造函数的参数分别表示:源.edmx文件,服务器和数据库名,存储过程的Schema(默认为dbo)和具体的ProcereNameConverter(默认为DefaultNameConverter)。1:publicclassProcereMappingTemplate:Template2:{3:publicXmlDocumentSourceModel{get;privateset;}4:publicIProcereNameConverterProcereNameConverter{get;privateset;}5:publicDatabaseDatabase{get;privateset;}6:publicstringSchema{get;privateset;}7:8:publicProcereMappingTemplate(stringsourceModelFile,stringserverName,stringdatabaseName);9:publicProcereMappingTemplate(stringsourceModelFile,stringserverName,stringdatabaseName,10:IProcereNameConverterprocereNameConverter,stringschema);11:12:protectedvirtualXElementGenerateStorageModelNode();13:protectedvirtualXElementGenerateMappingNode();14:publicoverridestringTransformText()15:{16:XElementnewStorageModelNode=this.GenerateStorageModelNode();17:XElementnewMappingNode=this.GenerateMappingNode();18:19:XmlNodestorageModelNode=this.SourceModel.GetElementsByTagName("edmx:StorageModels")[0];20:storageModelNode.InnerXml=newStorageModelNode.Elements().ToArray()[0].ToString();21:22:XmlNodemappingNode=this.SourceModel.GetElementsByTagName("edmx:Mappings")[0];23:mappingNode.InnerXml=newMappingNode.Elements().ToArray()[0].ToString();24:25:this.WriteLine("");26:this.Write(this.SourceModel.DocumentElement.OuterXml.Replace("xmlns=\"\"",""));27:returnGenerationEnvironment.ToString();28:}29:}在使用过程中,你只需要在tt模板中创建这个ProcereMappingTemplate对象,调用Render方法即可。1:2:3:4:5:6:7:8:9:四、看看生成出来的.emdx通过上面创建的TT模板(你指定的数据库中一定要存在具有相应映射关系的存储过程),新的.edmx模型文件会作为该tt文件的依赖文件被生成出来。而这个新生成的.edmx具有存储过程映射信息。具体来说,下面是原始的.edmx文件(只保留元数据节点)。1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:19:20:21:22:23:24:25:26:27:28:29:30:31:32:33:34:35:36:37:38:39:40:41:42:43:44:45:46:47:48:49:50:51:
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
...的直线分别与椭圆 C:(x^2)/2+y^2=1 交于A,C与B,D? ...2)作倾斜角互补的两条直线PA、PB,分别交椭圆C于A、B ...1,过点P作倾斜角互补的两条不同的直线PA PB分别交 已知斜率为1/2的直线与椭圆交于A,B两点,点A的坐标为(2,3),且椭圆的右... ...P(1, ), 一斜率为 的直线与此椭圆交于A,B两点,求三角形PAB的面积的... ...过F2作斜率为1的直线L,交椭圆于A,B两点。M为线段的中点,射线OM交椭... 椭圆X2/2+Y2/4=1,过点(1,根号2)做两条互余的直线,与椭圆交AB两点,证A... word里面的标记符号怎么去掉? 5万活期一年利息多少钱是多少? 农业银行存5万一年利息多少? 十场秋雨的前一句是什么 什么花的花粉有毒拜托各位大神 梅州大埔个人交社保多少钱 梅州大埔社保多少钱 卧室内晚上放什么花对人有好处,放什么花对人有害处?白天卧室又适合放什么花呢?什么花有毒? 世界上有毒的而美丽的花排名。 世界上有毒的花吗? 什么花不可带入室内种植,什么花有毒 国家标准的复审周期一般不超过几年 ,由于自己手贱不小心在交管12123软件上用身份证号码注册了新车车主用户给为段友好,本人最近正在考 您好,我是今年6月份刚毕业落户上海的,请问可以报考下半年的事业单位考试吗,户籍是算上海市户口吗? 买得起上海住房的人,以后户口都会是上海户口吗? 怎样正确解决广发信用卡逾期超额 我儿子要去上海读大学,如果把户口迁到所在学校,那毕业了若能在上海工作,户口算真正的上海户口吗? 本科生在上海工作两年可以落户上海户口吗 上海户口落户利弊 优秀农名工落户上海和上海本地户口有区别吗 我现在的户口是上海市户口然后我把我的户口迁到奉贤区,请问我的户口还... 外地人落户上海后,子女是上海户口吗?上海出生,是310开头身份证吗 上海个人户口卡是上海户口吗 meyersound音响北京有吗 谁使用过Meyer_sound? 洗脚桶滚轮下面脏了怎么清理 福州有哪几家代理这些牌子的音响设备,有没有他们的联系电话? L-ACOUSTICS Electro-Voice MeyerSound BOS 求meysound音响的品牌介绍 涌金牌足浴盆的过滤网可以卸下来吗? meyer sound的upj-1p是有源音箱吗 誉公馆和公馆是什么关系 meyer sound音响用什么功放 有听过MeyerSound HD1的吗 MEYER SOUND DDIO24的功能? 模拟人生4住宅世界怎么解锁 云南大剧院官网购票 线阵音响调试全频音响是不是不需要低音 线阵音响4+2和8+4的区别? ipad充电口坏了怎么办 Meyer Sound音箱是哪个国家的 meyer sound leo音响多少钱 meyer sound HD-1做影院好吗 买百元机,是买redmi 9,还是华为畅享10e?