版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
目录系列(1)总览. 错误!未定义书签。系列(2)配置运行环境和日志处理. 错误!未定义书签。系列(3)映射文件基础. 错误!未定义书签。系列(4)iBatisNetAPI 基础 错误!未定义书签。系列(5)ParameterMap. 错误!未定义书签。系列(6)ResultMap. 错误!未定义书签。系列(1)总览学习和使用Ibatisnet已经有一段时间了,前段时间也有写过一些与iBatis相关的Blog。也答应过一些朋友要比较全面地介绍一下iBatis,分享自己的学习过程和使用经验,记录一些常见且容易出现的问题。但由于前段时间一直在准备考试,而且当前的项目时间进度也比较紧,所以一直迟迟未能开始,在这里表示歉意,希望现在开始不会晚。不过最近社区(博客园)好消息不断,我发现越来越多的人开始关注iBatis了,并且也有热心网友在极力推广,如果您已经对它已经有一些了解了,那么更推荐您去阅读ShanYou的文章,他写的文章可能更加适合您。我本人也是一名初学者,这里记录的一些东西可能不会有很多的理论知识(理论知识还不够扎实),更多的可能是突出自己学习过程中需要很长时间来解决的一些问题,或者是个人认为特别重要,并且容易忘记的细节。水平有限,出现错误在所难免,如在这过程中不当之处敬请愿谅,并请不啬赐教。废话一翻后,进入今天的正题。今天的主题是Introduction,非官方正式介绍的中文版,更多详细的介绍请参阅官方文档。我们要使用它就必须要知道它是干什么用的,能为我们做哪些工作,开发效率如何,执行效率如何,技术难度怎么样。提到iBatis,大家可能会与ORM技术联系起来。是的,没错,它与 ORM技术有一定程度上的联系,但是更确切地讲,它并不是一种很正统的 ORMW决方案。因为它不像NHibernate那样,具备全自动的数据操作,包括查询,插入,更新,删除;也没有像它那样,与数据库的约束关系有紧密的联系(对NHibernate的了解不多,如果有不妥之处,希望能留下你们的臭鸡蛋,等着下回用)。iBatis为我们提供了一种更为灵活的方便的可控的方式去实现类ORM勺解决方案。我们需要自己来控制SQL语句,这样做有好处在于,我们可以更灵活地根据我们的需求,编写更加具备性能,功能优势的 SQL语句,但它的缺点同样明显,我们还是需要管理和编写SQL语句。但是值得感到高兴的是,我们只需要提供这些 SQL语句,和为它提供它所需的参数外,接下来的事情就无需我们参与了。这也是 iBatis最核心的功能,也是它为我们所做最多的工作了。 根据配置好的SQL语句和参数条件,它会动态生成一条可执行的SQL语句,然后根据具体传进来的参数值,为这些 SQL参数提供不同的具体值。然后根据配置好的数据访问驱动, 自动为DbComman添加DbParameter,自动执行SQL语句,使用IDataReader返回出数据集,生成并返回一个或多个强类型数据类对象(数据集用 IList集合对象表示)。我曾经在 CommunityServer中也见过类似的返回强类型数据对象的实现,但是需要很多的代码,与直接返回 DataTable相比,重复代码会更多。所有的这些在 iBatis中,只需要提供一个配置文件,调用它提供的 SqlMapper实例对象中的方法就可以很简单容易地实现了。 当然你也许会说,那这样如果系统比较大的话,可能就需要很多的配置文件了。是的,又陷了另一个极端了。怎么办呢?没办法,鱼和熊掌不能兼得啊。这里还不得不重点强调一下,如果你是经常在存储过程中拼接 SQL语句的话,那我就更加推荐你马上就开始使用iBatis吧。提到数据操作,就不能不提到数据的安全性和完整性问题了,也就是数据操作的事务问题。如果你是直接使用进行事务操作的话,那您可能需要写更多的代码了,当然我们可以使用 EnterpriseLibrary 来简化我们的工作。那现在通过一段简单的代码也看一下在 iBatis中该如何实现事务吧:=newDescription;("updateitem",item);();~properties :可以根据需要配置一些常量属性。如果这些属性有很多的话可以单独写一个文件里面,再通过 resource(或url,embedded分别是引用url和编译在程序中的资源文件)属性引用进来。如:vpropertiesresource="../../">vpropertykey="useStatementNamespaces"value="false"/>v/properties>这个配置节是可选的。settings :包括有三个配置段:vsettinguseStatementNamespaces="${useStatementNamespaces}"/>vsettingcacheModelsEnabled="true"/>vsettingvalidateSqlMap="false"/>useStatementNamespaces:在文档中说明它的作用是配置在使用语句 ID的时候要不要加命名空间,例中${useStatementNamespaces}就是使用properties中的一个属性,默认是false。cacheModelsEnabled是配置要不要启用 iBatis的缓存模型,默认是true。validateSqlMap 是配置要不要启示验证映射文件,默认是false。providers:配置数据驱动提供类配置文件的路径和文件名。vprovidersresource=""/> ]database:数据库的信息,包括使用哪些数据库驱动和数据连接字符串的配置。vdatabase>v!--Optional(default)-->vprovidername=""/>vdataSourcename="iBatisNet"connectionString=""/></database>alias:类型别名的配置,为了使用更方便的使用类(类名更短),就需在这里进行别名的配置。typeHandlers :这个就相对比较复杂些了,到目前我也没有使用到。从字面上理解,它是一个类型的处理器,它的作用是当你使用的数据库当中有 iBatis不支持或不认识的字段(或者不希望默认的处理方式),那就可以为它取一个名字,并且指定对应的 .NET类型来处理它。<typeHandlers>vtypeHandlertype="bool"dbType="Varchar"callback="OuiNonBool"/>v/typeHandlers>sqlMaps :用来包含当前已经写好的,并且需要用到的数据类映射文件。<sqlMaps>
<!--vsqlMapurl="E:/Projet/iBatis/trunk/cs/mapper/"/>vsqlMapresource="Mappers/"/><!--Rem:IfusedasembbededResources,usevsqlMapembedded=""/>-->resouce,resouce,url,以上就是的基本内容了。注意,以上凡是涉及到引用外部文件的都支持embedded三种方式。的配置类很简单,在默认的中已经有很多不同数据库的数据驱动,而在的 database配置的provider属性就是使用中已有的不同驱动中的一个。 以下是添加一个 数据访问驱动:vprovidername=""description="MicrosoftSQLServer2000/2005,providerinframework.NETenabled="true"default="true"assemblyName=",Version=Culture=neutral,PublicKeyToken=b77a5c561934e089"connectionClass=""commandClass=""parameterClass=""parameterDbTypeClass=""parameterDbTypeProperty="SqlDbType"dataAdapterClass=""commandBuilderClass=""usePositionalParameters="false"useParameterPrefixlnSql="true"useParameterPrefixlnParameter="true"parameterPrefix="@"/>OK以上就是和的基本内容。下面我来介绍一下如果利用 Iog4net来记录iBatisnet的一些运行日志记录。这也是我当初花了很多的时间才解决的一个问题, 因为记录这些日志太重要了,它可以记录下每次生成并执行的 SQL语句,对我们排除配置错误有非常重大的意义。 而但是文档使用的是的话,那可能你怎么折腾都无法搞出如果你是使用最新版的(当前是),
但是文档使用的是的话,那可能你怎么折腾都无法搞出认为跟文档介绍的一样, 生成一个,并记录下日志。但事实不是这样的,在的版本中还需要再加上一个配置节组:vsectionGroupname="iBATIS">vsectionname="logging"type=""/></sectionGroup>配置组的配置值如下:<iBATIS><logging><!--vlogFactoryAdaptertype=""><argkey="showLogName"value="true"/><argkey="showDataTime"value="true"/><argkey="level"value="ALL"/><argkey="dateTimeFormat"value="yyyy/MM/ddHH:mm:ss:SSS"/></logFactoryAdapter>--></logFactoryAdapter>-->vlogFactoryAdaptertype="">vargkey="configType"value="inline"/></logFactoryAdapter></logging></iBATIS>经过以上的配置后,再运行程序,就会创建并且记录日志了。 注意:即使是按以上的配置后,有可能还是无法记录日志, 那就可能是和的中的一个或两个没有拷到 bin目录,正常情况下,我们不需引用这两个程序集, 只需把它们拷到运行目录下, 即使你需要记录日志, 但找不到他们,程序仍然能正常执行而不会抛出异常, 如果你没有经验的话,解决这个问题可能需要你很多的时间。以上就是今天要介绍的内容了, Hopethishelps。附注:1.参考资料:DataMapper; 2.配置文件智能提示:把 三个文件拷贝到VS2005:C:\ProgramFiles'MicrosoftVisualStudio8\Xml\Schemas( 安装目录)XSD文件。VS2003:C:\ProgramFiles'MicrosoftVisualStudio.NET2003\Common7\Packages\schemas\xml (安装目录)下,就可以在 VSIDE下编写配置文件时得到 IntellisenseXSD文件。系列(3)映射文件基础iBatis的核心就在于映射文件(DataMapXMLFile)。在映射文件里可以定义包括要执行各种SQL语句,存储过程,输入参数映射,返回结果映射,缓存机制,并且能通过几种相对比较复杂的配置实现对象之间的关联关系和延迟加载。这也是 iBatis区别ORM匡架的,具备更灵活性,更高性能的关键所在。配置文件可以写得很简单,也可以很复杂。复杂配置文件也是出于更好的设计, 更好性能,更好扩展性方面的目的。再复杂的配置文件也是有限的,一个映射文件包括: MappedStatements、ParameterMaps、ResultMaps、CacheModels几个主要的配置,还包括命名空间的配置,类型别名(前一篇中有介绍)的配置。1.MappedStatements:顾名思义就是映射的语句声明。 它是整个iBatis配置核心的核心,真正将被执行的SQL语句(或存储过程)都是必须在这里被显式声明。在 MappedStatements里可以包含有:statement、select、insert、update、delete、procedure这6种不同的语句类型。从词面理解相信就可以了解到这些类型功能的一大半了。 statement可以包含所有类型的SQL语句(存储过程),它是一个泛泛的语句配置,没特别明确的职责,相反,其它5种类型的语句配置就是专门负责各种不同的 SQL语句。下面这张图列出了各种类型的语句的不同职责和调用方法。图片看不清楚?请点击这里查看原图(大图)。2.ParameterMaps:参数映射的配置,它是被用来向一个语句 (statement)提供所需参数的配置。每一个ParameterMaps都有一个自己的ID,在需要的时候需要在statement的parameterMap属性中提供它的ID。但是对一个语句来说,它并不是必须,在 iBatis中还支持内联参数(InlineParameterMaps) 的形式,我们不需单独写一个 ParameterMaps配置,只需要向parameterClass提供参数的类型,可以是元数据类型,复合数据类型, IDictionary数型的弱类型对象(使用key,value的键值对)。在内部访问数据类型的时候只使用#property#的形式访问对应的属性值。注意:在任何地方使用到的parameterClass类型如果是一个元数据类型(int,stringetc),都需要使用#value#的形式的来访问它的值。3.ResultMaps:返回结果的映射关系配置,就是列与属性的对应关系。在statement中使用resultMap属性来指定一个结果映射。对一个statement来说,resultMap也不是必须的,同样的,它仍然可以被resultClass给代替,因为如果返回出结果数据集的列名跟数据对象的属性相同的话,它会自动去匹配,但是它不保证所有列都被会被正确映射(当某列名在对象中找不对应的属性名,这列值将不被处理)。而resultMap则不同,如果已经在resultMap中定义将要使用到列或属性在结果集或数据对象中不存在,将会被认为是错误的,将会抛出异常。通过上面的表可以看到insert,update,delete三种语句类型是没有resultMap和resultClass,因为原则上来说,它们的操作是没有必要返回结果集。注意:如果在一个statement中同时指定了resultMap和resultClass属性的话,那将会优先使用resultMap。同时resultMap也是一个实现对象复杂查询功能的重要手段,如:resultmap的继承(与discriminator配合使用),对象的1..1、1..N关系查询。4.CacheModel:缓存模型。使用在CacheModel中定义好的缓存机制,只需在查询语句配置的cacheModel属性就可以很容易地缓存查询返回的数据集。在iBatis中提供了三种的类型的缓存模式(Memory,LRU,FIFO)算法。三种算法主要在于静态过期策略上的不同,而它们都有相同的动态过期依赖策略,即可以设置执行哪些statement时,缓存过期。注意:iBaits的缓存模型正常情况是非常好用的,但是因为缓存过期策略上的封装性,它在多个服务器,负载平衡场景下还是有它的局限性。有了对iBatis配置系统的一些认识后,现在就先来简单了解一下, iBatis是通过什么的方式去调用映射文件的SQL语句的。这对我们接下来深入了解有很大的帮助。对于简单的iBatis应用场合来说,我想大部分都是集中在与 SqlMapper对象打交道。这个类应该说是一个工具类,因为我们一般都是直接调用这个类的方法去执行 QUID操作,但是它却不是真正的去做这些事情。因为 iBatis内部有很多的类,对象之间的关系是非常复杂的,如果让客户直接去使用它内部方法, 无疑增加了使用的复杂性,同样也会产生很多的冗余代码。因此这里它使用外观设计模式,通过 SqlMapper类封装了iBatis执行数据库访问的复杂操作,包括打开一个会话(Session),获取返回IMappedStatement对象实例,执行数据库访问,关闭连接等相关操作。这样我们在使用 iBatisAPI的时候就可以非常简单调用的一个方法,就可以做所有的事情了。比如查询接口 publicIListQueryForList(stringstatementName,objectparameterobject),它的内部实现代码是这样的。IListlist1;boolflag1=false;IDalSessionsession1if(session1==null)IMappedStatement statement =(statementName);listl=(sessionl,parameterobject);catch那这些代码如果直接在客户代码中去实现, 可想而知工作量会有多大。并且还法保证正确性。以上简单看了一个SqlMapper的作用,那该怎样实例化这个对象呢?实例化它也是一个非常简单的事情。在iBatisNet中,SqlMapper对象默认是一个单件模式的实现。通过 Mapper类的静态Instanee属性来实例化一个SqlMapper对象。这样的设计可能有一部分是出于性能方面的考虑。因为在初始化 SqlMapper对象,需要初始iBatis运行环境配置,读取和初步解析包含的各个映射文件,所以在在系统运行时第一次调用 iBatisNetAPI的时候,可能会需要比较长来处理这个配置。属性的实现如下:publicstaticSqlMapperInstance。if==null)lock(typeof(SqlMapper))所以在使用API的时候可以像下面的这么简单:().lnsert("ContentObject_Defaultlnsert",p_dataObject);当然,如果愿意而且有必要的话, 也完全可以由自己来实例化这个对象, 我们可以直接使用DomSqlMapBuilder,它为我们提供这样的扩展能力,通过它的多种实例方法都可以返回出SqlMapper对象:Build,Configure,ConfigureAndWatch。在需要用到多个数据库或是多种不同数据库类型的场合下,这种方法是非常有用的。注意:在使用一个接口时, 使用的statementName要在对应类型的statement类型。比如在使用Insert接口时,如果你指定的是一个select类型配置语句的话,那将会抛出异常。因为每一种statement类型都对应一种类型,比如如 select 类型的配置语句对应的是 SelectMappedStatement类,它是从MappedStatement继承下来,而它的ExcuteInsert方法是这样实现的session,objectparameterObject)publicoverrideobjectExecuteInsert(IDalSessionsession,objectparameterObject)thrownewDataMapperException("Updatestatementscannotbeexecutedasaqueryinsert.");这样就保证了每一种语句类型的职责明确。系列(5)ParameterMap在用进行数据库访问操作中,最麻烦的就是准备 DbComman必须为它添加DbParameter,特别是当要传的参数特别多的情况下,数据访问层的很多代码都是花在这里。 iBatis的ParameterMap配置就是针对这个问题所提出的一种解决方案,基于 xml的配置,把字段名和对象的属性对应起来,通过运行时的一些工作,自动为DbComman提供它所需的参数集合。从而避免了我们直接写很多重复代码。在配置文件中:SELECTEmployeelD,LastName,FirstNameFROMEmployeesWHEREEmployeelD=#EmployeelD#ORLastName=#LastName#v/select>使用的是内联参数映射的方式,语句的在执行查询时只需为它提供 Employee类型的对象,它就会自动去读自己需要的 EmployeelD,LastName属性的值,返回查询结果。在执行时它所执行的语句如下:[SELECTEmployeeID,LastName,FirstNameFROMEmployeesWHEREEmployeelD=@paramOORLastName=@param1]所需的参数的提供方式如下:[@paramO=[EmployeelD,12],@param1=[LastName,8bbb7bfb-c]]并且,在iBatis中还会指出各个参数的类型:[@param0=[lnt32,],@param仁[String,]]对于下面这个配置:vselectid="Employees_SelectWithParameterMap1"parameterMap="Employee_SelectParameterMapresultClass="Employee"listClass="ArrayList">SELECTEmployeelD,LastName,FirstNameFROMEmployeesWHEREEmployeeID=#EmployeeID#ORLastName=#LastName#ORCountry=#Country#</select>1234下一页它所使用的ParameterMap配置如下:vparameterMapclass="Employee"id="EmployeeSelectParameterMap"><parametercolumn="EmployeeID"property="EmployeeID"dbType="int"type="int"direction="Input"/>vparametercolumn="LastName"property="LastName"dbType="nvarchar"type="string"direction="Input"/>vparametercolumn="Country"property="Country"dbType="nvarchar"type="string"direction="Input"/></parameterMap>在每一个Parameter映射元素可以指定每个属性对应的列, 它的类型和对应的数据库的类型,还可以指定当它为空值时的默认值,具体可以参看官方文档。但是可以看到,我们期待它能和内联参数一样的使用方法, 如上配置的那样。可是行不行呢?从程序的执行结果来看,是不可以的。由于之前在配置SQL语句的时候基本都是使用内联参数没有特别注意到这点。在使用ParameterMap的时候是不能用#property#的形式显示地指定要使用的属性参数,只能通过"?”,顺序替代每一个 parameter元素,如下:vselectid="Employees_SelectWithParameterMap2"parameterMap="Employee_SelectParameterMapresultClass="Employee"listClass="ArrayList">SELECTEmployeelD,LastName,FirstNameFROMEmployeesWHEREEmployeeID=?ORLastName=?ORCountry=?</select>可以看到,由于没有明显地指出 EmployeelD对应哪个属性,那如果把上面的 parameter元素调换一下,那么 EmployeelD所对应的参数值就发生变化了。同时,也是这个原因,通过这种方式的参数映射,就无法重复利用每个参数了。 如果仔细观察会发现,既然都指定了column属性了,那它为什么不会自动去配置呢?其实在这边 column属性是不起作用的,它只会作用在执行存储过程的时候。也就是说上面的 Parameter元素中的column属性不是必须的。下面是一个存储过程的例子:vprocedureid="Employee_InsertWithProcedure"parameterMap="Employee_lnsertParameterMap2"resultClass="int">InsertEmployee</procedure>InsertEmployee 接受两个参数@LastName和@FirstName。我给它提供的映射参数如下:vparameterMapclass="Employee"id="Employee_lnsertParameterMap2">vparametercolumn="LastName"property="LastName"dbType="nvarchar"type="string"direction="Input"/>vparametercolumn="FirstName"property="FirstName"dbType="nvarchar"type="stringdirection="Input"/></parameterMap>上面这样的配置的结果是(其中逗号后面的是值):[@LastName=[LastName,9a8bcO59-3],@FirstName=[FirstName,46887db0-2]]但是当我把他们的位置调换了一下。它的结果如下:[@LastName=[FirstName,9a8bcO59-3],@FirstName=[LastName,46887db0-2]]也就是对储存过程也是一样的,参数映射关系仍然与 parameter元素的顺序息息相关的。Column属性仍然没有显示出它的作用。所以使用 ParameterMap还有是有一定的局限性的。但是对存储过程来说,就必须使用这样的方式,因为它只支持 ParameterMap为它提供参数,而不支持内联参数。最后总结列出几点ParameterMap需要特别注意的几个细节:1.在配置ParameterMap的时候,如果传入的参数对像是元数据类型( int,stringetc),那么在配置Parameter元素的时候,property的属性名使用value。通过这种情况主要使用在为存储指定参数的情况下。2.如果ParameterMap中配置的parameter元素不包含在传入参数对象中(属性或IDictionary对象的一个key,value项),将会产生异常,而不管在statement中有没有用到。3.在使用parameterMap的extends属性时,它将会继承extends值对应的parameterMap配置,并且会继承它的所有的参数映射,并且顺序是从继承的那配置为基准开始计算。这个在需要用到extends属性的时候要特别注意。4.在为存储过程传参过程要特别注意,参数映射与存储过程的参数之间的顺序对应要正确。而且必须为提供与存储过程足够的参数(parameter配置足够多),即使存储过程的部分参数已经有默认值了。否则将抛出异常。5.正常情况下,应该尽量使用内联参数。系列(6)ResultMap我们将来讨论一下在iBatis中非常重要的一个内容,在我个人看来,能否真正用好 iBatis的一个关键,这就是ResultMap。字面上理解,它就是结果集的映射,就是将返回的记录逐个字段的映射赋值给对象的属性上。其实如果没有特殊需求的话我们完全可以使用 ResultClass来代替它,因为如果字段与属性一模一样的话,查询出来数据集会自动匹配到 ResultClass指定的类的实例对象,如果字段名不在属性中的话,那这个字段将不会被返回的实例体类对象接受,相当于没有查询出这个字段一样的。每个ResultMap都有一个自己的ID,如果你在中没有配置使用命名空间的话,那么这个ResulteMapID是全局(这点在所有的iBatis配置元素都是一样的),ResultMap一个重要的属性的是class,它将决定这个ResultMap对应的实例的类,换句话讲,它的作用是指出结果集要映射的数据类型。在 extends属性中可以设置它将要继承的 ResultMap,如果给他指定的了值,那么它将会从superResultmap继承所的映射配置字段。定义如下:<resultMaps><resultMapid="DemoResultMap"class="Hashtable">v/resultMap></resultMaps>如果你有正确配置了 iBatis的XSD架构文件的话,那么这时候就会提示 resultMap的定义是不完全的。没错,接下来就是要定义Result元素。每一个result元素都是定义一个字段与数据类属性对应的映射。在每一个 result元素有比较多的属性参数,其中 property和column是必须的,其它的参数属性都是可选的。所以我们在每一个 resultMap中必须定义超过一个以上的result定义。通常以下的配置就可以完成基本的配置了。<resultMaps>vresultMapid="DemoResultMap"class="Hashtable">vresultproperty="id"column="id"/></resultMaps>x属性提供了我们将数据集的第几个下标字段映射到指定的数据对象属性的方案, 但是这种方式应该尽量的少用,你会发现这对我们以后的维护和可读性会产生很大的副作用。 dbType属性明确指出这个字段对应的数据库的类型, 大多数情况我很少会用到。type属性则明确指出这个字段将对应的数据对象属性的数据类型, 通常如果你想保证类型安全的话,设置这个属性是很必要的。resultMapping 属性则稍微复杂一些,它是用在一种场景下,如果一个数据类的属性本身不是基元数据类型, 而是一个复杂数据类型的话,那我们就不可能很简单地给它一个简单的result元素就了事了,还必须给他一个完整的 resultMap。而resultMapping属性就是为了完成这个功能而存在的。它的属性值是一个已存在的 resultMap的ID。nullValue属性就没什么好讲的了,它是给出当这个字段的值为 null的时候,它的默认值是多少。select属性同resultMa
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 语义Web赋能:知识发现的创新路径与实践探索
- 2026黑龙江伊春市铁力市招募公益性岗位人员笔试模拟试题及答案详解
- 词块教学赋能:非英语专业研究生写作能力提升的实证探索
- 评价系统视角下现代服务业企业竞争力影响因素探究-以杭州企业为样本
- 2026年度山东省省级机关公开遴选公务员填报说明考试参考题库及答案详解
- 2026年蚌埠市政务服务中心窗口服务工作人员公开招聘4名笔试备考题库及答案详解
- 2026青海省林业生态建设投资有限责任公司社会招聘2人考试模拟试题及答案详解
- 2026云南玉溪家嘉城市投资有限责任公司招聘工作人员1人考试参考题库及答案详解
- 2026河北石家庄华师职业中学公开招聘教师81人考试模拟试题及答案详解
- 2026云南昆明市盘龙区人民医院招聘高校见习人员20人考试参考题库及答案详解
- 2023年江苏省无锡市中考政治真题含解析
- 新理性主义完整版本
- 江苏省苏州市2021年中考物理真题试卷(答案+解析)
- GB/T 42430-2023血液、尿液中乙醇、甲醇、正丙醇、丙酮、异丙醇和正丁醇检验
- 钢管规格型号重量对照表
- 饲料原料知识和品控
- GB/T 7582-2004声学听阈与年龄关系的统计分布
- GB/T 2946-2018氯化铵
- GB/T 25744-2010钢件渗碳淬火回火金相检验
- GB/T 12540-2009汽车最小转弯直径、最小转弯通道圆直径和外摆值测量方法
- GA/T 1068-2015刑事案件命名规则
评论
0/150
提交评论