亚洲必赢手机【转】你必须理解之EF知识和经验。【转】你得知道之EF知识及更,ef知识更。

by admin on 2018年10月10日

【转】你不能不掌握的EF知识和经历

【转】你得理解的EF知识以及更,ef知识更

【转】你不能不明白之EF知识与经历

瞩目:以下内容如果没特意说明,默认使用的EF6.0版本,code first模式。

只顾:以下内容如果没特意说明,默认使用的EF6.0版本,code first模式。

推荐MiniProfiler插件

工欲善其事,必先利其器。

俺们运用EF和当老大死程度增长了开发进度,不过随后带动的凡不少属性低下的写法与扭转不太高速之sql。

尽管我们可以行使SQL Server
Profiler来监控实施之sql,不过个人认为就是麻烦,每次要开拓、过滤、清除、关闭。

在此间强烈推荐一个插件MiniProfiler。实时监察页面请求对承诺执行之sql语句、执行时间。简单、方便、针对性强。

若果图:(具体采用以及介绍请走)

推荐MiniProfiler插件

工欲善其事,必先利其器。

俺们以EF和当挺酷程度增长了开进度,不过随着带动的凡多属性低下的写法与浮动不太高速的sql。

虽然我们可以应用SQL Server
Profiler来监控实施之sql,不过个人认为就是麻烦,每次需要开辟、过滤、清除、关闭。

在此强烈推荐一个插件MiniProfiler。实时监察页面请求对诺执行之sql语句、执行时间。简单、方便、针对性强。

如图:(实际使用及介绍请走)

亚洲必赢手机 1

数准备

新建实体:Score(成绩分数表)、Student(学生说明)、Teacher(老师表)

亚洲必赢手机 2

末尾会为出demo代码下充斥链接

数准备

新建实体:Score(成绩分数表)、Student(学生说明)、Teacher(老师表)

亚洲必赢手机 3

末尾会受出demo代码下充斥链接

foreach循环的陷进 

1.有关延迟加载

亚洲必赢手机 4

伸手看上图红框。为什么StudentId有价,而Studet为null?因为使用code
first,需要设置导航属性也virtual,才见面加载延迟加载数据。

亚洲必赢手机 5

2.关于在循环中做客导航属性之老大处理(接着上面,加上virtual后会报以下很)

“已来打开的跟是 Command 相关联的 DataReader,必须首先将它们倒闭。”

亚洲必赢手机 6

解决方案:

  • 方案1、设定ConnectionString加上MultipleActiveResultSets=true,但唯有适用于SQL
    2005自此的版本
  • 方案2、或者先念来放置在List中

3.之上两接触只有为热身,我们说的陷阱才刚刚开始!

亚洲必赢手机 7

下一场我们点击打开MiniProfiler工具(不要给吓到)

亚洲必赢手机 8

亚洲必赢手机 9

缓解方案:使用Include来得连续查询(注意:需要手动导入using
System.Data.Entity 不然Include只能传表名字符串)。

亚洲必赢手机 10

还拘留MiniProfiler的监察(瞬间101漫漫sql变成了1修,这其间的性质可想而知。)

亚洲必赢手机 11

foreach循环的陷进 

1.关于推迟加载

亚洲必赢手机 12

请看上图红框。为什么StudentId有价,而Studet为null?因为使用code
first,需要设置导航属性为virtual,才见面加载延迟加载数据。

亚洲必赢手机 13

2.关于以循环中做客导航属性的很处理(接着上面,加上virtual后会报以下很)

“已产生开拓的及这个 Command 相关联的
DataReader,必须首先以它倒闭。”

亚洲必赢手机 14

釜底抽薪方案:

  • 方案1、设定ConnectionString加上MultipleActiveResultSets=true,但惟独适用于SQL
    2005下的版本
  • 方案2、或者先念来放置于List中

3.上述两碰止为热身,我们说之陷阱才刚刚开始!

亚洲必赢手机 15

接下来我们点击打开MiniProfiler工具(不要吃吓到)

亚洲必赢手机 16

亚洲必赢手机 17

釜底抽薪方案:使用Include来得连续查询(注意:需要手动导入using System.Data.Entity
不然Include只能传表名字符串)。

亚洲必赢手机 18

双重看MiniProfiler的监控(瞬间101长sql变成了1长,这间的习性可想而知。)

亚洲必赢手机 19

AutoMapper工具

上面我们通过Include显示的执行表的连接查询显然是不易的,但尚不够。如果我们只有需要查询数据的少数字段呢,上面查询所有字段岂不是很浪费内存存储空间以及应用程序与数据库数据传带富。

咱俩可以:

亚洲必赢手机 20

针对许监督到的sql:

亚洲必赢手机 21

咱俩看来变化的sql,查询的字段少了累累。只有我们来得列出来字段的跟一个StudentId,StudentId用来连接查询条件的。

没错,这样的点子要命不错。可是有没有发出什么还好之方案或措施吗?答案是早晚之。(不然,也未会见在此地屁话了。)如果表字段非常多,我们要用的字段也老多,导航属性也生多之时刻,这样的手动映射就显不那么尴尬了。那么连下去我们开始介绍下AutoMapper来完成投:

瞩目:首先要NuGet下载AutoMapper。(然后导入命名空间 using
AutoMapper; using AutoMapper.QueryableExtensions;)

亚洲必赢手机 22

亚洲必赢手机 23

咱们见到上面查询语句没有一个个底手动映射,而映射都是单身布置了。其中CreateMap应该是设写到Global.asax文件里的。(其实呢即是分别了炫耀部分,清晰了询问语句。细心之同学也许注意到了,这种办法尚非去矣当仁不让Include)

亚洲必赢手机 24

咱俩看来了变通的sql和眼前来微异,但单纯可怜成了同长长的sql,并且结果吧是无可非议的。(其实就算是差不多矣同一长CASE
WHEN ([Extent2].[Id] IS NOT NULL) THEN 1 END AS
[C1]。看起就条告词并不曾啊实际意义,然而就是AutoMapper生成的sql,同时自己吗意味未了解为什么跟EF生成的不比)

如此做的功利?

关于AutoMapper的旁部分材料:

http://www.cnblogs.com/xishuai/p/3712361.html

http://www.cnblogs.com/xishuai/p/3700052.html

http://www.cnblogs.com/farb/p/AutoMapperContent.html

AutoMapper工具

地方我们由此Include显示的执行表的接连查询显然是正确的,但还不够。如果我们只有待查询数据的少数字段呢,上面查询有字段岂不是格外浪费内存存储空间及应用程序与数据库数据传带富。

我们可以:

亚洲必赢手机 25

针对诺监督及之sql:

亚洲必赢手机 26

俺们来看变化的sql,查询的字段少了森。只有咱展示列出来字段的和一个StudentId,StudentId用来连续查询条件的。

毋庸置疑,这样的艺术非常对。可是有没有产生什么还好的方案要方式啊?答案是自然的。(不然,也非会见于此屁话了。)如果表字段非常多,我们用运用的字段也殊多,导航属性为大多之时节,这样的手动映射就展示不那么尴尬了。那么接下我们开始介绍以AutoMapper来完成投:

在意:首先要NuGet下载AutoMapper。(然后导入命名空间 using
AutoMapper; using AutoMapper.QueryableExtensions;)

亚洲必赢手机 27

亚洲必赢手机 28

咱看看上面查询语句没有一个个底手动映射,而映射都是单身布置了。其中CreateMap应该是若写到Global.asax文件里的。(其实为即是分离了炫耀部分,清晰了询问语句。细心之同室也许注意到了,这种方法尚非去矣主动Include)

亚洲必赢手机 29

咱俩看出了变通的sql和前面来微不比,但偏偏可怜成了扳平久sql,并且结果也是正确的。(其实就是是差不多矣同长长的CASE WHEN ([Extent2].[Id] IS
NOT NULL) THEN 1 END AS
[C1]。看起就条告句并不曾呀实际意义,然而这是AutoMapper生成的sql,同时我也意味未知情为什么和EF生成的不比)

然做的补?

  1. 避在循环中做客导航属性多次实行sql语句。
  2. 避了查询语句子被最好多的手动映射,影响代码的读书。

有关AutoMapper的另外有素材:

http://www.cnblogs.com/xishuai/p/3712361.html

http://www.cnblogs.com/xishuai/p/3700052.html

http://www.cnblogs.com/farb/p/AutoMapperContent.html

联表查询统计

要求:查询前100只学生考项目(“模拟考试”、“正式考试”)、考试次数、语文平均分、学生姓名,且考试次数超过等于3差。(按考试项目分类统计)

代码如下:

亚洲必赢手机 30

视这么的代码,我首先感应是惨不忍睹了。又以循环执行sql了。监控如下:

亚洲必赢手机 31

实在,我们一味需要多少改变就拿101久sql变成1长达,如下:

亚洲必赢手机 32

马上变1条。

亚洲必赢手机 33

我们开拓查看详细的sql语句

亚洲必赢手机 34

发觉及时仅仅只是查询结果集合而已,其中的照考试项目来统计是先后用到具备数据后当盘算的(而休是当数据库内计算,然后径直返回结果),这样同样是荒废了数据库查询数据传。

关于连接查询分组统计我们可以运用SelectMany,如下:

亚洲必赢手机 35

监控sql如下:(是免是简单多矣吗?)

亚洲必赢手机 36

关于SelectMany资料:

http://www.cnblogs.com/lifepoem/archive/2011/11/18/2253579.html

http://www.cnblogs.com/heyuquan/p/Linq-to-Objects.html

联表查询统计

务求:查询前100个学生考项目(“模拟考试”、“正式考试”)、考试次数、语文平均分、学生姓名,且考试次数超过等于3坏。(按考试类别分类统计)

代码如下:

亚洲必赢手机 37

看来如此的代码,我第一反应是灾难性了。又在循环执行sql了。监控如下:

亚洲必赢手机 38

事实上,我们惟有待多少改变就把101长达sql变成1长长的,如下:

亚洲必赢手机 39

马上变1条。

亚洲必赢手机 40

咱们打开查看详细的sql语句

亚洲必赢手机 41

发觉及时仅仅只是查询结果集合而已,其中的准考试项目来统计是先后用到持有数据后当盘算的(而不是当数据库内计算,然后径直回到结果),这样同样是荒废了数据库查询数据传。

至于连接查询分组统计我们可以采用SelectMany,如下:

亚洲必赢手机 42

监理sql如下:(是免是简单多了吗?)

亚洲必赢手机 43

关于SelectMany资料:

http://www.cnblogs.com/lifepoem/archive/2011/11/18/2253579.html

http://www.cnblogs.com/heyuquan/p/Linq-to-Objects.html

性提升的AsNonUnicode

亚洲必赢手机 44

监察到的sql

亚洲必赢手机 45

俺们看看EF正常情况变化的sql会于前面带上“N”,如果我们抬高DbFunctions.AsNonUnicode生成的sql是尚未“N”的,当你发现带来上“N”的sql比从来不带“N”的
sql查询速度迟滞很多之时节那么就算懂得该怎么收拾。

(以前用oracle的时光带非带来“N”查询效率差别特别扎眼,今天为此sql
server测试并无发觉什么差异亚洲必赢手机 46。还有本人发现EF6会根据数据库被凡nvarchar的时节才会生成带“N”的sql,oracle数据库没测试,有趣味之同桌可以测试下)

特性提升的AsNonUnicode

亚洲必赢手机 47

监理及之sql

亚洲必赢手机 48

俺们看EF正常情形变化的sql会当前边带齐“N”,如果我们添加DbFunctions.AsNonUnicode生成的sql是未曾“N”的,当您意识带来上“N”的sql比从来不带“N”的
sql查询速度迟滞很多底时那么就算知该怎么惩罚。

(以前之所以oracle的时段带不牵动“N”查询效率差别特别明确,今天为此sql
server测试并无发现什么异样亚洲必赢手机 49。还有我意识EF6会根据数据库中凡是nvarchar的时才见面生成带“N”的sql,oracle数据库没测试,有趣味的同窗可以测试下)

性能提升的AsNoTracking

亚洲必赢手机 50

咱看变化的sql

亚洲必赢手机 51

sql是别的均等模子一样,但是实施时间也是4.8倍。原因仅仅只是第一漫长EF语句多加了一个AsNoTracking。

注意:

  • AsNoTracking干啊的也罢?无跟踪查询而已,也就是说查询出来的目标不克直接开修改。所以,我们以举行多少集合查询显示,而而不需对聚集修改并更新到数据库的上,一定不要遗忘加上AsNoTracking。
  • 假使查询过程做了select映射就未待加AsNoTracking。如:db.Students.Where(t=>t.Name.Contains(“张三”)).select(t=>new
    (t.Name,t.Age)).ToList();

性能提升的AsNoTracking

亚洲必赢手机 52

我们看变化的sql

亚洲必赢手机 53

sql是转变的平等模子一样,但是实施时间却是4.8倍。原因仅仅只是第一长长的EF语句多加了一个AsNoTracking。

注意:

  • AsNoTracking干啊的啊?无跟踪查询而已,也就是说查询出来的靶子非可知一直开修改。所以,我们在举行多少集合查询显示,而又不欲针对聚集修改并创新至数据库的时刻,一定毫无忘记加上AsNoTracking。
  • 假设查询过程做了select映射就未需要加AsNoTracking。如:db.Students.Where(t=>t.Name.Contains(“张三”)).select(t=>new
    (t.Name,t.Age)).ToList();

大多配段组合排序(字符串)

务求:查询名字中富含“张三”的学童,先以名排序,再按年排序。

亚洲必赢手机 54

亚洲必赢手机 55

哎,不对啊。按名排序为年龄排序覆盖了。我们应当用ThenBy来做排序。

亚洲必赢手机 56

亚洲必赢手机 57

不错不错,正是我们想如果的职能。如果您免思就此ThenBy,且还是升序的语句,我们呢得:

亚洲必赢手机 58

亚洲必赢手机 59

别的sql是同等的。与OrderBy、ThenBy对应的降序有OrderByDescending、ThenByDescending。

类好像特别完善了。其实不然,我们大部分气象排序是动态的。比如,我们会愈发前端页面不同的操作要求不同字段的两样排序。那咱们后台应该怎么开吧?

亚洲必赢手机 60

本,这样就是绝非问题的,只要你肯。可以这么多或的论断出无产生觉那个SB?是的,我们本来有重复好的化解方案。要是OrderBy可以一直传字符串???

解决方案:

亚洲必赢手机 61

接下来上面又长又丑的代码可以描绘成:

亚洲必赢手机 62

我们看下转的sql:

亚洲必赢手机 63

暨我们怀念使的功用完全符合,是休是发美美哒!!

【注意】:盛传的排序字段后面要加排序关键字 asc或desc

多字段组合排序(字符串)

渴求:查询名字中含“张三”的学生,先随名排序,再以年排序。

亚洲必赢手机 64

亚洲必赢手机 65

咦,不对啊。按名排序为年龄排序覆盖了。我们应有据此ThenBy来组成排序。

亚洲必赢手机 66

亚洲必赢手机 67

不错不错,正是我们怀念使的机能。如果您切莫思就此ThenBy,且还是升序的话语,我们吧得以:

亚洲必赢手机 68

亚洲必赢手机 69

变的sql是千篇一律的。与OrderBy、ThenBy对应的降序有OrderByDescending、ThenByDescending。

接近好像死周全了。其实不然,我们大部分场面排序是动态的。比如,我们会越前端页面不同的操作要求不同字段的差排序。那我们后台应该怎么开吗?

亚洲必赢手机 70

当,这样形成是从未有过问题的,只要你肯。可以如此多或的判断发生没出痛感甚SB?是的,我们当然有双重好之解决方案。要是OrderBy可以直接传字符串???

缓解方案:

  1. guget下载System.Linq.Dynamic 
  2. 导入System.Linq.Dynamic命名空间
  3. 修OrderBy的恢弘方法

亚洲必赢手机 71

下一场上面又加上同时臭的代码可以形容成:

亚洲必赢手机 72

我们看下转的sql:

亚洲必赢手机 73

及我们纪念要之效用完全符合,是不是深感美美哒!!

【注意】:传播的排序字段后面要加排序关键字
asc或desc

lamdba条件做

求:根据不同情况询问,可能情况

兑现代码:

亚洲必赢手机 74

是无是味及了平的恶臭亚洲必赢手机 75。下面我们来灵活组装Lamdba条件。

缓解方案:

亚洲必赢手机 76亚洲必赢手机 77

这段代码我为是自网上偷的,具体链接找不至了。

接下来我们的代码可以形容成:

亚洲必赢手机 78

来没发得意美哒一点亚洲必赢手机 79。然后我们看看生成的sql是否对:

亚洲必赢手机 80

lamdba条件做

务求:根据不同景象询问,可能情况

  1. 查询name=“张三” 的兼具学员
  2. 查询name=“张三” 或者 age=18的拥有学员

心想事成代码:

亚洲必赢手机 81

举凡未是味及了一致的荤亚洲必赢手机 82。下面我们来活组装Lamdba条件。

解决方案:

亚洲必赢手机 83亚洲必赢手机 84

马上段代码我吧是自网上偷之,具体链接找不至了。

接下来我们的代码可以形容成:

亚洲必赢手机 85

发没发美美哒一点亚洲必赢手机 86。然后我们看看生成的sql是否对:

亚洲必赢手机 87

EF的预热

http://www.cnblogs.com/dudu/p/entity-framework-warm-up.html

EF的预热

http://www.cnblogs.com/dudu/p/entity-framework-warm-up.html

count(*)被您用很了啊(Any的用法)

渴求:查询是否有名字啊“张三”的学童。(你的代码会怎样写吧?)

亚洲必赢手机 88

首先种?第二栽?第三栽?呵呵,我以前就是用的率先种,然后有人说“你count被公用非常了”,后来本身想了想了怎么就让我所以十分了也?直到对比了当时三独告知词的特性后自己掌握了。

亚洲必赢手机 89

特性的异竟有三百几近倍,count确实于我因此特别了。(我眷恋,不止于我一个口之所以很了咔嚓。)

咱们看看地方的Any干嘛的?官方解释是:

亚洲必赢手机 90

自身多次读是中文解说,一直无法掌握。甚至早有人也提出了一样的疑云《实在看无懂MSDN关于
Any 的说》

用我个人知道为是“确定集合中是否发素满足某同标准化”。我们来看望any其他用法:

求:查询教过“张三”或“李四”的老师

兑现代码:

亚洲必赢手机 91

点滴栽方法,以前我会习惯写第一种植。当然我们省那个成了的sql和履行效率之后,看法改变了。

亚洲必赢手机 92

频率的差竟生近六倍

咱俩重对照下count:

亚洲必赢手机 93

亚洲必赢手机 94

得出奇怪的结论:

count(*)被公用大了为(Any的用法)

求:查询是否存在名字呢“张三”的生。(你的代码会如何写啊?)

亚洲必赢手机 95

率先种?第二栽?第三栽?呵呵,我以前便是采取的率先种,然后有人说“你count被公用十分了”,后来自我思念了想了怎么就于自己用好了吗?直到对比了即三独告知词之性后自明白了。

亚洲必赢手机 96

特性的异竟生三百多加倍,count确实给我于是很了。(我想,不止于我一个总人口就此老了咔嚓。)

俺们看看地方的Any干嘛的?官方说是:

亚洲必赢手机 97

自身多次读之中文说,一直无法知晓。甚至早有人吗提出了同样的疑点《骨子里看不懂MSDN关于
Any
的说》

之所以自己个人理解为是“确定集合中是否发生素满足某平法”。我们来探视any其他用法:

渴求:查询教了“张三”或“李四”的教员

心想事成代码:

亚洲必赢手机 98

鲜种植办法,以前我会习惯写第一栽。当然我们看看那个成了之sql和实行效率之后,看法改变了。

亚洲必赢手机 99

频率的差竟产生近六倍

咱再次比下count:

亚洲必赢手机 100

亚洲必赢手机 101

得出奇怪的下结论:

  1. 每当导航属性之中用count和利用any性能分别不甚,反而FirstOrDefault()
    != null的艺术性能最好差。
  2. 每当直性判断其中any和FirstOrDefault() !=
    null性能分别不雅,count性能要差之大都。
  3. 为此,不管是一直性还是导航属性我们还用any来判定是否在是不过稳妥的。

晶莹剔透标识符

如由于各种原因我们需要写下面这样逻辑的言辞

亚洲必赢手机 102

咱得以形容成这么更好

亚洲必赢手机 103

看生成的sql就掌握了

亚洲必赢手机 104

老二种植艺术变的sql要清得差不多,性能也重好。

晶莹剔透标识符

如果由于各种缘由我们得写下面这样逻辑的讲话

亚洲必赢手机 105

咱们得写成这样还好

亚洲必赢手机 106

看生成的sql就知晓了

亚洲必赢手机 107

其次栽办法转变的sql要根本得多,性能为还好。

EntityFramework.Extended

此地推荐下插件EntityFramework.Extended,看了生,很科学。

极致深的优点就是是可一直批量改动、删除,不用像EF默认的要事先举行询问操作。

有关官方EF为什么从来不供这么的支持即无亮了。不过用EntityFramework.Extended需要专注以下几点:

http://www.cnblogs.com/GuZhenYin/p/5482288.html

当此正个问题EntityFramework.Extended并无是说勿可知回滚,感谢@GuZhenYin园友的指正(原谅自己事先没下手测试)。

瞩目:需要NuGet下载EntityFramework.Extended, 并导入命名空间: using EntityFramework.Extensions ;

测试代码如下:(如果注释掉手抛大代码是足以一直更新至数据库的)

using (var ctxTransaction = db.Database.BeginTransaction())
{
    try
    {
        db.Teachers.Where(t => true).Update(t => new Teacher { Age = "1" });

        throw new Exception("手动抛出异常");

        ctxTransaction.Commit();//提交事务
    }
    catch (Exception)
    {
        ctxTransaction.Rollback();//回滚事务
    }
}

EntityFramework.Extended

此地推荐生插件EntityFramework.Extended,看了生,很科学。

极致充分的优点就是是好一直批量改动、删除,不用像EF默认的内需先举行询问操作。

有关官方EF为什么从来不供这么的支撑即无知道了。不过用EntityFramework.Extended需要专注以下几点:

  1. 只支持sql server
  2. 批量改动、删除时无克落实工作(也即是发了大不可知回滚)
  3. 从未有过联级删除
  4. 不能同EF一起SaveChanges
    (详见)

http://www.cnblogs.com/GuZhenYin/p/5482288.html

在这个正个问题EntityFramework.Extended并无是说不能够回滚,感谢@GuZhenYin园友的指正(原谅我前面从没动手测试)。

顾:需要NuGet下载EntityFramework.Extended,
并导入命名空间: using
EntityFramework.Extensions ;

测试代码如下:(如果注释掉手抛大代码是可以一直更新到数据库的)

using (var ctxTransaction = db.Database.BeginTransaction())
{
    try
    {
        db.Teachers.Where(t => true).Update(t => new Teacher { Age = "1" });

        throw new Exception("手动抛出异常");

        ctxTransaction.Commit();//提交事务
    }
    catch (Exception)
    {
        ctxTransaction.Rollback();//回滚事务
    }
}

起定义IQueryable扩展方法

 最后整理下从定义的IQueryable的扩充。

 亚洲必赢手机 108

亚洲必赢手机 109

 

补充1:

First和Single的区别:前者是TOP(1)后者是TOP(2),后者如果查询到了2条数据则抛出异常。所以在必要的时候使用Single也不会比First慢多少。

补充2: 

曾打包nuget提供直接设置 Install-Package
Talk.Linq.Extensions 或nuget搜索 Talk.Linq.Extensions 

https://github.com/zhaopeiym/Talk/wiki/Talk.Linq.Extensions\_demo

 

结束:

源码下载:http://pan.baidu.com/s/1o8MYozw

本文为联合到《C#基础知识巩固系列》

迎热心园友补充!

http://www.bkjia.com/C\_jc/1281707.htmlwww.bkjia.comtruehttp://www.bkjia.com/C\_jc/1281707.htmlTechArticle【转】你必须知道的EF知识和经验,ef知识经验
【转】你不能不知道之EF知识及经历
注意:以下内容如果没特意说明,默认使用的 EF6.0版本…

由定义IQueryable扩展方法

 最后整理下于定义之IQueryable的扩充。

 亚洲必赢手机 110

亚洲必赢手机 111

 

补充1:

First和Single的区别:前者是TOP(1)后者是TOP(2),后者如果查询到了2条数据则抛出异常。所以在必要的时候使用Single也不会比First慢多少。

补充2: 

既打包nuget提供第一手装 Install-Package
Talk.Linq.Extensions 或nuget搜索 Talk.Linq.Extensions 

https://github.com/zhaopeiym/Talk/wiki/Talk.Linq.Extensions_demo

 

结束:

源码下载:http://pan.baidu.com/s/1o8MYozw

正文为同到《C#基础知识巩固系列》

欢迎热心园友补充!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图