mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
pgsql/mysql/sqlserver适配
This commit is contained in:
commit
9b5e34032c
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
246
.gitignore
vendored
Normal file
246
.gitignore
vendored
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
[Xx]64/
|
||||||
|
[Xx]86/
|
||||||
|
[Bb]uild/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# Visual Studio 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# DNX
|
||||||
|
project.lock.json
|
||||||
|
package-lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
|
||||||
|
# TODO: Un-comment the next line if you do not want to checkin
|
||||||
|
# your web deploy settings because they may include unencrypted
|
||||||
|
# passwords
|
||||||
|
#*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignoreable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Microsoft Azure ApplicationInsights config file
|
||||||
|
ApplicationInsights.config
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# LightSwitch generated files
|
||||||
|
GeneratedArtifacts/
|
||||||
|
ModelManifest.xml
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
92
Docs/Generator.md
Normal file
92
Docs/Generator.md
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# 生成器
|
||||||
|
|
||||||
|
生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板:
|
||||||
|
|
||||||
|
| 模板名称 | 路径 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 |
|
||||||
|
| ------------- | - | - |- | - |- | - |- |
|
||||||
|
| simple-entity | ../Templates/MySql/simple-entity | √ | X | X | √ | X | X |
|
||||||
|
| simple-entity-navigation-object | ../Templates/MySql/simple-entity-navigation-object | √ | √ | X | √ | X | X |
|
||||||
|
| rich-entity-navigation-object | ../Templates/MySql/rich-entity-navigation-object | √ | √ | √ | X | √ | X |
|
||||||
|
|
||||||
|
> 更多模板逐步开发中。。。
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
//定义 mysql FreeSql
|
||||||
|
var mysql = new FreeSql.FreeSqlBuilder()
|
||||||
|
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
//创建模板生成类现实
|
||||||
|
var gen = new FreeSql.Generator.TemplateGenerator();
|
||||||
|
gen.Build(mysql.DbFirst,
|
||||||
|
@"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", //模板目录(事先下载)
|
||||||
|
@"C:\Users\28810\Desktop\新建文件夹 (9)", //生成后保存的目录
|
||||||
|
"cccddd" //数据库
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 模板语法
|
||||||
|
|
||||||
|
```html
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{#title}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!--绑定表达式-->
|
||||||
|
{#表达式}
|
||||||
|
{##表达式} 当表达式可能发生runtime错误时使用,性能没有上面的高
|
||||||
|
|
||||||
|
<!--可嵌套使用,同一标签最多支持3个指令-->
|
||||||
|
{include ../header.html}
|
||||||
|
<div @for="i 1, 101">
|
||||||
|
<p @if="i === 50" @for="item,index in data">aaa</p>
|
||||||
|
<p @else="i % 3 === 0">bbb {#i}</p>
|
||||||
|
<p @else="">ccc {#i}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--定义模块,可以将公共模块定义到一个文件中-->
|
||||||
|
{module module_name1 parms1, 2, 3...}
|
||||||
|
{/module}
|
||||||
|
{module module_name2 parms1, 2, 3...}
|
||||||
|
{/module}
|
||||||
|
|
||||||
|
<!--使用模块-->
|
||||||
|
{import ../module.html as myname}
|
||||||
|
{#myname.module_name(parms1, 2, 3...)}
|
||||||
|
|
||||||
|
<!--继承-->
|
||||||
|
{extends ../inc/layout.html}
|
||||||
|
{block body}{/block}
|
||||||
|
|
||||||
|
<!--嵌入代码块-->
|
||||||
|
{%
|
||||||
|
for (var a = 0; a < 100; a++)
|
||||||
|
print(a);
|
||||||
|
%}
|
||||||
|
|
||||||
|
<!--条件分支-->
|
||||||
|
{if i === 50}
|
||||||
|
{elseif i > 60}
|
||||||
|
{else}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!--三种循环-->
|
||||||
|
{for i 1,101} 可自定义名 {for index2 表达式1 in 表达式2}
|
||||||
|
|
||||||
|
{for item,index in items} 可选参数称 index
|
||||||
|
可自定义名 {for item2, index99 in 数组表达式}
|
||||||
|
|
||||||
|
{for key,item,index on json} 可选参数 item, index,
|
||||||
|
可自定义名 {for key2, item2, index99 in 对象表达式}
|
||||||
|
{/for}
|
||||||
|
|
||||||
|
<!--不被解析-->
|
||||||
|
{miss}
|
||||||
|
此块内容不被bmw.js解析
|
||||||
|
{/miss}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
135
Docs/codefirst.md
Normal file
135
Docs/codefirst.md
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
# CodeFirst
|
||||||
|
|
||||||
|
### 支持的类型
|
||||||
|
|
||||||
|
bool, byte, short, int, long, byte, ushort, uint, ulong, double, float, decimal, int
|
||||||
|
|
||||||
|
bool?, byte?, short?, int?, long?, byte?, ushort?, uint?, ulong?, double?, float?, decimal?, int?
|
||||||
|
|
||||||
|
TimeSpan, DateTime
|
||||||
|
|
||||||
|
TimeSpan?, DateTime?
|
||||||
|
|
||||||
|
byte[], string
|
||||||
|
|
||||||
|
MygisPoint, MygisLineString, MygisPolygon, MygisMultiPoint, MygisMultiLineString, MygisMultiPolygon
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var mysql = new MySql(null, null, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=3", null, null);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自动同步实体结构【开发环境必备】
|
||||||
|
|
||||||
|
自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
mysql.CodeFirst.IsAutoSyncDataStructure = true;
|
||||||
|
```
|
||||||
|
|
||||||
|
> 此功能默认为开启状态,发布正式环境后,请修改此设置
|
||||||
|
|
||||||
|
> 虽然【自动同步实体结构】功能开发非常好用,但是有个坏处,就是数据库后面会很乱,没用的字段一大堆
|
||||||
|
|
||||||
|
### 手工同步实体结构
|
||||||
|
|
||||||
|
| 实体&表对比 | 添加 | 改名 | 删除 |
|
||||||
|
| - | - | - | - |
|
||||||
|
| | √ | √ | X |
|
||||||
|
|
||||||
|
| 实体属性&字段对比 | 添加 | 修改可空 | 修改自增 | 修改类型 | 改名 | 删除 |
|
||||||
|
| - | - | - | - | - | - | - |
|
||||||
|
| | √ | √ | √ | √ | √ | X |
|
||||||
|
|
||||||
|
> 为了保证安全,不提供删除字段
|
||||||
|
|
||||||
|
|
||||||
|
1、提供方法对比实体,与数据库中的变化部分
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t1 = mysql.CodeFirst.GetComparisonDDLStatements<Topic>();
|
||||||
|
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Clicks { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
public ushort fusho { get; set; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS `cccddd`.`Topic` (
|
||||||
|
`Id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`Clicks` INT(11) NOT NULL,
|
||||||
|
`Title` VARCHAR(255),
|
||||||
|
`CreateTime` DATETIME NOT NULL,
|
||||||
|
`fusho` SMALLINT(5) UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY (`Id`)
|
||||||
|
) Engine=InnoDB CHARACTER SET utf8;
|
||||||
|
```
|
||||||
|
|
||||||
|
2、指定实体的表名
|
||||||
|
|
||||||
|
指定 Name 后,实体类名变化不影响数据库对应的表
|
||||||
|
```csharp
|
||||||
|
[Table(Name = "tb_topic111")]
|
||||||
|
class Topic {
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3、无指定实体的表名,修改实体类名
|
||||||
|
|
||||||
|
指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Table(OldName = "Topic")]
|
||||||
|
class Topic2 {
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```sql
|
||||||
|
ALTER TABLE `cccddd`.`Topic` RENAME TO `cccddd`.`Topic2`;
|
||||||
|
```
|
||||||
|
|
||||||
|
4、修改属性的类型
|
||||||
|
|
||||||
|
把 Id 类型改为 uint 后
|
||||||
|
```sql
|
||||||
|
ALTER TABLE `cccddd`.`Topic2` MODIFY `Id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||||
|
```
|
||||||
|
```csharp
|
||||||
|
[Column(DbType = "varchar(128)")]
|
||||||
|
public string Title { get; set; }
|
||||||
|
```
|
||||||
|
```sql
|
||||||
|
ALTER TABLE `cccddd`.`Topic2` MODIFY `Title2` VARCHAR(128);
|
||||||
|
```
|
||||||
|
|
||||||
|
5、指定属性的字段名
|
||||||
|
|
||||||
|
这样指定后,修改实体的属性名不影响数据库对应的列
|
||||||
|
```csharp
|
||||||
|
[Column(Name = "titl2")]
|
||||||
|
public string Title { get; set; }
|
||||||
|
```
|
||||||
|
|
||||||
|
6、无指定属性的字段名,修改属性名
|
||||||
|
|
||||||
|
指定数据库旧的列名,修改实体属性命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库字段;否则将视为【新增字段】
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Column(OldName = "Title2")]
|
||||||
|
public string Title { get; set; }
|
||||||
|
```
|
||||||
|
```sql
|
||||||
|
ALTER TABLE `cccddd`.`Topic2` CHANGE COLUMN `Title2` `Title` VARCHAR(255);
|
||||||
|
```
|
||||||
|
|
||||||
|
7、提供方法同步结构
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t2 = mysql.CodeFirst.SyncStructure<Topic>();
|
||||||
|
//同步实体类型到数据库
|
||||||
|
```
|
112
Docs/dbfirst.md
Normal file
112
Docs/dbfirst.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# DbFirst
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
MySql mysql = new MySql(null, null, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=3", null, null);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 获取所有数据库
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t1 = mysql.DbFirst.GetDatabases();
|
||||||
|
//返回字符串数组, ["cccddd", "test"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 获取指定数据库的表信息
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t2 = mysql.DbFirst.GetTablesByDatabase(mysql.DbFirst.GetDatabases()[0]);
|
||||||
|
//返回包括表、列详情、主键、唯一键、索引、外键
|
||||||
|
```
|
||||||
|
|
||||||
|
# 生成器
|
||||||
|
|
||||||
|
生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板:
|
||||||
|
|
||||||
|
| 模板名称 | 路径 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 |
|
||||||
|
| ------------- | - | - |- | - |- | - |- |
|
||||||
|
| simple-entity | ../Templates/MySql/simple-entity | √ | X | X | √ | X | X |
|
||||||
|
| simple-entity-navigation-object | ../Templates/MySql/simple-entity-navigation-object | √ | √ | X | √ | X | X |
|
||||||
|
| rich-entity-navigation-object | ../Templates/MySql/rich-entity-navigation-object | √ | √ | √ | X | √ | X |
|
||||||
|
|
||||||
|
> 更多模板逐步开发中。。。
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
//定义 mysql FreeSql
|
||||||
|
var mysql = new FreeSql.FreeSqlBuilder()
|
||||||
|
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
//创建模板生成类现实
|
||||||
|
var gen = new FreeSql.Generator.TemplateGenerator();
|
||||||
|
gen.Build(mysql.DbFirst,
|
||||||
|
@"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", //模板目录(事先下载)
|
||||||
|
@"C:\Users\28810\Desktop\新建文件夹 (9)", //生成后保存的目录
|
||||||
|
"cccddd" //数据库
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 模板语法
|
||||||
|
|
||||||
|
```html
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{#title}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!--绑定表达式-->
|
||||||
|
{#表达式}
|
||||||
|
{##表达式} 当表达式可能发生runtime错误时使用,性能没有上面的高
|
||||||
|
|
||||||
|
<!--可嵌套使用,同一标签最多支持3个指令-->
|
||||||
|
{include ../header.html}
|
||||||
|
<div @for="i 1, 101">
|
||||||
|
<p @if="i === 50" @for="item,index in data">aaa</p>
|
||||||
|
<p @else="i % 3 === 0">bbb {#i}</p>
|
||||||
|
<p @else="">ccc {#i}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--定义模块,可以将公共模块定义到一个文件中-->
|
||||||
|
{module module_name1 parms1, 2, 3...}
|
||||||
|
{/module}
|
||||||
|
{module module_name2 parms1, 2, 3...}
|
||||||
|
{/module}
|
||||||
|
|
||||||
|
<!--使用模块-->
|
||||||
|
{import ../module.html as myname}
|
||||||
|
{#myname.module_name(parms1, 2, 3...)}
|
||||||
|
|
||||||
|
<!--继承-->
|
||||||
|
{extends ../inc/layout.html}
|
||||||
|
{block body}{/block}
|
||||||
|
|
||||||
|
<!--嵌入代码块-->
|
||||||
|
{%
|
||||||
|
for (var a = 0; a < 100; a++)
|
||||||
|
print(a);
|
||||||
|
%}
|
||||||
|
|
||||||
|
<!--条件分支-->
|
||||||
|
{if i === 50}
|
||||||
|
{elseif i > 60}
|
||||||
|
{else}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!--三种循环-->
|
||||||
|
{for i 1,101} 可自定义名 {for index2 表达式1 in 表达式2}
|
||||||
|
|
||||||
|
{for item,index in items} 可选参数称 index
|
||||||
|
可自定义名 {for item2, index99 in 数组表达式}
|
||||||
|
|
||||||
|
{for key,item,index on json} 可选参数 item, index,
|
||||||
|
可自定义名 {for key2, item2, index99 in 对象表达式}
|
||||||
|
{/for}
|
||||||
|
|
||||||
|
<!--不被解析-->
|
||||||
|
{miss}
|
||||||
|
此块内容不被bmw.js解析
|
||||||
|
{/miss}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
80
Docs/delete.md
Normal file
80
Docs/delete.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# 删除数据
|
||||||
|
|
||||||
|
| 方法 | 返回值 | 参数 | 描述 |
|
||||||
|
| - | - | - | - |
|
||||||
|
| Where | \<this\> | Lambda | 表达式条件,仅支持实体基础成员(不包含导航对象) |
|
||||||
|
| Where | \<this\> | string, parms | 原生sql语法条件,Where("id = ?id", new { id = 1 }) |
|
||||||
|
| Where | \<this\> | T1 \| IEnumerable<T1> | 传入实体或集合,将其主键作为条件 |
|
||||||
|
| WhereExists | \<this\> | ISelect | 子查询是否存在 |
|
||||||
|
| ToSql | string | | 返回即将执行的SQL语句 |
|
||||||
|
| ExecuteAffrows | long | | 执行SQL语句,返回影响的行数 |
|
||||||
|
| ExecuteDeleted | List\<T1\> | | 执行SQL语句,返回被删除的记录 |
|
||||||
|
|
||||||
|
### 测试代码
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var mysql = new MySql("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=3");
|
||||||
|
IDelete<Topic> delete => mysql.Delete<Topic>();
|
||||||
|
|
||||||
|
[Table(Name = "tb_topic")]
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Clicks { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 动态条件
|
||||||
|
```csharp
|
||||||
|
Delete<Topic>(object dywhere)
|
||||||
|
```
|
||||||
|
dywhere 支持
|
||||||
|
|
||||||
|
* 主键值
|
||||||
|
* new[] { 主键值1, 主键值2 }
|
||||||
|
* Topic对象
|
||||||
|
* new[] { Topic对象1, Topic对象2 }
|
||||||
|
* new { id = 1 }
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t1 = mysql.Delete<Topic>(new[] { 1, 2 }).ToSql();
|
||||||
|
//DELETE FROM `tb_topic` WHERE (`Id` = 1 OR `Id` = 2)
|
||||||
|
|
||||||
|
var t2 = mysql.Delete<Topic>(new Topic { Id = 1, Title = "test" }).ToSql();
|
||||||
|
//DELETE FROM `tb_topic` WHERE (`Id` = 1)
|
||||||
|
|
||||||
|
var t3 = mysql.Delete<Topic>(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).ToSql();
|
||||||
|
//DELETE FROM `tb_topic` WHERE (`Id` = 1 OR `Id` = 2)
|
||||||
|
|
||||||
|
var t4 = mysql.Delete<Topic>(new { id = 1 }).ToSql();
|
||||||
|
//DELETE FROM `tb_topic` WHERE (`Id` = 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 删除条件
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t5 = delete.Where(a => a.Id == 1).ToSql().Replace("\r\n", "");
|
||||||
|
//DELETE FROM `tb_topic` WHERE (`Id` = 1)
|
||||||
|
|
||||||
|
var t6 = delete.Where("id = ?id", new { id = 1 }).ToSql().Replace("\r\n", "");
|
||||||
|
//DELETE FROM `tb_topic` WHERE (id = ?id)
|
||||||
|
|
||||||
|
var item = new Topic { Id = 1, Title = "newtitle" };
|
||||||
|
var t7 = delete.Where(item).ToSql().Replace("\r\n", "");
|
||||||
|
//DELETE FROM `tb_topic` WHERE (`Id` = 1)
|
||||||
|
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
var t8 = delete.Where(items).ToSql().Replace("\r\n", "");
|
||||||
|
//DELETE FROM `tb_topic` WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 执行命令
|
||||||
|
|
||||||
|
| 方法 | 返回值 | 参数 | 描述 |
|
||||||
|
| - | - | - | - |
|
||||||
|
| ExecuteAffrows | long | | 执行SQL语句,返回影响的行数 |
|
||||||
|
| ExecuteDeleted | List\<T1\> | | 执行SQL语句,返回被删除的记录 |
|
77
Docs/insert.md
Normal file
77
Docs/insert.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# 插入数据
|
||||||
|
|
||||||
|
| 方法 | 返回值 | 参数 | 描述 |
|
||||||
|
| - | - | - | - |
|
||||||
|
| AppendData | \<this\> | T1 \| IEnumerable<T1> | 追加准备插入的实体 |
|
||||||
|
| InsertColumns | \<this\> | Lambda | 只插入的列 |
|
||||||
|
| IgnoreColumns | \<this\> | Lambda | 忽略的列 |
|
||||||
|
| ToSql | string | | 返回即将执行的SQL语句 |
|
||||||
|
| ExecuteAffrows | long | | 执行SQL语句,返回影响的行数 |
|
||||||
|
| ExecuteIdentity | long | | 执行SQL语句,返回自增值 |
|
||||||
|
| ExecuteInserted | List\<T1\> | | 执行SQL语句,返回插入后的记录 |
|
||||||
|
|
||||||
|
### 列优先级
|
||||||
|
|
||||||
|
> 全部列 < 指定列(InsertColumns) < 忽略列(IgnoreColumns)
|
||||||
|
|
||||||
|
### 测试代码
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var mysql = new MySql("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=3");
|
||||||
|
IInsert<Topic> insert => mysql.Insert<Topic>();
|
||||||
|
|
||||||
|
[Table(Name = "tb_topic")]
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Clicks { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
```
|
||||||
|
|
||||||
|
### 插入
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t1 = insert.AppendData(items.First()).ToSql();
|
||||||
|
//INSERT INTO `tb_topic`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks0, ?Title0, ?CreateTime0)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 批量插入
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t2 = insert.AppendData(items).ToSql();
|
||||||
|
//INSERT INTO `tb_topic`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks0, ?Title0, ?CreateTime0), (?Clicks1, ?Title1, ?CreateTime1), (?Clicks2, ?Title2, ?CreateTime2), (?Clicks3, ?Title3, ?CreateTime3), (?Clicks4, ?Title4, ?CreateTime4), (?Clicks5, ?Title5, ?CreateTime5), (?Clicks6, ?Title6, ?CreateTime6), (?Clicks7, ?Title7, ?CreateTime7), (?Clicks8, ?Title8, ?CreateTime8), (?Clicks9, ?Title9, ?CreateTime9)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 只想插入指定的列
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t3 = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
|
||||||
|
//INSERT INTO `tb_topic`(`Title`) VALUES(?Title0), (?Title1), (?Title2), (?Title3), (?Title4), (?Title5), (?Title6), (?Title7), (?Title8), (?Title9)
|
||||||
|
|
||||||
|
var t4 = insert.AppendData(items).InsertColumns(a =>new { a.Title, a.Clicks }).ToSql();
|
||||||
|
//INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 忽略列
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t5 = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
|
||||||
|
//INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)
|
||||||
|
|
||||||
|
var t6 = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql();
|
||||||
|
///INSERT INTO `tb_topic`(`Clicks`) VALUES(?Clicks0), (?Clicks1), (?Clicks2), (?Clicks3), (?Clicks4), (?Clicks5), (?Clicks6), (?Clicks7), (?Clicks8), (?Clicks9)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 执行命令
|
||||||
|
|
||||||
|
| 方法 | 返回值 | 描述 |
|
||||||
|
| - | - | - |
|
||||||
|
| ExecuteAffrows | long | 执行SQL语句,返回影响的行数 |
|
||||||
|
| ExecuteIdentity | long | 执行SQL语句,返回自增值 |
|
||||||
|
| ExecuteInserted | List\<T1\> | 执行SQL语句,返回插入后的记录 |
|
48
Docs/select.md
Normal file
48
Docs/select.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# 查询数据
|
||||||
|
|
||||||
|
| 方法 | 返回值 | 参数 | 描述 |
|
||||||
|
| ------------- | - | - | - |
|
||||||
|
| ToSql | string | | 返回即将执行的SQL语句 |
|
||||||
|
| ToList | List<T1> | | 执行SQL查询,返回 T1 实体所有字段的记录,若存在导航属性则一起查询返回,记录不存在时返回 Count 为 0 的列表 |
|
||||||
|
| ToList\<T\> | List\<T\> | Lambda | 执行SQL查询,返回指定字段的记录,记录不存在时返回 Count 为 0 的列表 |
|
||||||
|
| ToList\<T\> | List\<T\> | string field | 执行SQL查询,返回 field 指定字段的记录,并以元组或基础类型(int,string,long)接收,记录不存在时返回 Count 为 0 的列表 |
|
||||||
|
| ToOne | T1 | | 执行SQL查询,返回 T1 实体所有字段的第一条记录,记录不存在时返回 null |
|
||||||
|
| Any | bool | | 执行SQL查询,是否有记录 |
|
||||||
|
| Sum | T | Lambda | 指定一个列求和 |
|
||||||
|
| Min | T | Lambda | 指定一个列求最小值 |
|
||||||
|
| Max | T | Lambda | 指定一个列求最大值 |
|
||||||
|
| Avg | T | Lambda | 指定一个列求平均值 |
|
||||||
|
| 【分页】 |
|
||||||
|
| Count | long | | 查询的记录数量 |
|
||||||
|
| Count | \<this\> | out long | 查询的记录数量,以参数out形式返回 |
|
||||||
|
| Skip | \<this\> | int offset | 查询向后偏移行数 |
|
||||||
|
| Offset | \<this\> | int offset | 查询向后偏移行数 |
|
||||||
|
| Limit | \<this\> | int limit | 查询多少条数据 |
|
||||||
|
| Take | \<this\> | int limit | 查询多少条数据 |
|
||||||
|
| Page | \<this\> | int pageIndex, int pageSize | 分页 |
|
||||||
|
| 【条件】 |
|
||||||
|
| Where | \<this\> | Lambda | 支持多表查询表达式 |
|
||||||
|
| WhereIf | \<this\> | bool, Lambda | 支持多表查询表达式 |
|
||||||
|
| Where | \<this\> | string, parms | 原生sql语法条件,Where("id = ?id", new { id = 1 }) |
|
||||||
|
| WhereIf | \<this\> | bool, string, parms | 原生sql语法条件,WhereIf(true, "id = ?id", new { id = 1 }) |
|
||||||
|
| WhereLike | \<this\> | Lambda, string, bool | like 查询条件,where title like '%xxx%' or content like '%xxx%' |
|
||||||
|
| 【分组】 |
|
||||||
|
| GroupBy | \<this\> | Lambda | 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.Time}) | GroupBy(a => new[]{"name","time"}) |
|
||||||
|
| GroupBy | \<this\> | string, parms | 按原生sql语法分组,GroupBy("concat(name, ?cc)", new { cc = 1 }) |
|
||||||
|
| Having | \<this\> | string, parms | 按原生sql语法聚合条件过滤,Having("count(name) = ?cc", new { cc = 1 }) |
|
||||||
|
| 【排序】 |
|
||||||
|
| OrderBy | \<this\> | Lambda | 按列排序,OrderBy(a => a.Time) |
|
||||||
|
| OrderByDescending | \<this\> | Lambda | 按列倒向排序,OrderByDescending(a => a.Time) |
|
||||||
|
| OrderBy | \<this\> | string, parms | 按原生sql语法排序,OrderBy("count(name) + ?cc", new { cc = 1 }) |
|
||||||
|
| 【联表】 |
|
||||||
|
| LeftJoin | \<this\> | Lambda | 左联查询,可使用导航属性,或指定关联的实体类型 |
|
||||||
|
| InnerJoin | \<this\> | Lambda | 联接查询,可使用导航属性,或指定关联的实体类型 |
|
||||||
|
| RightJoin | \<this\> | Lambda | 右联查询,可使用导航属性,或指定关联的实体类型 |
|
||||||
|
| LeftJoin | \<this\> | string, parms | 左联查询,使用原生sql语法,LeftJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) |
|
||||||
|
| InnerJoin | \<this\> | string, parms | 联接查询,使用原生sql语法,InnerJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) |
|
||||||
|
| RightJoin | \<this\> | string, parms | 右联查询,使用原生sql语法,RightJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 }) |
|
||||||
|
| From | \<this\> | Lambda | 多表查询,3个表以上使用非常方便,目前设计最大支持10个表 |
|
||||||
|
| 【其他】 |
|
||||||
|
| As | \<this\> | string alias = "a" | 指定别名 |
|
||||||
|
| Master | \<this\> | | 指定从主库查询(默认查询从库) |
|
||||||
|
| Caching | \<this\> | int seconds, string key = null | 缓存查询结果 |
|
127
Docs/update.md
Normal file
127
Docs/update.md
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
# 更新数据
|
||||||
|
|
||||||
|
| 方法 | 返回值 | 参数 | 描述 |
|
||||||
|
| - | - | - | - |
|
||||||
|
| SetSource | \<this\> | T1 \| IEnumerable<T1> | 更新数据,设置更新的实体 |
|
||||||
|
| IgnoreColumns | \<this\> | Lambda | 忽略的列 |
|
||||||
|
| Set | \<this\> | Lambda, value | 设置列的新值,Set(a => a.Name, "newvalue") |
|
||||||
|
| Set | \<this\> | Lambda | 设置列的的新值为基础上增加,Set(a => a.Clicks + 1),相当于 clicks=clicks+1; |
|
||||||
|
| SetRaw | \<this\> | string, parms | 设置值,自定义SQL语法,SetRaw("title = ?title", new { title = "newtitle" }) |
|
||||||
|
| Where | \<this\> | Lambda | 表达式条件,仅支持实体基础成员(不包含导航对象) |
|
||||||
|
| Where | \<this\> | string, parms | 原生sql语法条件,Where("id = ?id", new { id = 1 }) |
|
||||||
|
| Where | \<this\> | T1 \| IEnumerable<T1> | 传入实体或集合,将其主键作为条件 |
|
||||||
|
| WhereExists | \<this\> | ISelect | 子查询是否存在 |
|
||||||
|
| ToSql | string | | 返回即将执行的SQL语句 |
|
||||||
|
| ExecuteAffrows | long | | 执行SQL语句,返回影响的行数 |
|
||||||
|
| ExecuteUpdated | List\<T1\> | | 执行SQL语句,返回更新后的记录 |
|
||||||
|
|
||||||
|
### 列优先级
|
||||||
|
|
||||||
|
> 全部列 < 指定列(Set/SetRaw) < 忽略列(IgnoreColumns)
|
||||||
|
|
||||||
|
### 测试代码
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
[Table(Name = "tb_topic")]
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Clicks { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
var mysql = new MySql("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=3");
|
||||||
|
IUpdate<Topic> update => mysql.Update<Topic>();
|
||||||
|
```
|
||||||
|
|
||||||
|
### 动态条件
|
||||||
|
```csharp
|
||||||
|
Update<Topic>(object dywhere)
|
||||||
|
```
|
||||||
|
dywhere 支持
|
||||||
|
|
||||||
|
* 主键值
|
||||||
|
* new[] { 主键值1, 主键值2 }
|
||||||
|
* Topic对象
|
||||||
|
* new[] { Topic对象1, Topic对象2 }
|
||||||
|
* new { id = 1 }
|
||||||
|
|
||||||
|
### 更新指定列
|
||||||
|
```csharp
|
||||||
|
var t1 = mysql.Update<Topic>(1).Set(a => a.CreateTime, DateTime.Now).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `CreateTime` = '2018-12-08 00:04:59' WHERE (`Id` = 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 更新指定列,累加
|
||||||
|
```csharp
|
||||||
|
var t2 = mysql.Update<Topic>(1).Set(a => a.Clicks + 1).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `Clicks` = ifnull(`Clicks`,0) + 1 WHERE (`Id` = 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 保存实体
|
||||||
|
```csharp
|
||||||
|
var item = new Topic { Id = 1, Title = "newtitle" };
|
||||||
|
var t3 = update.SetSource(item).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `Clicks` = ?p_0, `Title` = ?p_1, `CreateTime` = ?p_2 WHERE (`Id` = 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 保存实体,忽略一些列
|
||||||
|
```csharp
|
||||||
|
var t4 = update.SetSource(item).IgnoreColumns(a => a.Clicks).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `Title` = ?p_0, `CreateTime` = ?p_1 WHERE (`Id` = 1)
|
||||||
|
var t5 = update.SetSource(item).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `Title` = ?p_0 WHERE (`Id` = 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 批量保存
|
||||||
|
```csharp
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
var t6 = update.SetSource(items).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `Clicks` = CASE `Id` WHEN 1 THEN ?p_0 WHEN 2 THEN ?p_1 WHEN 3 THEN ?p_2 WHEN 4 THEN ?p_3 WHEN 5 THEN ?p_4 WHEN 6 THEN ?p_5 WHEN 7 THEN ?p_6 WHEN 8 THEN ?p_7 WHEN 9 THEN ?p_8 WHEN 10 THEN ?p_9 END, `Title` = CASE `Id` WHEN 1 THEN ?p_10 WHEN 2 THEN ?p_11 WHEN 3 THEN ?p_12 WHEN 4 THEN ?p_13 WHEN 5 THEN ?p_14 WHEN 6 THEN ?p_15 WHEN 7 THEN ?p_16 WHEN 8 THEN ?p_17 WHEN 9 THEN ?p_18 WHEN 10 THEN ?p_19 END, `CreateTime` = CASE `Id` WHEN 1 THEN ?p_20 WHEN 2 THEN ?p_21 WHEN 3 THEN ?p_22 WHEN 4 THEN ?p_23 WHEN 5 THEN ?p_24 WHEN 6 THEN ?p_25 WHEN 7 THEN ?p_26 WHEN 8 THEN ?p_27 WHEN 9 THEN ?p_28 WHEN 10 THEN ?p_29 END WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))
|
||||||
|
```
|
||||||
|
|
||||||
|
> 批量保存的场景,先查询20条记录,根据本地很复杂的规则把集合的值改完后
|
||||||
|
|
||||||
|
> 传统做法是循环20次保存,用 case when 只要一次就行
|
||||||
|
|
||||||
|
### 批量保存,忽略一些列
|
||||||
|
```csharp
|
||||||
|
var t7 = update.SetSource(items).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `Title` = CASE `Id` WHEN 1 THEN ?p_0 WHEN 2 THEN ?p_1 WHEN 3 THEN ?p_2 WHEN 4 THEN ?p_3 WHEN 5 THEN ?p_4 WHEN 6 THEN ?p_5 WHEN 7 THEN ?p_6 WHEN 8 THEN ?p_7 WHEN 9 THEN ?p_8 WHEN 10 THEN ?p_9 END WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 批量更新指定列
|
||||||
|
```csharp
|
||||||
|
var t8 = update.SetSource(items).Set(a => a.CreateTime, DateTime.Now).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `CreateTime` = ?p_0 WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))
|
||||||
|
```
|
||||||
|
|
||||||
|
> 指定列更新后,批量保存将失效
|
||||||
|
|
||||||
|
### 更新条件
|
||||||
|
|
||||||
|
> 除了顶上介绍的 dywhere 构造参数外,还支持 Where lambda/sql 方法
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t9 = update.Set(a => a.Title, "新标题").Where(a => a.Id == 1).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET `Title` = '新标题' WHERE (Id = 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 自定义SQL
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var t10 = update.SetRaw("Title = {0}", "新标题").Where("Id = {0}", 1).ToSql();
|
||||||
|
//UPDATE `tb_topic` SET Title = '新标题' WHERE (Id = 1)
|
||||||
|
//sql语法条件,参数使用 {0},与 string.Format 保持一致,无须加单引号,错误的用法:'{0}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 执行命令
|
||||||
|
|
||||||
|
| 方法 | 返回值 | 参数 | 描述 |
|
||||||
|
| - | - | - | - |
|
||||||
|
| ExecuteAffrows | long | | 执行SQL语句,返回影响的行数 |
|
||||||
|
| ExecuteUpdated | List\<T1\> | | 执行SQL语句,返回更新后的记录 |
|
126
FreeSql.Tests/Class1.cs
Normal file
126
FreeSql.Tests/Class1.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
|
||||||
|
//using System;
|
||||||
|
//using System.Collections;
|
||||||
|
//using System.Collections.Generic;
|
||||||
|
//using System.Linq;
|
||||||
|
//using System.Text;
|
||||||
|
//using System.Text.RegularExpressions;
|
||||||
|
//using FreeSql;
|
||||||
|
//using FreeSql.DatabaseModel;
|
||||||
|
|
||||||
|
////namespace TplDynamicCodeGenerate {
|
||||||
|
//public class TplDynamicCodeGenerate_view1 : FreeSql.Generator.TemplateEngin.ITemplateOutput {
|
||||||
|
// public FreeSql.Generator.TemplateEngin.TemplateReturnInfo OuTpUt(StringBuilder tOuTpUt, IDictionary oPtIoNs, string rEfErErFiLeNaMe, FreeSql.Generator.TemplateEngin tEmPlAtEsEnDeR) {
|
||||||
|
// FreeSql.Generator.TemplateEngin.TemplateReturnInfo rTn = tOuTpUt == null ?
|
||||||
|
// new FreeSql.Generator.TemplateEngin.TemplateReturnInfo { Sb = (tOuTpUt = new StringBuilder()), Blocks = new Dictionary<string, int[]>() } :
|
||||||
|
// new FreeSql.Generator.TemplateEngin.TemplateReturnInfo { Sb = tOuTpUt, Blocks = new Dictionary<string, int[]>() };
|
||||||
|
// Dictionary<string, int[]> TPL__blocks = rTn.Blocks;
|
||||||
|
// Stack<int[]> TPL__blocks_stack = new Stack<int[]>();
|
||||||
|
// int[] TPL__blocks_stack_peek;
|
||||||
|
// List<IDictionary> TPL__forc = new List<IDictionary>();
|
||||||
|
// Func<IDictionary> pRoCeSsOpTiOnS = new Func<IDictionary>(delegate () {
|
||||||
|
// IDictionary nEwoPtIoNs = new Hashtable();
|
||||||
|
// foreach (DictionaryEntry oPtIoNs_dE in oPtIoNs)
|
||||||
|
// nEwoPtIoNs[oPtIoNs_dE.Key] = oPtIoNs_dE.Value;
|
||||||
|
// foreach (IDictionary TPL__forc_dIc in TPL__forc)
|
||||||
|
// foreach (DictionaryEntry TPL__forc_dIc_dE in TPL__forc_dIc)
|
||||||
|
// nEwoPtIoNs[TPL__forc_dIc_dE.Key] = TPL__forc_dIc_dE.Value;
|
||||||
|
// return nEwoPtIoNs;
|
||||||
|
// });
|
||||||
|
// FreeSql.Generator.TemplateEngin.TemplateIf tPlIf = delegate (object exp) {
|
||||||
|
// if (exp is bool) return (bool)exp;
|
||||||
|
// if (exp == null) return false;
|
||||||
|
// if (exp is int && (int)exp == 0) return false;
|
||||||
|
// if (exp is string && (string)exp == string.Empty) return false;
|
||||||
|
// if (exp is long && (long)exp == 0) return false;
|
||||||
|
// if (exp is short && (short)exp == 0) return false;
|
||||||
|
// if (exp is byte && (byte)exp == 0) return false;
|
||||||
|
// if (exp is double && (double)exp == 0) return false;
|
||||||
|
// if (exp is float && (float)exp == 0) return false;
|
||||||
|
// if (exp is decimal && (decimal)exp == 0) return false;
|
||||||
|
// return true;
|
||||||
|
// };
|
||||||
|
// FreeSql.Generator.TemplateEngin.TemplatePrint print = delegate (object[] pArMs) {
|
||||||
|
// if (pArMs == null || pArMs.Length == 0) return;
|
||||||
|
// foreach (object pArMs_A in pArMs) if (pArMs_A != null) tOuTpUt.Append(pArMs_A);
|
||||||
|
// };
|
||||||
|
// FreeSql.Generator.TemplateEngin.TemplatePrint Print = prin
|
||||||
|
// dynamic index = oPtIoNs["index"];
|
||||||
|
// dynamic col = oPtIoNs["col"];
|
||||||
|
// dynamic table = oPtIoNs["table"];
|
||||||
|
// dynamic dbfirst = oPtIoNs["dbfirst"]; t;
|
||||||
|
// tOuTpUt.Append("using System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Reflection;\r\nusing System.Threading.Tasks;\r\nusing Newtonsoft.Json;\r\nusing FreeSql.DataAnnotations;\r\n");
|
||||||
|
|
||||||
|
// var dbf = dbfirst as FreeSql.IDbFirst;
|
||||||
|
// var cols = (table.Columns as List<DbColumnInfo>);
|
||||||
|
|
||||||
|
// Func<string, string> UString = stra => stra.Substring(0, 1).ToUpper() + stra.Substring(1);
|
||||||
|
// Func<DbColumnInfo, string> GetCsType = cola3 => {
|
||||||
|
// if (cola3.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Enum || cola3.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Set) {
|
||||||
|
// return $"{UString(cola3.Table.Name)}{cola3.Name.ToUpper()}{(cola3.IsNullable ? "?" : "")}";
|
||||||
|
// }
|
||||||
|
// return dbf.GetCsType(cola3);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// tOuTpUt.Append("\r\nnamespace test.Model {\r\n\r\n [JsonObject(MemberSerialization.OptIn), Table(Name = \"");
|
||||||
|
// Print(!string.IsNullOrEmpty(table.Schema) ? table.Schema + "." : "");
|
||||||
|
// tOuTpUt.Append("");
|
||||||
|
// Print(table.Name);
|
||||||
|
// tOuTpUt.Append("\"");
|
||||||
|
// if (tPlIf(cols.Where(cola003 => cola003.Name.ToLower() == "is_deleted" || cola003.Name.ToLower() == "isdeleted").Any())) {
|
||||||
|
// tOuTpUt.Append(", SelectFilter = \"a.IsDeleted = 1\"");
|
||||||
|
// }
|
||||||
|
// tOuTpUt.Append(")]\r\n public partial class ");
|
||||||
|
// Print(UString(table.Name));
|
||||||
|
// tOuTpUt.Append(" {");
|
||||||
|
// //new Action(delegate () {
|
||||||
|
// IDictionary TPL__tmp1 = new Hashtable();
|
||||||
|
// TPL__forc.Add(TPL__tmp1);
|
||||||
|
// var TPL__tmp2 = table.Columns;
|
||||||
|
// var TPL__tmp3 = col;
|
||||||
|
// var TPL__tmp4 = index;
|
||||||
|
// index = 0;
|
||||||
|
// if (TPL__tmp2 != null)
|
||||||
|
// foreach (var TPL__tmp5 in TPL__tmp2) {
|
||||||
|
// TPL__tmp1["index"] = ++index;
|
||||||
|
// TPL__tmp1["col"] = TPL__tmp5;
|
||||||
|
// col = TPL__tmp5;
|
||||||
|
// tOuTpUt.Append("\r\n ");
|
||||||
|
// if (tPlIf(string.IsNullOrEmpty(col.Coment) == false)) {
|
||||||
|
// tOuTpUt.Append("/// <summary>\r\n /// ");
|
||||||
|
// Print(col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n /// "));
|
||||||
|
// tOuTpUt.Append("\r\n /// </summary>");
|
||||||
|
// }
|
||||||
|
// tOuTpUt.Append("\r\n [JsonProperty, Column(Name = \"");
|
||||||
|
// Print(col.Name);
|
||||||
|
// tOuTpUt.Append("\", DbType = \"");
|
||||||
|
// Print(col.DbTypeTextFull);
|
||||||
|
// tOuTpUt.Append("\"");
|
||||||
|
// if (tPlIf(col.IsPrimary == true)) {
|
||||||
|
// tOuTpUt.Append(", IsPrimary = true");
|
||||||
|
// }
|
||||||
|
// tOuTpUt.Append("");
|
||||||
|
// if (tPlIf(col.IsIdentity == true)) {
|
||||||
|
// tOuTpUt.Append(", IsIdentity = true");
|
||||||
|
// }
|
||||||
|
// tOuTpUt.Append("");
|
||||||
|
// if (tPlIf(col.IsNullable == true)) {
|
||||||
|
// tOuTpUt.Append(", IsNullable = true");
|
||||||
|
// }
|
||||||
|
// tOuTpUt.Append(")]\r\n public ");
|
||||||
|
// Print(GetCsType(col));
|
||||||
|
// tOuTpUt.Append(" ");
|
||||||
|
// Print(UString(col.Name));
|
||||||
|
// tOuTpUt.Append(" { get; set; }\r\n ");
|
||||||
|
// }
|
||||||
|
// col = TPL__tmp3;
|
||||||
|
// index = TPL__tmp4;
|
||||||
|
// TPL__forc.RemoveAt(TPL__forc.Count - 1);
|
||||||
|
// //})();
|
||||||
|
// tOuTpUt.Append("\r\n }\r\n");
|
||||||
|
// tEmPlAtEsEnDeR.RenderFile2(tOuTpUt, pRoCeSsOpTiOnS(), "../../include/enumtype.tpl", rEfErErFiLeNaMe);
|
||||||
|
// tOuTpUt.Append("\r\n}");
|
||||||
|
// return rTn;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
////}
|
65
FreeSql.Tests/Extensions/StringExtensionsTest.cs
Normal file
65
FreeSql.Tests/Extensions/StringExtensionsTest.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.Extensions {
|
||||||
|
public class StringExtensionsTest {
|
||||||
|
[Fact]
|
||||||
|
public void FormatMySql() {
|
||||||
|
|
||||||
|
Assert.Empty(((string)null).FormatMySql("11"));
|
||||||
|
Assert.Equal("a=1", "a={0}".FormatMySql(1));
|
||||||
|
Assert.Equal("a =1", "a ={0}".FormatMySql(1));
|
||||||
|
Assert.Equal("a = 1", "a = {0}".FormatMySql(1));
|
||||||
|
Assert.Equal("a='a'", "a={0}".FormatMySql('a'));
|
||||||
|
Assert.Equal("a ='a'", "a ={0}".FormatMySql('a'));
|
||||||
|
Assert.Equal("a = 'a'", "a = {0}".FormatMySql('a'));
|
||||||
|
|
||||||
|
Assert.Equal("a=1 and b IS NULL", "a={0} and b={1}".FormatMySql(1, null));
|
||||||
|
Assert.Equal("a =1 and b IS NULL", "a ={0} and b ={1}".FormatMySql(1, null));
|
||||||
|
Assert.Equal("a = 1 and b IS NULL", "a = {0} and b = {1}".FormatMySql(1, null));
|
||||||
|
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c in (1,2,3,4)", "a={0} and b={1} and c in {2}".FormatMySql(1, null, new[] { 1, 2, 3, 4 }));
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c IS NULL", "a={0} and b={1} and c in {2}".FormatMySql(1, null, null));
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c not IS NULL", "a={0} and b={1} and c not in {2}".FormatMySql(1, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FormatSqlServer() {
|
||||||
|
|
||||||
|
Assert.Empty(((string)null).FormatSqlServer("11"));
|
||||||
|
Assert.Equal("a=1", "a={0}".FormatSqlServer(1));
|
||||||
|
Assert.Equal("a =1", "a ={0}".FormatSqlServer(1));
|
||||||
|
Assert.Equal("a = 1", "a = {0}".FormatSqlServer(1));
|
||||||
|
Assert.Equal("a='a'", "a={0}".FormatSqlServer('a'));
|
||||||
|
Assert.Equal("a ='a'", "a ={0}".FormatSqlServer('a'));
|
||||||
|
Assert.Equal("a = 'a'", "a = {0}".FormatSqlServer('a'));
|
||||||
|
|
||||||
|
Assert.Equal("a=1 and b IS NULL", "a={0} and b={1}".FormatSqlServer(1, null));
|
||||||
|
Assert.Equal("a =1 and b IS NULL", "a ={0} and b ={1}".FormatSqlServer(1, null));
|
||||||
|
Assert.Equal("a = 1 and b IS NULL", "a = {0} and b = {1}".FormatSqlServer(1, null));
|
||||||
|
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c in (1,2,3,4)", "a={0} and b={1} and c in {2}".FormatSqlServer(1, null, new[] { 1, 2, 3, 4 }));
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c IS NULL", "a={0} and b={1} and c in {2}".FormatSqlServer(1, null, null));
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c not IS NULL", "a={0} and b={1} and c not in {2}".FormatSqlServer(1, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FormatPostgreSQL() {
|
||||||
|
|
||||||
|
Assert.Empty(((string)null).FormatPostgreSQL("11"));
|
||||||
|
Assert.Equal("a=1", "a={0}".FormatPostgreSQL(1));
|
||||||
|
Assert.Equal("a =1", "a ={0}".FormatPostgreSQL(1));
|
||||||
|
Assert.Equal("a = 1", "a = {0}".FormatPostgreSQL(1));
|
||||||
|
Assert.Equal("a='a'", "a={0}".FormatPostgreSQL('a'));
|
||||||
|
Assert.Equal("a ='a'", "a ={0}".FormatPostgreSQL('a'));
|
||||||
|
Assert.Equal("a = 'a'", "a = {0}".FormatPostgreSQL('a'));
|
||||||
|
|
||||||
|
Assert.Equal("a=1 and b IS NULL", "a={0} and b={1}".FormatPostgreSQL(1, null));
|
||||||
|
Assert.Equal("a =1 and b IS NULL", "a ={0} and b ={1}".FormatPostgreSQL(1, null));
|
||||||
|
Assert.Equal("a = 1 and b IS NULL", "a = {0} and b = {1}".FormatPostgreSQL(1, null));
|
||||||
|
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c in (1,2,3,4)", "a={0} and b={1} and c in {2}".FormatPostgreSQL(1, null, new[] { 1, 2, 3, 4 }));
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c IS NULL", "a={0} and b={1} and c in {2}".FormatSqlServer(1, null, null));
|
||||||
|
Assert.Equal("a=1 and b IS NULL and c not IS NULL", "a={0} and b={1} and c not in {2}".FormatSqlServer(1, null, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
FreeSql.Tests/FreeSql.Tests.csproj
Normal file
19
FreeSql.Tests/FreeSql.Tests.csproj
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.0" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\FreeSql\FreeSql.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
27
FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs
Normal file
27
FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using FreeSql.Generator;
|
||||||
|
using System;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.Generator {
|
||||||
|
public class MySqlTemplateGeneratorTest {
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildSimpleEntity() {
|
||||||
|
var gen = new TemplateGenerator();
|
||||||
|
gen.Build(g.mysql.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", @"C:\Users\28810\Desktop\新建文件夹 (9)", "cccddd");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildSimpleEntityNavigationObject () {
|
||||||
|
var gen = new TemplateGenerator();
|
||||||
|
gen.Build(g.mysql.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity-navigation-object", @"C:\Users\28810\Desktop\新建文件夹 (9)", "cccddd");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BuildRichEntityNavigationObject() {
|
||||||
|
var gen = new TemplateGenerator();
|
||||||
|
gen.Build(g.mysql.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\rich-entity-navigation-object", @"C:\Users\28810\Desktop\新建文件夹 (9)", "cccddd");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
FreeSql.Tests/MySql/Curd/MySqlDeleteTest.cs
Normal file
72
FreeSql.Tests/MySql/Curd/MySqlDeleteTest.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.MySql {
|
||||||
|
public class MySqlDeleteTest {
|
||||||
|
|
||||||
|
IDelete<Topic> delete => g.mysql.Delete<Topic>(); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
[Table(Name = "tb_topic")]
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Clicks { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Dywhere() {
|
||||||
|
Assert.Null(g.mysql.Delete<Topic>().ToSql());
|
||||||
|
var sql = g.mysql.Delete<Topic>(new[] { 1, 2 }).ToSql();
|
||||||
|
Assert.Equal("DELETE FROM `tb_topic` WHERE (`Id` = 1 OR `Id` = 2)", sql);
|
||||||
|
|
||||||
|
sql = g.mysql.Delete<Topic>(new Topic { Id = 1, Title = "test" }).ToSql();
|
||||||
|
Assert.Equal("DELETE FROM `tb_topic` WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
sql = g.mysql.Delete<Topic>(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).ToSql();
|
||||||
|
Assert.Equal("DELETE FROM `tb_topic` WHERE (`Id` = 1 OR `Id` = 2)", sql);
|
||||||
|
|
||||||
|
sql = g.mysql.Delete<Topic>(new { id = 1 }).ToSql();
|
||||||
|
Assert.Equal("DELETE FROM `tb_topic` WHERE (`Id` = 1)", sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Where() {
|
||||||
|
var sql = delete.Where(a => a.Id == 1).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("DELETE FROM `tb_topic` WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
sql = delete.Where("id = ?id", new { id = 1 }).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("DELETE FROM `tb_topic` WHERE (id = ?id)", sql);
|
||||||
|
|
||||||
|
var item = new Topic { Id = 1, Title = "newtitle" };
|
||||||
|
sql = delete.Where(item).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("DELETE FROM `tb_topic` WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
sql = delete.Where(items).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("DELETE FROM `tb_topic` WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))", sql);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void WhereExists() {
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteAffrows() {
|
||||||
|
|
||||||
|
var id = g.mysql.Insert<Topic>(new Topic { Title = "xxxx" }).ExecuteIdentity();
|
||||||
|
Assert.Equal(1, delete.Where(a => a.Id == id).ExecuteAffrows());
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteDeleted() {
|
||||||
|
|
||||||
|
Assert.Throws<NotImplementedException>(() => delete.Where(a => a.Id > 0).ExecuteDeleted());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
85
FreeSql.Tests/MySql/Curd/MySqlInsertTest.cs
Normal file
85
FreeSql.Tests/MySql/Curd/MySqlInsertTest.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.MySql {
|
||||||
|
public class MySqlInsertTest {
|
||||||
|
|
||||||
|
IInsert<Topic> insert => g.mysql.Insert<Topic>(); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
|
||||||
|
[Table(Name = "tb_topic")]
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Clicks { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AppendData() {
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
var sql = insert.AppendData(items.First()).ToSql();
|
||||||
|
Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks0, ?Title0, ?CreateTime0)", sql);
|
||||||
|
|
||||||
|
sql = insert.AppendData(items).ToSql();
|
||||||
|
Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`, `CreateTime`) VALUES(?Clicks0, ?Title0, ?CreateTime0), (?Clicks1, ?Title1, ?CreateTime1), (?Clicks2, ?Title2, ?CreateTime2), (?Clicks3, ?Title3, ?CreateTime3), (?Clicks4, ?Title4, ?CreateTime4), (?Clicks5, ?Title5, ?CreateTime5), (?Clicks6, ?Title6, ?CreateTime6), (?Clicks7, ?Title7, ?CreateTime7), (?Clicks8, ?Title8, ?CreateTime8), (?Clicks9, ?Title9, ?CreateTime9)", sql);
|
||||||
|
|
||||||
|
sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
|
||||||
|
Assert.Equal("INSERT INTO `tb_topic`(`Title`) VALUES(?Title0), (?Title1), (?Title2), (?Title3), (?Title4), (?Title5), (?Title6), (?Title7), (?Title8), (?Title9)", sql);
|
||||||
|
|
||||||
|
sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
|
||||||
|
Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void InsertColumns() {
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
var sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql();
|
||||||
|
Assert.Equal("INSERT INTO `tb_topic`(`Title`) VALUES(?Title0), (?Title1), (?Title2), (?Title3), (?Title4), (?Title5), (?Title6), (?Title7), (?Title8), (?Title9)", sql);
|
||||||
|
|
||||||
|
sql = insert.AppendData(items).InsertColumns(a =>new { a.Title, a.Clicks }).ToSql();
|
||||||
|
Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void IgnoreColumns() {
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
var sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql();
|
||||||
|
Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks0, ?Title0), (?Clicks1, ?Title1), (?Clicks2, ?Title2), (?Clicks3, ?Title3), (?Clicks4, ?Title4), (?Clicks5, ?Title5), (?Clicks6, ?Title6), (?Clicks7, ?Title7), (?Clicks8, ?Title8), (?Clicks9, ?Title9)", sql);
|
||||||
|
|
||||||
|
sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql();
|
||||||
|
Assert.Equal("INSERT INTO `tb_topic`(`Clicks`) VALUES(?Clicks0), (?Clicks1), (?Clicks2), (?Clicks3), (?Clicks4), (?Clicks5), (?Clicks6), (?Clicks7), (?Clicks8), (?Clicks9)", sql);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteAffrows() {
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
Assert.Equal(1, insert.AppendData(items.First()).ExecuteAffrows());
|
||||||
|
Assert.Equal(10, insert.AppendData(items).ExecuteAffrows());
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteIdentity() {
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
Assert.NotEqual(0, insert.AppendData(items.First()).ExecuteIdentity());
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteInserted() {
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
Assert.Throws<NotImplementedException>(() => insert.AppendData(items.First()).ExecuteInserted());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
501
FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs
Normal file
501
FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs
Normal file
@ -0,0 +1,501 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.MySql {
|
||||||
|
public class MySqlSelectTest {
|
||||||
|
|
||||||
|
ISelect<Topic> select => g.mysql.Select<Topic>();
|
||||||
|
|
||||||
|
[Table(Name = "tb_topic")]
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Clicks { get; set; }
|
||||||
|
public int TestTypeInfoGuid { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
class TestTypeInfo {
|
||||||
|
public int Guid { get; set; }
|
||||||
|
public int ParentId { get; set; }
|
||||||
|
public TestTypeParentInfo Parent { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
class TestTypeParentInfo {
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public List<TestTypeInfo> Types { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ToList() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ToOne() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ToSql() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Any() {
|
||||||
|
var count = select.Where(a => 1 == 1).Count();
|
||||||
|
Assert.False(select.Where(a => 1 == 2).Any());
|
||||||
|
Assert.Equal(count > 0, select.Where(a => 1 == 1).Any());
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Count() {
|
||||||
|
var count = select.Where(a => 1 == 1).Count();
|
||||||
|
select.Where(a => 1 == 1).Count(out var count2);
|
||||||
|
Assert.Equal(count, count2);
|
||||||
|
Assert.Equal(0, select.Where(a => 1 == 2).Count());
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Master() {
|
||||||
|
Assert.StartsWith(" SELECT", select.Master().Where(a => 1 == 1).ToSql());
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Caching() {
|
||||||
|
var result1 = select.Where(a => 1 == 1).Caching(20, "testcaching").ToList();
|
||||||
|
var testcaching1 = g.mysql.Cache.Get("testcaching");
|
||||||
|
Assert.NotNull(testcaching1);
|
||||||
|
var result2 = select.Where(a => 1 == 1).Caching(20, "testcaching").ToList();
|
||||||
|
var testcaching2 = g.mysql.Cache.Get("testcaching");
|
||||||
|
Assert.NotNull(testcaching2);
|
||||||
|
Assert.Equal(result1.Count, result1.Count);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void From() {
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
var query2 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.LeftJoin(a => a.TestTypeInfoGuid == b.Guid)
|
||||||
|
.LeftJoin(a => b.ParentId == c.Id)
|
||||||
|
);
|
||||||
|
var sql = query2.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON a.`TestTypeInfoGuid` = b.`Guid` LEFT JOIN `TestTypeParentInfo` c ON b.`ParentId` = c.`Id`", sql);
|
||||||
|
query2.ToList();
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void LeftJoin() {
|
||||||
|
//<2F><><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a.Type<70><65>a.Type.Parent <20><><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
var query = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid);
|
||||||
|
var sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` AND a__Type.`Name` = 'xxx'", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeParentInfo` a__Type__Parent ON 1 = 1 LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` AND a__Type.`Name` = 'xxx' WHERE (a__Type__Parent.`Id` = 10)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD>û<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query = select.LeftJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.LeftJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'xxx'", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.LeftJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx").Where(a => a.Type.Parent.Id == 10);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeParentInfo` b__Parent ON 1 = 1 LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'xxx' WHERE (b__Parent.`Id` = 10)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query = select
|
||||||
|
.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid)
|
||||||
|
.LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` LEFT JOIN `TestTypeParentInfo` a__Type__Parent ON a__Type__Parent.`Id` = a__Type.`ParentId`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select
|
||||||
|
.LeftJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid)
|
||||||
|
.LeftJoin<TestTypeParentInfo>((a, c) => c.Id == a.Type.ParentId);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` LEFT JOIN `TestTypeParentInfo` c ON c.`Id` = b.`ParentId`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD>û<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>b<EFBFBD><62>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ
|
||||||
|
var query2 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.LeftJoin(a => a.TestTypeInfoGuid == b.Guid)
|
||||||
|
.LeftJoin(a => b.ParentId == c.Id));
|
||||||
|
sql = query2.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON a.`TestTypeInfoGuid` = b.`Guid` LEFT JOIN `TestTypeParentInfo` c ON b.`ParentId` = c.`Id`", sql);
|
||||||
|
query2.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD>㲻<EFBFBD><E3B2BB>
|
||||||
|
query = select.LeftJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a LEFT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.LeftJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", new { bname = "xxx" });
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a LEFT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", sql);
|
||||||
|
query.ToList();
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void InnerJoin() {
|
||||||
|
//<2F><><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a.Type<70><65>a.Type.Parent <20><><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
var query = select.InnerJoin(a => a.Type.Guid == a.TestTypeInfoGuid);
|
||||||
|
var sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a INNER JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.InnerJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a INNER JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` AND a__Type.`Name` = 'xxx'", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.InnerJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeParentInfo` a__Type__Parent ON 1 = 1 INNER JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` AND a__Type.`Name` = 'xxx' WHERE (a__Type__Parent.`Id` = 10)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD>û<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query = select.InnerJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a INNER JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.InnerJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a INNER JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'xxx'", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.InnerJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx").Where(a => a.Type.Parent.Id == 10);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeParentInfo` b__Parent ON 1 = 1 INNER JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'xxx' WHERE (b__Parent.`Id` = 10)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query = select
|
||||||
|
.InnerJoin(a => a.Type.Guid == a.TestTypeInfoGuid)
|
||||||
|
.InnerJoin(a => a.Type.Parent.Id == a.Type.ParentId);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a INNER JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` INNER JOIN `TestTypeParentInfo` a__Type__Parent ON a__Type__Parent.`Id` = a__Type.`ParentId`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select
|
||||||
|
.InnerJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid)
|
||||||
|
.InnerJoin<TestTypeParentInfo>((a, c) => c.Id == a.Type.ParentId);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a INNER JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` INNER JOIN `TestTypeParentInfo` c ON c.`Id` = b.`ParentId`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD>û<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>b<EFBFBD><62>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ
|
||||||
|
var query2 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.InnerJoin(a => a.TestTypeInfoGuid == b.Guid)
|
||||||
|
.InnerJoin(a => b.ParentId == c.Id));
|
||||||
|
sql = query2.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a INNER JOIN `TestTypeInfo` b ON a.`TestTypeInfoGuid` = b.`Guid` INNER JOIN `TestTypeParentInfo` c ON b.`ParentId` = c.`Id`", sql);
|
||||||
|
query2.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD>㲻<EFBFBD><E3B2BB>
|
||||||
|
query = select.InnerJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a INNER JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.InnerJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", new { bname = "xxx" });
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a INNER JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void RightJoin() {
|
||||||
|
//<2F><><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a.Type<70><65>a.Type.Parent <20><><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
var query = select.RightJoin(a => a.Type.Guid == a.TestTypeInfoGuid);
|
||||||
|
var sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a RIGHT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.RightJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a RIGHT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` AND a__Type.`Name` = 'xxx'", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.RightJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeParentInfo` a__Type__Parent ON 1 = 1 RIGHT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` AND a__Type.`Name` = 'xxx' WHERE (a__Type__Parent.`Id` = 10)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD>û<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query = select.RightJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a RIGHT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.RightJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a RIGHT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'xxx'", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.RightJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx").Where(a => a.Type.Parent.Id == 10);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeParentInfo` b__Parent ON 1 = 1 RIGHT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'xxx' WHERE (b__Parent.`Id` = 10)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query = select
|
||||||
|
.RightJoin(a => a.Type.Guid == a.TestTypeInfoGuid)
|
||||||
|
.RightJoin(a => a.Type.Parent.Id == a.Type.ParentId);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a RIGHT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` RIGHT JOIN `TestTypeParentInfo` a__Type__Parent ON a__Type__Parent.`Id` = a__Type.`ParentId`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select
|
||||||
|
.RightJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid)
|
||||||
|
.RightJoin<TestTypeParentInfo>((a, c) => c.Id == a.Type.ParentId);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a RIGHT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` RIGHT JOIN `TestTypeParentInfo` c ON c.`Id` = b.`ParentId`", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD>û<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>b<EFBFBD><62>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ
|
||||||
|
var query2 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.RightJoin(a => a.TestTypeInfoGuid == b.Guid)
|
||||||
|
.RightJoin(a => b.ParentId == c.Id));
|
||||||
|
sql = query2.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a RIGHT JOIN `TestTypeInfo` b ON a.`TestTypeInfoGuid` = b.`Guid` RIGHT JOIN `TestTypeParentInfo` c ON b.`ParentId` = c.`Id`", sql);
|
||||||
|
query2.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD>㲻<EFBFBD><E3B2BB>
|
||||||
|
query = select.RightJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a RIGHT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.RightJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", new { bname = "xxx" });
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a RIGHT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Where() {
|
||||||
|
//<2F><><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a.Type<70><65>a.Type.Parent <20><><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
var query = select.Where(a => a.Id == 10);
|
||||||
|
var sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.`Id` = 10)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.Where(a => a.Id == 10 && a.Id > 10 || a.Clicks > 100);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.`Id` = 10 AND a.`Id` > 10 OR a.`Clicks` > 100)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.Where(a => a.Id == 10).Where(a => a.Clicks > 100);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.`Id` = 10) AND (a.`Clicks` > 100)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.Where(a => a.Type.Name == "typeTitle");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` a__Type WHERE (a__Type.`Name` = 'typeTitle')", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.Where(a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` a__Type WHERE (a__Type.`Name` = 'typeTitle' AND a__Type.`Guid` = a.`TestTypeInfoGuid`)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.Where(a => a.Type.Parent.Name == "tparent");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` a__Type, `TestTypeParentInfo` a__Type__Parent WHERE (a__Type__Parent.`Name` = 'tparent')", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD>û<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԣ<EFBFBD><D4A3><EFBFBD><F2B5A5B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query = select.Where<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "typeTitle");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` b WHERE (b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'typeTitle')", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.Where<TestTypeInfo>((a, b) => b.Name == "typeTitle" && b.Guid == a.TestTypeInfoGuid);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` b WHERE (b.`Name` = 'typeTitle' AND b.`Guid` = a.`TestTypeInfoGuid`)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.Where<TestTypeInfo, TestTypeParentInfo>((a, b, c) => c.Name == "tparent");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a, `TestTypeParentInfo` c WHERE (c.`Name` = 'tparent')", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> From <20><>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
var query2 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.Where(a => a.Id == 10 && c.Name == "xxx")
|
||||||
|
.Where(a => b.ParentId == 20));
|
||||||
|
sql = query2.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeParentInfo` c, `TestTypeInfo` b WHERE (a.`Id` = 10 AND c.`Name` = 'xxx') AND (b.`ParentId` = 20)", sql);
|
||||||
|
query2.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD>㲻<EFBFBD><E3B2BB>
|
||||||
|
query = select.Where("a.clicks > 100 && a.id = ?id", new { id = 10 });
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.clicks > 100 && a.id = ?id)", sql);
|
||||||
|
query.ToList();
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void WhereIf() {
|
||||||
|
//<2F><><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a.Type<70><65>a.Type.Parent <20><><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
var query = select.WhereIf(true, a => a.Id == 10);
|
||||||
|
var sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.`Id` = 10)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(true, a => a.Id == 10 && a.Id > 10 || a.Clicks > 100);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.`Id` = 10 AND a.`Id` > 10 OR a.`Clicks` > 100)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(true, a => a.Id == 10).WhereIf(true, a => a.Clicks > 100);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.`Id` = 10) AND (a.`Clicks` > 100)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(true, a => a.Type.Name == "typeTitle");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` a__Type WHERE (a__Type.`Name` = 'typeTitle')", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(true, a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` a__Type WHERE (a__Type.`Name` = 'typeTitle' AND a__Type.`Guid` = a.`TestTypeInfoGuid`)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(true, a => a.Type.Parent.Name == "tparent");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` a__Type, `TestTypeParentInfo` a__Type__Parent WHERE (a__Type__Parent.`Name` = 'tparent')", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> From <20><>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
var query2 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.WhereIf(true, a => a.Id == 10 && c.Name == "xxx")
|
||||||
|
.WhereIf(true, a => b.ParentId == 20));
|
||||||
|
sql = query2.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeParentInfo` c, `TestTypeInfo` b WHERE (a.`Id` = 10 AND c.`Name` = 'xxx') AND (b.`ParentId` = 20)", sql);
|
||||||
|
query2.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD>㲻<EFBFBD><E3B2BB>
|
||||||
|
query = select.WhereIf(true, "a.clicks > 100 && a.id = ?id", new { id = 10 });
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.clicks > 100 && a.id = ?id)", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
// ==========================================WhereIf(false)
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a.Type<70><65>a.Type.Parent <20><><EFBFBD>ǵ<EFBFBD><C7B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query = select.WhereIf(false, a => a.Id == 10);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(false, a => a.Id == 10 && a.Id > 10 || a.Clicks > 100);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(false, a => a.Id == 10).WhereIf(false, a => a.Clicks > 100);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(false, a => a.Type.Name == "typeTitle");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(false, a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid);
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
query = select.WhereIf(false, a => a.Type.Parent.Name == "tparent");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql);
|
||||||
|
query.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> From <20><>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
query2 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.WhereIf(false, a => a.Id == 10 && c.Name == "xxx")
|
||||||
|
.WhereIf(false, a => b.ParentId == 20));
|
||||||
|
sql = query2.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql);
|
||||||
|
query2.ToList();
|
||||||
|
|
||||||
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>϶<EFBFBD><CFB6><EFBFBD><EFBFBD>㲻<EFBFBD><E3B2BB>
|
||||||
|
query = select.WhereIf(false, "a.clicks > 100 && a.id = ?id", new { id = 10 });
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql);
|
||||||
|
query.ToList();
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void WhereLike() {
|
||||||
|
//ģ<><C4A3><EFBFBD><EFBFBD>ѯ<EFBFBD><D1AF>WhereLike(a => a.Title, "%sql")
|
||||||
|
var query = select.Where(a => a.Title.StartsWith("ss")).Where(a => a.Type.Name.Contains("sss"));
|
||||||
|
var sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
|
||||||
|
query = select.Where(a => a.Title.EndsWith("ss"));
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
|
||||||
|
query = select.Where(a => a.Title.Contains("ss"));
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
|
||||||
|
query = select.WhereLike(a => a.Title, "%ss");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
|
||||||
|
query = select.WhereLike(a => a.Title, "%ss").WhereLike(a => a.Title, "%aa");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
|
||||||
|
//ģ<><C4A3><EFBFBD><EFBFBD>ѯ<EFBFBD><D1AF>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD> OR<4F><52>WhereLike(a => new[] { a.Title, a.Content }, "%sql%")
|
||||||
|
query = select.WhereLike(a => new[] { a.Title, a.Type.Name, a.Type.Parent.Name }, "%aa");
|
||||||
|
sql = query.ToSql().Replace("\r\n", "");
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void GroupBy() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Having() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void OrderBy() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Skip_Offset() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Take_Limit() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Page() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Sum() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Min() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Max() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Avg() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void As() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
107
FreeSql.Tests/MySql/Curd/MySqlUpdateTest.cs
Normal file
107
FreeSql.Tests/MySql/Curd/MySqlUpdateTest.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.MySql {
|
||||||
|
public class MySqlUpdateTest {
|
||||||
|
IUpdate<Topic> update => g.mysql.Update<Topic>();
|
||||||
|
|
||||||
|
[Table(Name = "tb_topic")]
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int? Clicks { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Dywhere() {
|
||||||
|
Assert.Null(g.mysql.Update<Topic>().ToSql());
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET title='test' \r\nWHERE (`Id` = 1 OR `Id` = 2)", g.mysql.Update<Topic>(new[] { 1, 2 }).SetRaw("title='test'").ToSql());
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET title='test1' \r\nWHERE (`Id` = 1)", g.mysql.Update<Topic>(new Topic { Id = 1, Title = "test" }).SetRaw("title='test1'").ToSql());
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET title='test1' \r\nWHERE (`Id` = 1 OR `Id` = 2)", g.mysql.Update<Topic>(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).SetRaw("title='test1'").ToSql());
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET title='test1' \r\nWHERE (`Id` = 1)", g.mysql.Update<Topic>(new { id = 1 }).SetRaw("title='test1'").ToSql());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SetSource() {
|
||||||
|
var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Clicks` = ?p_0, `Title` = ?p_1, `CreateTime` = ?p_2 WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
|
||||||
|
sql = update.SetSource(items).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Clicks` = CASE `Id` WHEN 1 THEN ?p_0 WHEN 2 THEN ?p_1 WHEN 3 THEN ?p_2 WHEN 4 THEN ?p_3 WHEN 5 THEN ?p_4 WHEN 6 THEN ?p_5 WHEN 7 THEN ?p_6 WHEN 8 THEN ?p_7 WHEN 9 THEN ?p_8 WHEN 10 THEN ?p_9 END, `Title` = CASE `Id` WHEN 1 THEN ?p_10 WHEN 2 THEN ?p_11 WHEN 3 THEN ?p_12 WHEN 4 THEN ?p_13 WHEN 5 THEN ?p_14 WHEN 6 THEN ?p_15 WHEN 7 THEN ?p_16 WHEN 8 THEN ?p_17 WHEN 9 THEN ?p_18 WHEN 10 THEN ?p_19 END, `CreateTime` = CASE `Id` WHEN 1 THEN ?p_20 WHEN 2 THEN ?p_21 WHEN 3 THEN ?p_22 WHEN 4 THEN ?p_23 WHEN 5 THEN ?p_24 WHEN 6 THEN ?p_25 WHEN 7 THEN ?p_26 WHEN 8 THEN ?p_27 WHEN 9 THEN ?p_28 WHEN 10 THEN ?p_29 END WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))", sql);
|
||||||
|
|
||||||
|
sql = update.SetSource(items).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Title` = CASE `Id` WHEN 1 THEN ?p_0 WHEN 2 THEN ?p_1 WHEN 3 THEN ?p_2 WHEN 4 THEN ?p_3 WHEN 5 THEN ?p_4 WHEN 6 THEN ?p_5 WHEN 7 THEN ?p_6 WHEN 8 THEN ?p_7 WHEN 9 THEN ?p_8 WHEN 10 THEN ?p_9 END WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))", sql);
|
||||||
|
|
||||||
|
sql = update.SetSource(items).Set(a => a.CreateTime, new DateTime(2020,1,1)).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `CreateTime` = ?p_0 WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))", sql);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void IgnoreColumns() {
|
||||||
|
var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Title` = ?p_0 WHERE (`Id` = 1)", sql);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Set() {
|
||||||
|
var sql = update.Where(a => a.Id == 1).Set(a => a.Title, "newtitle").ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Title` = ?p_0 WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
sql = update.Where(a => a.Id == 1).Set(a => a.Title, "newtitle").Set(a => a.CreateTime, new DateTime(2020, 1, 1)).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Title` = ?p_0, `CreateTime` = ?p_1 WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
sql = update.Set(a => a.Clicks * 10 / 1).Where(a => a.Id == 1).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Clicks` = ifnull(`Clicks`, 0) * 10 / 1 WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
sql = update.Set(a => a.Id - 10).Where(a => a.Id == 1).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Id` = `Id` - 10 WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
int incrv = 10;
|
||||||
|
sql = update.Set(a => a.Clicks * incrv / 1).Where(a => a.Id == 1).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Clicks` = ifnull(`Clicks`, 0) * 10 / 1 WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
sql = update.Set(a => a.Id - incrv).Where(a => a.Id == 1).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET `Id` = `Id` - 10 WHERE (`Id` = 1)", sql);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void SetRaw() {
|
||||||
|
var sql = update.Where(a => a.Id == 1).SetRaw("clicks = clicks + ?incrClick", new { incrClick = 1 }).ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET clicks = clicks + ?incrClick WHERE (`Id` = 1)", sql);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Where() {
|
||||||
|
var sql = update.Where(a => a.Id == 1).SetRaw("title='newtitle'").ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET title='newtitle' WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
sql = update.Where("id = ?id", new { id = 1 }).SetRaw("title='newtitle'").ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET title='newtitle' WHERE (id = ?id)", sql);
|
||||||
|
|
||||||
|
var item = new Topic { Id = 1, Title = "newtitle" };
|
||||||
|
sql = update.Where(item).SetRaw("title='newtitle'").ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET title='newtitle' WHERE (`Id` = 1)", sql);
|
||||||
|
|
||||||
|
var items = new List<Topic>();
|
||||||
|
for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 });
|
||||||
|
sql = update.Where(items).SetRaw("title='newtitle'").ToSql().Replace("\r\n", "");
|
||||||
|
Assert.Equal("UPDATE `tb_topic` SET title='newtitle' WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))", sql);
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void WhereExists() {
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteAffrows() {
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteUpdated() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
FreeSql.Tests/MySql/MySqlAdo/MySqlAdoTest.cs
Normal file
54
FreeSql.Tests/MySql/MySqlAdo/MySqlAdoTest.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.MySql {
|
||||||
|
public class MySqlAdoTest {
|
||||||
|
[Fact]
|
||||||
|
public void Pool() {
|
||||||
|
var t1 = g.mysql.Ado.MasterPool.StatisticsFullily;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SlavePools() {
|
||||||
|
var t2 = g.mysql.Ado.SlavePools.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IsTracePerformance() {
|
||||||
|
Assert.True(g.mysql.Ado.IsTracePerformance);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteReader() {
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteArray() {
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteNonQuery() {
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ExecuteScalar() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Query() {
|
||||||
|
var t3 = g.mysql.Ado.Query<xxx>("select * from song");
|
||||||
|
|
||||||
|
var t4 = g.mysql.Ado.Query<(int, string, string)>("select * from song");
|
||||||
|
|
||||||
|
var t5 = g.mysql.Ado.Query<dynamic>("select * from song");
|
||||||
|
}
|
||||||
|
|
||||||
|
class xxx {
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
|
public string Title2 { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
350
FreeSql.Tests/MySql/MySqlCodeFirstTest.cs
Normal file
350
FreeSql.Tests/MySql/MySqlCodeFirstTest.cs
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.MySql {
|
||||||
|
public class MySqlCodeFirstTest {
|
||||||
|
[Fact]
|
||||||
|
public void GetComparisonDDLStatements() {
|
||||||
|
|
||||||
|
var sql = g.mysql.CodeFirst.GetComparisonDDLStatements<TableAllType>();
|
||||||
|
if (string.IsNullOrEmpty(sql) == false) {
|
||||||
|
Assert.Equal(@"CREATE TABLE IF NOT EXISTS `cccddd`.`tb_alltype` (
|
||||||
|
`Id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`testFieldBool` BIT(1) NOT NULL,
|
||||||
|
`testFieldSByte` TINYINT(3) NOT NULL,
|
||||||
|
`testFieldShort` SMALLINT(6) NOT NULL,
|
||||||
|
`testFieldInt` INT(11) NOT NULL,
|
||||||
|
`testFieldLong` BIGINT(20) NOT NULL,
|
||||||
|
`testFieldByte` TINYINT(3) UNSIGNED NOT NULL,
|
||||||
|
`testFieldUShort` SMALLINT(5) UNSIGNED NOT NULL,
|
||||||
|
`testFieldUInt` INT(10) UNSIGNED NOT NULL,
|
||||||
|
`testFieldULong` BIGINT(20) UNSIGNED NOT NULL,
|
||||||
|
`testFieldDouble` DOUBLE NOT NULL,
|
||||||
|
`testFieldFloat` FLOAT NOT NULL,
|
||||||
|
`testFieldDecimal` DECIMAL(10,2) NOT NULL,
|
||||||
|
`testFieldTimeSpan` TIME NOT NULL,
|
||||||
|
`testFieldDateTime` DATETIME NOT NULL,
|
||||||
|
`testFieldBytes` VARBINARY(255),
|
||||||
|
`testFieldString` VARCHAR(255),
|
||||||
|
`testFieldGuid` VARCHAR(36),
|
||||||
|
`testFieldBoolNullable` BIT(1),
|
||||||
|
`testFieldSByteNullable` TINYINT(3),
|
||||||
|
`testFieldShortNullable` SMALLINT(6),
|
||||||
|
`testFieldIntNullable` INT(11),
|
||||||
|
`testFielLongNullable` BIGINT(20),
|
||||||
|
`testFieldByteNullable` TINYINT(3) UNSIGNED,
|
||||||
|
`testFieldUShortNullable` SMALLINT(5) UNSIGNED,
|
||||||
|
`testFieldUIntNullable` INT(10) UNSIGNED,
|
||||||
|
`testFieldULongNullable` BIGINT(20) UNSIGNED,
|
||||||
|
`testFieldDoubleNullable` DOUBLE,
|
||||||
|
`testFieldFloatNullable` FLOAT,
|
||||||
|
`testFieldDecimalNullable` DECIMAL(10,2),
|
||||||
|
`testFieldTimeSpanNullable` TIME,
|
||||||
|
`testFieldDateTimeNullable` DATETIME,
|
||||||
|
`testFieldGuidNullable` VARCHAR(36),
|
||||||
|
`testFieldPoint` POINT,
|
||||||
|
`testFieldLineString` LINESTRING,
|
||||||
|
`testFieldPolygon` POLYGON,
|
||||||
|
`testFieldMultiPoint` MULTIPOINT,
|
||||||
|
`testFieldMultiLineString` MULTILINESTRING,
|
||||||
|
`testFieldMultiPolygon` MULTIPOLYGON,
|
||||||
|
`testFieldEnum1` ENUM('E1','E2','E3') NOT NULL,
|
||||||
|
`testFieldEnum1Nullable` ENUM('E1','E2','E3'),
|
||||||
|
`testFieldEnum2` SET('F1','F2','F3') NOT NULL,
|
||||||
|
`testFieldEnum2Nullable` SET('F1','F2','F3'),
|
||||||
|
PRIMARY KEY (`Id`)
|
||||||
|
) Engine=InnoDB CHARACTER SET utf8;
|
||||||
|
", sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
sql = g.mysql.CodeFirst.GetComparisonDDLStatements<Tb_alltype>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[JsonObject(MemberSerialization.OptIn), Table(Name = "tb_alltype")]
|
||||||
|
public partial class Tb_alltype {
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "Id", DbType = "int(11)", IsPrimary = true, IsIdentity = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldBool", DbType = "bit(1)")]
|
||||||
|
public bool TestFieldBool { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldBoolNullable", DbType = "bit(1)", IsNullable = true)]
|
||||||
|
public bool? TestFieldBoolNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldByte", DbType = "tinyint(3) unsigned")]
|
||||||
|
public byte TestFieldByte { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldByteNullable", DbType = "tinyint(3) unsigned", IsNullable = true)]
|
||||||
|
public byte? TestFieldByteNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldBytes", DbType = "varbinary(255)", IsNullable = true)]
|
||||||
|
public byte[] TestFieldBytes { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldDateTime", DbType = "datetime")]
|
||||||
|
public DateTime TestFieldDateTime { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldDateTimeNullable", DbType = "datetime", IsNullable = true)]
|
||||||
|
public DateTime? TestFieldDateTimeNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldDecimal", DbType = "decimal(10,2)")]
|
||||||
|
public decimal TestFieldDecimal { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldDecimalNullable", DbType = "decimal(10,2)", IsNullable = true)]
|
||||||
|
public decimal? TestFieldDecimalNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldDouble", DbType = "double")]
|
||||||
|
public double TestFieldDouble { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldDoubleNullable", DbType = "double", IsNullable = true)]
|
||||||
|
public double? TestFieldDoubleNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldEnum1", DbType = "enum('E1','E2','E3','E5')")]
|
||||||
|
public Tb_alltypeTESTFIELDENUM1 TestFieldEnum1 { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldEnum1Nullable", DbType = "enum('E1','E2','E3','E5')", IsNullable = true)]
|
||||||
|
public Tb_alltypeTESTFIELDENUM1NULLABLE? TestFieldEnum1Nullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldEnum2", DbType = "set('F1','F2','F3')")]
|
||||||
|
public Tb_alltypeTESTFIELDENUM2 TestFieldEnum2 { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldEnum2Nullable", DbType = "set('F1','F2','F3')", IsNullable = true)]
|
||||||
|
public Tb_alltypeTESTFIELDENUM2NULLABLE? TestFieldEnum2Nullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldFloat", DbType = "float")]
|
||||||
|
public float TestFieldFloat { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldFloatNullable", DbType = "float", IsNullable = true)]
|
||||||
|
public float? TestFieldFloatNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldGuid", DbType = "char(36)")]
|
||||||
|
public Guid TestFieldGuid { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldGuidNullable", DbType = "char(36)", IsNullable = true)]
|
||||||
|
public Guid? TestFieldGuidNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldInt", DbType = "int(11)")]
|
||||||
|
public int TestFieldInt { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldIntNullable", DbType = "int(11)", IsNullable = true)]
|
||||||
|
public int? TestFieldIntNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldLineString", DbType = "linestring", IsNullable = true)]
|
||||||
|
public MygisGeometry TestFieldLineString { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldLong", DbType = "bigint(20)")]
|
||||||
|
public long TestFieldLong { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldMultiLineString", DbType = "multilinestring", IsNullable = true)]
|
||||||
|
public MygisGeometry TestFieldMultiLineString { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldMultiPoint", DbType = "multipoint", IsNullable = true)]
|
||||||
|
public MygisGeometry TestFieldMultiPoint { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldMultiPolygon", DbType = "multipolygon", IsNullable = true)]
|
||||||
|
public MygisGeometry TestFieldMultiPolygon { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldPoint", DbType = "point", IsNullable = true)]
|
||||||
|
public MygisGeometry TestFieldPoint { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldPolygon", DbType = "polygon", IsNullable = true)]
|
||||||
|
public MygisGeometry TestFieldPolygon { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldSByte", DbType = "tinyint(3)")]
|
||||||
|
public sbyte TestFieldSByte { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldSByteNullable", DbType = "tinyint(3)", IsNullable = true)]
|
||||||
|
public sbyte? TestFieldSByteNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldShort", DbType = "smallint(6)")]
|
||||||
|
public short TestFieldShort { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldShortNullable", DbType = "smallint(6)", IsNullable = true)]
|
||||||
|
public short? TestFieldShortNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldString", DbType = "varchar(255)", IsNullable = true)]
|
||||||
|
public string TestFieldString { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldTimeSpan", DbType = "time")]
|
||||||
|
public TimeSpan TestFieldTimeSpan { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldTimeSpanNullable", DbType = "time", IsNullable = true)]
|
||||||
|
public TimeSpan? TestFieldTimeSpanNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldUInt", DbType = "int(10) unsigned")]
|
||||||
|
public uint TestFieldUInt { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldUIntNullable", DbType = "int(10) unsigned", IsNullable = true)]
|
||||||
|
public uint? TestFieldUIntNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldULong", DbType = "bigint(20) unsigned")]
|
||||||
|
public ulong TestFieldULong { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldULongNullable", DbType = "bigint(20) unsigned", IsNullable = true)]
|
||||||
|
public ulong? TestFieldULongNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldUShort", DbType = "smallint(5) unsigned")]
|
||||||
|
public ushort TestFieldUShort { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFieldUShortNullable", DbType = "smallint(5) unsigned", IsNullable = true)]
|
||||||
|
public ushort? TestFieldUShortNullable { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[JsonProperty, Column(Name = "testFielLongNullable", DbType = "bigint(20)", IsNullable = true)]
|
||||||
|
public long? TestFielLongNullable { get; set; }
|
||||||
|
|
||||||
|
internal static IFreeSql mysql => null;
|
||||||
|
public static FreeSql.ISelect<Tb_alltype> Select => mysql.Select<Tb_alltype>();
|
||||||
|
|
||||||
|
public static int ItemCacheTimeout = 180;
|
||||||
|
public static Tb_alltype GetItem(int Id) => Select.Where(a => a.Id == Id).Caching(ItemCacheTimeout, string.Concat("test:tb_alltype:", Id)).ToOne();
|
||||||
|
|
||||||
|
public static long Delete(int Id) {
|
||||||
|
var affrows = mysql.Delete<Tb_alltype>().Where(a => a.Id == Id).ExecuteAffrows();
|
||||||
|
if (ItemCacheTimeout > 0) RemoveCache(new Tb_alltype { Id = Id });
|
||||||
|
return affrows;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void RemoveCache(Tb_alltype item) => RemoveCache(item == null ? null : new[] { item });
|
||||||
|
internal static void RemoveCache(IEnumerable<Tb_alltype> items) {
|
||||||
|
if (ItemCacheTimeout <= 0 || items == null || items.Any() == false) return;
|
||||||
|
var keys = new string[items.Count() * 1];
|
||||||
|
var keysIdx = 0;
|
||||||
|
foreach (var item in items) {
|
||||||
|
keys[keysIdx++] = string.Concat("test:tb_alltype:", item.Id);
|
||||||
|
}
|
||||||
|
if (mysql.Ado.TransactionCurrentThread != null) mysql.Ado.TransactionPreRemoveCache(keys);
|
||||||
|
else mysql.Cache.Remove(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 保存或添加,如果主键有值则尝试 Update,如果影响的行为 0 则尝试 Insert
|
||||||
|
/// </summary>
|
||||||
|
public void Save() {
|
||||||
|
if (this.Id != default(int)) {
|
||||||
|
var affrows = mysql.Update<Tb_alltype>().Where(a => a.Id == Id).ExecuteAffrows();
|
||||||
|
if (affrows > 0) return;
|
||||||
|
}
|
||||||
|
this.Id = (int)mysql.Insert<Tb_alltype>().AppendData(this).ExecuteIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Tb_alltypeTESTFIELDENUM1 {
|
||||||
|
E1 = 1, E2, E3, E5
|
||||||
|
}
|
||||||
|
public enum Tb_alltypeTESTFIELDENUM1NULLABLE {
|
||||||
|
E1 = 1, E2, E3, E5
|
||||||
|
}
|
||||||
|
[Flags]
|
||||||
|
public enum Tb_alltypeTESTFIELDENUM2 : long {
|
||||||
|
F1 = 1, F2 = 2, F3 = 4
|
||||||
|
}
|
||||||
|
[Flags]
|
||||||
|
public enum Tb_alltypeTESTFIELDENUM2NULLABLE : long {
|
||||||
|
F1 = 1, F2 = 2, F3 = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Table(Name = "tb_alltype")]
|
||||||
|
class TableAllType {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public bool testFieldBool { get; set; }
|
||||||
|
public sbyte testFieldSByte { get; set; }
|
||||||
|
public short testFieldShort { get; set; }
|
||||||
|
public int testFieldInt { get; set; }
|
||||||
|
public long testFieldLong { get; set; }
|
||||||
|
public byte testFieldByte { get; set; }
|
||||||
|
public ushort testFieldUShort { get; set; }
|
||||||
|
public uint testFieldUInt { get; set; }
|
||||||
|
public ulong testFieldULong { get; set; }
|
||||||
|
public double testFieldDouble { get; set; }
|
||||||
|
public float testFieldFloat { get; set; }
|
||||||
|
public decimal testFieldDecimal { get; set; }
|
||||||
|
public TimeSpan testFieldTimeSpan { get; set; }
|
||||||
|
public DateTime testFieldDateTime { get; set; }
|
||||||
|
public byte[] testFieldBytes { get; set; }
|
||||||
|
public string testFieldString { get; set; }
|
||||||
|
public Guid testFieldGuid { get; set; }
|
||||||
|
|
||||||
|
public bool? testFieldBoolNullable { get; set; }
|
||||||
|
public sbyte? testFieldSByteNullable { get; set; }
|
||||||
|
public short? testFieldShortNullable { get; set; }
|
||||||
|
public int? testFieldIntNullable { get; set; }
|
||||||
|
public long? testFielLongNullable { get; set; }
|
||||||
|
public byte? testFieldByteNullable { get; set; }
|
||||||
|
public ushort? testFieldUShortNullable { get; set; }
|
||||||
|
public uint? testFieldUIntNullable { get; set; }
|
||||||
|
public ulong? testFieldULongNullable { get; set; }
|
||||||
|
public double? testFieldDoubleNullable { get; set; }
|
||||||
|
public float? testFieldFloatNullable { get; set; }
|
||||||
|
public decimal? testFieldDecimalNullable { get; set; }
|
||||||
|
public TimeSpan? testFieldTimeSpanNullable { get; set; }
|
||||||
|
public DateTime? testFieldDateTimeNullable { get; set; }
|
||||||
|
public Guid? testFieldGuidNullable { get; set; }
|
||||||
|
|
||||||
|
public MygisPoint testFieldPoint { get; set; }
|
||||||
|
public MygisLineString testFieldLineString { get; set; }
|
||||||
|
public MygisPolygon testFieldPolygon { get; set; }
|
||||||
|
public MygisMultiPoint testFieldMultiPoint { get; set; }
|
||||||
|
public MygisMultiLineString testFieldMultiLineString { get; set; }
|
||||||
|
public MygisMultiPolygon testFieldMultiPolygon { get; set; }
|
||||||
|
|
||||||
|
public TableAllTypeEnumType1 testFieldEnum1 { get; set; }
|
||||||
|
public TableAllTypeEnumType1? testFieldEnum1Nullable { get; set; }
|
||||||
|
public TableAllTypeEnumType2 testFieldEnum2 { get; set; }
|
||||||
|
public TableAllTypeEnumType2? testFieldEnum2Nullable { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TableAllTypeEnumType1 { e1, e2, e3, e5 }
|
||||||
|
[Flags] public enum TableAllTypeEnumType2 { f1, f2, f3 }
|
||||||
|
}
|
||||||
|
}
|
21
FreeSql.Tests/MySql/MySqlDbFirstTest.cs
Normal file
21
FreeSql.Tests/MySql/MySqlDbFirstTest.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.MySql {
|
||||||
|
public class MySqlDbFirstTest {
|
||||||
|
[Fact]
|
||||||
|
public void GetDatabases() {
|
||||||
|
|
||||||
|
var t1 = g.mysql.DbFirst.GetDatabases();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetTablesByDatabase() {
|
||||||
|
|
||||||
|
var t2 = g.mysql.DbFirst.GetTablesByDatabase(g.mysql.DbFirst.GetDatabases()[0]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
82
FreeSql.Tests/MySql/MySqlExpressionTest.cs
Normal file
82
FreeSql.Tests/MySql/MySqlExpressionTest.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests.MySql {
|
||||||
|
public class MySqlExpressionTest {
|
||||||
|
|
||||||
|
ISelect<Topic> select => g.mysql.Select<Topic>();
|
||||||
|
|
||||||
|
[Table(Name = "tb_topic")]
|
||||||
|
class Topic {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int Clicks { get; set; }
|
||||||
|
public int TestTypeInfoGuid { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
class TestTypeInfo {
|
||||||
|
public int Guid { get; set; }
|
||||||
|
public int ParentId { get; set; }
|
||||||
|
public TestTypeParentInfo Parent { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
class TestTypeParentInfo {
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public List<TestTypeInfo> Types { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void StartsWith() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void EndsWith() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Contains() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ToLower() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ToUpper() {
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Substring() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Length() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void IndexOf() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void PadLeft() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void PadRight() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Trim() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void TrimStart() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void TrimEnd() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Replace() {
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void CompareTo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
150
FreeSql.Tests/UnitTest1.cs
Normal file
150
FreeSql.Tests/UnitTest1.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using FreeSql;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace FreeSql.Tests {
|
||||||
|
public class UnitTest1 {
|
||||||
|
|
||||||
|
ISelect<TestInfo> select => g.mysql.Select<TestInfo>();
|
||||||
|
[Fact]
|
||||||
|
public void Test1() {
|
||||||
|
|
||||||
|
var t1 = g.mysql.Select<TestInfo>().Where("").Where(a => a.Id > 0).Skip(100).Limit(200).ToSql();
|
||||||
|
var t2 = g.mysql.Select<TestInfo>().As("b").Where("").Where(a => a.Id > 0).Skip(100).Limit(200).ToSql();
|
||||||
|
|
||||||
|
|
||||||
|
var sql1 = select.LeftJoin(a => a.Type.Guid == a.TypeGuid).ToSql();
|
||||||
|
var sql2 = select.LeftJoin<TestTypeInfo>((a, b) => a.TypeGuid == b.Guid && b.Name == "111").ToSql();
|
||||||
|
var sql3 = select.LeftJoin("TestTypeInfo b on b.Guid = a.TypeGuid").ToSql();
|
||||||
|
|
||||||
|
//g.mysql.Select<TestInfo, TestTypeInfo, TestTypeParentInfo>().Join((a, b, c) => new Model.JoinResult3(
|
||||||
|
// Model.JoinType.LeftJoin, a.TypeGuid == b.Guid,
|
||||||
|
// Model.JoinType.InnerJoin, c.Id == b.ParentId && c.Name == "xxx")
|
||||||
|
//);
|
||||||
|
|
||||||
|
//var sql4 = select.From<TestTypeInfo, TestTypeParentInfo>((a, b, c) => new SelectFrom()
|
||||||
|
// .InnerJoin(a.TypeGuid == b.Guid)
|
||||||
|
// .LeftJoin(c.Id == b.ParentId)
|
||||||
|
// .Where(b.Name == "xxx"))
|
||||||
|
//.Where(a => a.Id == 1).ToSql();
|
||||||
|
|
||||||
|
var sql4 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.InnerJoin(a => a.TypeGuid == b.Guid)
|
||||||
|
.LeftJoin(a => c.Id == b.ParentId)
|
||||||
|
.Where(a => b.Name == "xxx"));
|
||||||
|
//.Where(a => a.Id == 1).ToSql();
|
||||||
|
|
||||||
|
|
||||||
|
var list111 = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||||
|
.InnerJoin(a => a.TypeGuid == b.Guid)
|
||||||
|
.LeftJoin(a => c.Id == b.ParentId)
|
||||||
|
.Where(a => b.Name != "xxx")).ToList((a, b, c) => new {
|
||||||
|
a.Id,
|
||||||
|
a.Title,
|
||||||
|
a.Type,
|
||||||
|
ccc = new { a.Id, a.Title },
|
||||||
|
tp = a.Type,
|
||||||
|
tp2 = new {
|
||||||
|
a.Id,
|
||||||
|
tp2 = a.Type.Name
|
||||||
|
},
|
||||||
|
tp3 = new {
|
||||||
|
a.Id,
|
||||||
|
tp33 = new {
|
||||||
|
a.Id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var ttt122 = g.mysql.Select<TestTypeParentInfo>().Where(a => a.Id > 0).ToSql();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var sql5 = g.mysql.Select<TestInfo>().From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s).Where((a, b, c) => a.Id == b.ParentId).ToSql();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//((JoinType.LeftJoin, a.TypeGuid == b.Guid), (JoinType.InnerJoin, b.ParentId == c.Id)
|
||||||
|
|
||||||
|
var t11112 = g.mysql.Select<TestInfo>().ToList(a => new {
|
||||||
|
a.Id, a.Title, a.Type,
|
||||||
|
ccc = new { a.Id, a.Title },
|
||||||
|
tp = a.Type,
|
||||||
|
tp2 = new {
|
||||||
|
a.Id, tp2 = a.Type.Name
|
||||||
|
},
|
||||||
|
tp3 = new {
|
||||||
|
a.Id,
|
||||||
|
tp33 = new {
|
||||||
|
a.Id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var t100 = g.mysql.Select<TestInfo>().Where("").Where(a => a.Id > 0).Skip(100).Limit(200).Caching(50).ToList();
|
||||||
|
var t101 = g.mysql.Select<TestInfo>().As("b").Where("").Where(a => a.Id > 0).Skip(100).Limit(200).Caching(50).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
var t1111 = g.mysql.Select<TestInfo>().ToList(a => new { a.Id, a.Title, a.Type });
|
||||||
|
|
||||||
|
var t2222 = g.mysql.Select<TestInfo>().ToList(a => new { a.Id, a.Title, a.Type.Name });
|
||||||
|
|
||||||
|
var t3 = g.mysql.Insert<TestInfo>(new[] { new TestInfo { }, new TestInfo { } }).IgnoreColumns(a => a.Title).ToSql();
|
||||||
|
var t4 = g.mysql.Insert<TestInfo>(new[] { new TestInfo { }, new TestInfo { } }).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql();
|
||||||
|
var t5 = g.mysql.Insert<TestInfo>(new[] { new TestInfo { }, new TestInfo { } }).IgnoreColumns(a => new { a.Title, a.TypeGuid, a.CreateTime }).ToSql();
|
||||||
|
var t6 = g.mysql.Insert<TestInfo>(new[] { new TestInfo { }, new TestInfo { } }).InsertColumns(a => new { a.Title }).ToSql();
|
||||||
|
|
||||||
|
var t7 = g.mysql.Update<TestInfo>().ToSql();
|
||||||
|
var t8 = g.mysql.Update<TestInfo>().Where(new TestInfo { }).ToSql();
|
||||||
|
var t9 = g.mysql.Update<TestInfo>().Where(new[] { new TestInfo { Id = 1 }, new TestInfo { Id = 2 } }).ToSql();
|
||||||
|
var t10 = g.mysql.Update<TestInfo>().Where(new[] { new TestInfo { Id = 1 }, new TestInfo { Id = 2 } }).Where(a => a.Title == "111").ToSql();
|
||||||
|
var t11 = g.mysql.Update<TestInfo>().SetSource(new[] { new TestInfo { Id = 1, Title = "111" }, new TestInfo { Id = 2, Title = "222" } }).ToSql();
|
||||||
|
var t12 = g.mysql.Update<TestInfo>().SetSource(new[] { new TestInfo { Id = 1, Title = "111" }, new TestInfo { Id = 2, Title = "222" } }).Where(a => a.Title == "111").ToSql();
|
||||||
|
|
||||||
|
var t13 = g.mysql.Update<TestInfo>().Set(a => a.Title, "222111").ToSql();
|
||||||
|
var t14 = g.mysql.Update<TestInfo>().Set(a => a.Title, "222111").Where(new TestInfo { }).ToSql();
|
||||||
|
var t15 = g.mysql.Update<TestInfo>().Set(a => a.Title, "222111").Where(new[] { new TestInfo { Id = 1 }, new TestInfo { Id = 2 } }).ToSql();
|
||||||
|
var t16 = g.mysql.Update<TestInfo>().Set(a => a.Title, "222111").Where(new[] { new TestInfo { Id = 1 }, new TestInfo { Id = 2 } }).Where(a => a.Title == "111").ToSql();
|
||||||
|
var t17 = g.mysql.Update<TestInfo>().SetSource(new[] { new TestInfo { Id = 1, Title = "111" }, new TestInfo { Id = 2, Title = "222" } }).Set(a => a.Title, "222111").ToSql();
|
||||||
|
var t18 = g.mysql.Update<TestInfo>().SetSource(new[] { new TestInfo { Id = 1, Title = "111" }, new TestInfo { Id = 2, Title = "222" } }).Set(a => a.Title, "222111").Where(a => a.Title == "111").ToSql();
|
||||||
|
|
||||||
|
var t19 = g.mysql.Update<TestInfo>().Set(a => a.TypeGuid + 222111).ToSql();
|
||||||
|
var t20 = g.mysql.Update<TestInfo>().Set(a => a.TypeGuid + 222111).Where(new TestInfo { }).ToSql();
|
||||||
|
var t21 = g.mysql.Update<TestInfo>().Set(a => a.TypeGuid + 222111).Where(new[] { new TestInfo { Id = 1 }, new TestInfo { Id = 2 } }).ToSql();
|
||||||
|
var t22 = g.mysql.Update<TestInfo>().Set(a => a.TypeGuid + 222111).Where(new[] { new TestInfo { Id = 1 }, new TestInfo { Id = 2 } }).Where(a => a.Title == "111").ToSql();
|
||||||
|
var t23 = g.mysql.Update<TestInfo>().SetSource(new[] { new TestInfo { Id = 1, Title = "111" }, new TestInfo { Id = 2, Title = "222" } }).Set(a => a.TypeGuid + 222111).ToSql();
|
||||||
|
var t24 = g.mysql.Update<TestInfo>().SetSource(new[] { new TestInfo { Id = 1, Title = "111" }, new TestInfo { Id = 2, Title = "222" } }).Set(a => a.TypeGuid + 222111).Where(a => a.Title == "111").ToSql();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table(Name = "xxx", SelectFilter = " a.id > 0")]
|
||||||
|
class TestInfo {
|
||||||
|
[Column(IsIdentity = true, IsPrimary = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int TypeGuid { get; set; }
|
||||||
|
public TestTypeInfo Type { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestTypeInfo {
|
||||||
|
public int Guid { get; set; }
|
||||||
|
public int ParentId { get; set; }
|
||||||
|
public TestTypeParentInfo Parent { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestTypeParentInfo {
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public List<TestTypeInfo> Types { get; set; }
|
||||||
|
}
|
||||||
|
}
|
15
FreeSql.Tests/g.cs
Normal file
15
FreeSql.Tests/g.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
|
||||||
|
public class g {
|
||||||
|
|
||||||
|
public static IFreeSql mysql = new FreeSql.FreeSqlBuilder()
|
||||||
|
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
public static IFreeSql sqlserver = new FreeSql.FreeSqlBuilder()
|
||||||
|
.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=shop;Pooling=true;Max Pool Size=10")
|
||||||
|
.Build();
|
||||||
|
}
|
76
FreeSql.sln
Normal file
76
FreeSql.sln
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.26124.0
|
||||||
|
MinimumVisualStudioVersion = 15.0.26124.0
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql", "FreeSql\FreeSql.csproj", "{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Tests", "FreeSql.Tests\FreeSql.Tests.csproj", "{AA88EB04-4788-4180-AE68-7FA5ED17D98C}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{C6A74E2A-6660-473D-8852-B1D8348DB4E9}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
Docs\codefirst.md = Docs\codefirst.md
|
||||||
|
Docs\dbfirst.md = Docs\dbfirst.md
|
||||||
|
Docs\delete.md = Docs\delete.md
|
||||||
|
Docs\insert.md = Docs\insert.md
|
||||||
|
readme.md = readme.md
|
||||||
|
Docs\select.md = Docs\select.md
|
||||||
|
Docs\update.md = Docs\update.md
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xxx", "..\..\新建文件夹 (9)\xxx.csproj", "{6DC39740-0B26-4029-AB75-D436A7F666A2}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{AF9C50EC-6EB6-494B-9B3B-7EDBA6FD0EBB}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{AA88EB04-4788-4180-AE68-7FA5ED17D98C}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{6DC39740-0B26-4029-AB75-D436A7F666A2}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
32
FreeSql/DataAnnotations/ColumnAttribute.cs
Normal file
32
FreeSql/DataAnnotations/ColumnAttribute.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FreeSql.DataAnnotations {
|
||||||
|
public class ColumnAttribute : Attribute {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库列名
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 指定数据库旧的列名,修改实体属性命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库字段;否则将视为【新增字段】
|
||||||
|
/// </summary>
|
||||||
|
public string OldName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库类型,如: varchar(255)
|
||||||
|
/// </summary>
|
||||||
|
public string DbType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主键
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPrimary { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 自增标识
|
||||||
|
/// </summary>
|
||||||
|
public bool IsIdentity { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否可DBNull
|
||||||
|
/// </summary>
|
||||||
|
public bool IsNullable { get; set; }
|
||||||
|
}
|
||||||
|
}
|
19
FreeSql/DataAnnotations/TableAttribute.cs
Normal file
19
FreeSql/DataAnnotations/TableAttribute.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FreeSql.DataAnnotations {
|
||||||
|
public class TableAttribute : Attribute {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库表名
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 指定数据库旧的表名,修改实体命名时,同时设置此参数为修改之前的值,CodeFirst才可以正确修改数据库表;否则将视为【创建新表】
|
||||||
|
/// </summary>
|
||||||
|
public string OldName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 查询过滤SQL,实现类似 a.IsDeleted = 1 功能
|
||||||
|
/// </summary>
|
||||||
|
public string SelectFilter { get; set; }
|
||||||
|
}
|
||||||
|
}
|
52
FreeSql/DatabaseModel/DBColumnInfo.cs
Normal file
52
FreeSql/DatabaseModel/DBColumnInfo.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.DatabaseModel {
|
||||||
|
public class DbColumnInfo {
|
||||||
|
/// <summary>
|
||||||
|
/// 所属表
|
||||||
|
/// </summary>
|
||||||
|
public DbTableInfo Table { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 列名
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 映射到 C# 类型
|
||||||
|
/// </summary>
|
||||||
|
public Type CsType { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库枚举类型int值
|
||||||
|
/// </summary>
|
||||||
|
public int DbType { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库类型,字符串,varchar
|
||||||
|
/// </summary>
|
||||||
|
public string DbTypeText { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库类型,字符串,varchar(255)
|
||||||
|
/// </summary>
|
||||||
|
public string DbTypeTextFull { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 最大长度
|
||||||
|
/// </summary>
|
||||||
|
public int MaxLength { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 主键
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPrimary { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 自增标识
|
||||||
|
/// </summary>
|
||||||
|
public bool IsIdentity { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否可DBNull
|
||||||
|
/// </summary>
|
||||||
|
public bool IsNullable { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 备注
|
||||||
|
/// </summary>
|
||||||
|
public string Coment { get; internal set; }
|
||||||
|
}
|
||||||
|
}
|
52
FreeSql/DatabaseModel/DBTableInfo.cs
Normal file
52
FreeSql/DatabaseModel/DBTableInfo.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.DatabaseModel {
|
||||||
|
public class DbTableInfo {
|
||||||
|
/// <summary>
|
||||||
|
/// 唯一标识
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// SqlServer下是Owner、PostgreSQL下是Schema、MySql下是数据库名
|
||||||
|
/// </summary>
|
||||||
|
public string Schema { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 表名
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; internal set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 表/视图
|
||||||
|
/// </summary>
|
||||||
|
public DbTableType Type { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 列
|
||||||
|
/// </summary>
|
||||||
|
public List<DbColumnInfo> Columns { get; internal set; } = new List<DbColumnInfo>();
|
||||||
|
/// <summary>
|
||||||
|
/// 自增列
|
||||||
|
/// </summary>
|
||||||
|
public List<DbColumnInfo> Identitys { get; internal set; } = new List<DbColumnInfo>();
|
||||||
|
/// <summary>
|
||||||
|
/// 主键/组合
|
||||||
|
/// </summary>
|
||||||
|
public List<DbColumnInfo> Primarys { get; internal set; } = new List<DbColumnInfo>();
|
||||||
|
/// <summary>
|
||||||
|
/// 唯一键/组合
|
||||||
|
/// </summary>
|
||||||
|
public List<List<DbColumnInfo>> Uniques { get; internal set; } = new List<List<DbColumnInfo>>();
|
||||||
|
/// <summary>
|
||||||
|
/// 索引/组合
|
||||||
|
/// </summary>
|
||||||
|
public List<List<DbColumnInfo>> Indexes { get; internal set; } = new List<List<DbColumnInfo>>();
|
||||||
|
/// <summary>
|
||||||
|
/// 外键
|
||||||
|
/// </summary>
|
||||||
|
public List<DbForeignInfo> Foreigns { get; internal set; } = new List<DbForeignInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DbTableType {
|
||||||
|
TABLE, VIEW, StoreProcedure
|
||||||
|
}
|
||||||
|
}
|
13
FreeSql/DatabaseModel/DbForeignInfo.cs
Normal file
13
FreeSql/DatabaseModel/DbForeignInfo.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.DatabaseModel {
|
||||||
|
public class DbForeignInfo {
|
||||||
|
public DbTableInfo Table { get; internal set; }
|
||||||
|
public List<DbColumnInfo> Columns { get; internal set; } = new List<DbColumnInfo>();
|
||||||
|
public DbTableInfo ReferencedTable { get; internal set; }
|
||||||
|
public List<DbColumnInfo> ReferencedColumns { get; internal set; } = new List<DbColumnInfo>();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
39
FreeSql/Extensions/NpgsqlTypesExtensions.cs
Normal file
39
FreeSql/Extensions/NpgsqlTypesExtensions.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using NpgsqlTypes;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace NpgsqlTypes {
|
||||||
|
public static class FreeSqlExtensions {
|
||||||
|
|
||||||
|
public static string To1010(this BitArray ba) {
|
||||||
|
char[] ret = new char[ba.Length];
|
||||||
|
for (int a = 0; a < ba.Length; a++) ret[a] = ba[a] ? '1' : '0';
|
||||||
|
return new string(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将 1010101010 这样的二进制字符串转换成 BitArray
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="_1010">1010101010</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static BitArray ToBitArray(this string _1010Str) {
|
||||||
|
if (_1010Str == null) return null;
|
||||||
|
BitArray ret = new BitArray(_1010Str.Length);
|
||||||
|
for (int a = 0; a < _1010Str.Length; a++) ret[a] = _1010Str[a] == '1';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NpgsqlRange<T> ToNpgsqlRange<T>(this string that) {
|
||||||
|
var s = that;
|
||||||
|
if (string.IsNullOrEmpty(s) || s == "empty") return NpgsqlRange<T>.Empty;
|
||||||
|
string s1 = s.Trim('(', ')', '[', ']');
|
||||||
|
string[] ss = s1.Split(new char[] { ',' }, 2);
|
||||||
|
if (ss.Length != 2) return NpgsqlRange<T>.Empty;
|
||||||
|
T t1 = default(T);
|
||||||
|
T t2 = default(T);
|
||||||
|
if (!string.IsNullOrEmpty(ss[0])) t1 = (T)Convert.ChangeType(ss[0], typeof(T));
|
||||||
|
if (!string.IsNullOrEmpty(ss[1])) t2 = (T)Convert.ChangeType(ss[1], typeof(T));
|
||||||
|
return new NpgsqlRange<T>(t1, s[0] == '[', s[0] == '(', t2, s[s.Length - 1] == ']', s[s.Length - 1] == ')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
FreeSql/Extensions/StringExtensions.cs
Normal file
31
FreeSql/Extensions/StringExtensions.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
public static class StringExtensions {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="that"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string FormatMySql(this string that, params object[] args) => _mysqlAdo.Addslashes(that, args);
|
||||||
|
static FreeSql.MySql.MySqlAdo _mysqlAdo = new FreeSql.MySql.MySqlAdo();
|
||||||
|
/// <summary>
|
||||||
|
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="that"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string FormatSqlServer(this string that, params object[] args) => _sqlserverAdo.Addslashes(that, args);
|
||||||
|
static FreeSql.SqlServer.SqlServerAdo _sqlserverAdo = new FreeSql.SqlServer.SqlServerAdo();
|
||||||
|
/// <summary>
|
||||||
|
/// 特殊处理类似 string.Format 的使用方法,防止注入,以及 IS NULL 转换
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="that"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string FormatPostgreSQL(this string that, params object[] args) => _postgresqlAdo.Addslashes(that, args);
|
||||||
|
static FreeSql.PostgreSQL.PostgreSQLAdo _postgresqlAdo = new FreeSql.PostgreSQL.PostgreSQLAdo();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace System.Runtime.CompilerServices {
|
||||||
|
public class ExtensionAttribute : Attribute { }
|
||||||
|
}
|
21
FreeSql/FreeSql.csproj
Normal file
21
FreeSql/FreeSql.csproj
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CS-Script.Core" Version="1.0.5" />
|
||||||
|
<PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.2.0" />
|
||||||
|
<PackageReference Include="MySql.Data" Version="8.0.13" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||||
|
<PackageReference Include="Npgsql" Version="4.0.4" />
|
||||||
|
<PackageReference Include="Npgsql.LegacyPostgis" Version="4.0.4" />
|
||||||
|
<PackageReference Include="SafeObjectPool" Version="1.0.12" />
|
||||||
|
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
66
FreeSql/FreeSqlBuilder.cs
Normal file
66
FreeSql/FreeSqlBuilder.cs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public class FreeSqlBuilder {
|
||||||
|
IDistributedCache _cache;
|
||||||
|
ILogger _logger;
|
||||||
|
DataType _dataType;
|
||||||
|
string _masterConnectionString;
|
||||||
|
string[] _slaveConnectionString;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用缓存,不指定默认使用内存
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cache">缓存现实</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public FreeSqlBuilder UseCache(IDistributedCache cache) {
|
||||||
|
_cache = cache;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用日志,不指定默认输出控制台
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logger"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public FreeSqlBuilder UseLogger(ILogger logger) {
|
||||||
|
_logger = logger;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 使用连接串
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataType">数据库类型</param>
|
||||||
|
/// <param name="connectionString">数据库连接串</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public FreeSqlBuilder UseConnectionString(DataType dataType, string connectionString) {
|
||||||
|
_dataType = dataType;
|
||||||
|
_masterConnectionString = connectionString;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 使用从数据库,支持多个
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slaveConnectionString">从数据库连接串</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public FreeSqlBuilder UseSlave(params string[] slaveConnectionString) {
|
||||||
|
_slaveConnectionString = slaveConnectionString;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFreeSql Build() {
|
||||||
|
switch(_dataType) {
|
||||||
|
case DataType.MySql: return new MySql.MySqlProvider(_cache, null, _masterConnectionString, _slaveConnectionString, _logger);
|
||||||
|
case DataType.SqlServer: return new SqlServer.SqlServerProvider(_cache, null, _masterConnectionString, _slaveConnectionString, _logger);
|
||||||
|
case DataType.PostgreSQL: return new MySql.MySqlProvider(_cache, null, _masterConnectionString, _slaveConnectionString, _logger);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DataType { MySql, SqlServer, PostgreSQL }
|
||||||
|
}
|
34
FreeSql/FreeUtil.cs
Normal file
34
FreeSql/FreeUtil.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using NpgsqlTypes;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
public static class FreeUtil {
|
||||||
|
|
||||||
|
private static DateTime dt1970 = new DateTime(1970, 1, 1);
|
||||||
|
private static ThreadLocal<Random> rnd = new ThreadLocal<Random>();
|
||||||
|
private static readonly int __staticMachine = ((0x00ffffff & Environment.MachineName.GetHashCode()) +
|
||||||
|
#if NETSTANDARD1_5 || NETSTANDARD1_6
|
||||||
|
1
|
||||||
|
#else
|
||||||
|
AppDomain.CurrentDomain.Id
|
||||||
|
#endif
|
||||||
|
) & 0x00ffffff;
|
||||||
|
private static readonly int __staticPid = Process.GetCurrentProcess().Id;
|
||||||
|
private static int __staticIncrement = rnd.Value.Next();
|
||||||
|
/// <summary>
|
||||||
|
/// 生成类似Mongodb的ObjectId有序、不重复Guid
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Guid NewMongodbId() {
|
||||||
|
var now = DateTime.Now;
|
||||||
|
var uninxtime = (int)now.Subtract(dt1970).TotalSeconds;
|
||||||
|
int increment = Interlocked.Increment(ref __staticIncrement) & 0x00ffffff;
|
||||||
|
var rand = rnd.Value.Next(0, int.MaxValue);
|
||||||
|
var guid = $"{uninxtime.ToString("x8").PadLeft(8, '0')}{__staticMachine.ToString("x8").PadLeft(8, '0').Substring(2, 6)}{__staticPid.ToString("x8").PadLeft(8, '0').Substring(6, 2)}{increment.ToString("x8").PadLeft(8, '0')}{rand.ToString("x8").PadLeft(8, '0')}";
|
||||||
|
return Guid.Parse(guid);
|
||||||
|
}
|
||||||
|
}
|
640
FreeSql/Generator/TemplateEngin.cs
Normal file
640
FreeSql/Generator/TemplateEngin.cs
Normal file
@ -0,0 +1,640 @@
|
|||||||
|
using Microsoft.CSharp;
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace FreeSql.Generator {
|
||||||
|
public class TemplateEngin : IDisposable {
|
||||||
|
public interface ITemplateOutput {
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tOuTpUt">返回内容</param>
|
||||||
|
/// <param name="oPtIoNs">渲染对象</param>
|
||||||
|
/// <param name="rEfErErFiLeNaMe">当前文件路径</param>
|
||||||
|
/// <param name="tEmPlAtEsEnDeR"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TemplateReturnInfo OuTpUt(StringBuilder tOuTpUt, IDictionary oPtIoNs, string rEfErErFiLeNaMe, TemplateEngin tEmPlAtEsEnDeR);
|
||||||
|
}
|
||||||
|
public class TemplateReturnInfo {
|
||||||
|
public Dictionary<string, int[]> Blocks;
|
||||||
|
public StringBuilder Sb;
|
||||||
|
}
|
||||||
|
public delegate bool TemplateIf(object exp);
|
||||||
|
public delegate void TemplatePrint(params object[] parms);
|
||||||
|
|
||||||
|
private static int _view = 0;
|
||||||
|
private static Regex _reg = new Regex(@"\{(\$TEMPLATE__CODE|\/\$TEMPLATE__CODE|import\s+|module\s+|extends\s+|block\s+|include\s+|for\s+|if\s+|#|\/for|elseif|else|\/if|\/block|\/module)([^\}]*)\}", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_forin = new Regex(@"^([\w_]+)\s*,?\s*([\w_]+)?\s+in\s+(.+)", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_foron = new Regex(@"^([\w_]+)\s*,?\s*([\w_]+)?,?\s*([\w_]+)?\s+on\s+(.+)", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_forab = new Regex(@"^([\w_]+)\s+([^,]+)\s*,\s*(.+)", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_miss = new Regex(@"\{\/?miss\}", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_code = new Regex(@"(\{%|%\})", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_syntax = new Regex(@"<(\w+)\s+@(if|for|else)\s*=""([^""]*)""", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_htmltag = new Regex(@"<\/?\w+[^>]*>", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_blank = new Regex(@"\s+", RegexOptions.Compiled);
|
||||||
|
private static Regex _reg_complie_undefined = new Regex(@"(当前上下文中不存在名称)?“(\w+)”", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private Dictionary<string, ITemplateOutput> _cache = new Dictionary<string, ITemplateOutput>();
|
||||||
|
private object _cache_lock = new object();
|
||||||
|
private string _viewDir;
|
||||||
|
private string[] _usings;
|
||||||
|
private FileSystemWatcher _fsw = new FileSystemWatcher();
|
||||||
|
|
||||||
|
public TemplateEngin(string viewDir, params string[] usings) {
|
||||||
|
_viewDir = Utils.TranslateUrl(viewDir);
|
||||||
|
_usings = usings;
|
||||||
|
_fsw = new FileSystemWatcher(_viewDir);
|
||||||
|
_fsw.IncludeSubdirectories = true;
|
||||||
|
_fsw.Changed += ViewDirChange;
|
||||||
|
_fsw.Renamed += ViewDirChange;
|
||||||
|
_fsw.EnableRaisingEvents = true;
|
||||||
|
}
|
||||||
|
public void Dispose() {
|
||||||
|
_fsw.Dispose();
|
||||||
|
}
|
||||||
|
void ViewDirChange(object sender, FileSystemEventArgs e) {
|
||||||
|
string filename = e.FullPath.ToLower();
|
||||||
|
lock (_cache_lock) {
|
||||||
|
_cache.Remove(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public TemplateReturnInfo RenderFile2(StringBuilder sb, IDictionary options, string filename, string refererFilename) {
|
||||||
|
if (filename[0] == '/' || string.IsNullOrEmpty(refererFilename)) refererFilename = _viewDir;
|
||||||
|
//else refererFilename = Path.GetDirectoryName(refererFilename);
|
||||||
|
string filename2 = Utils.TranslateUrl(filename, refererFilename);
|
||||||
|
ITemplateOutput tpl;
|
||||||
|
if (_cache.TryGetValue(filename2, out tpl) == false) {
|
||||||
|
string tplcode = File.Exists(filename2) == false ? string.Concat("文件不存在 ", filename) : Utils.ReadTextFile(filename2);
|
||||||
|
tpl = Parser(tplcode, _usings, options);
|
||||||
|
lock (_cache_lock) {
|
||||||
|
if (_cache.ContainsKey(filename2) == false) {
|
||||||
|
_cache.Add(filename2, tpl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return tpl.OuTpUt(sb, options, filename2, this);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
TemplateReturnInfo ret = sb == null ?
|
||||||
|
new TemplateReturnInfo { Sb = new StringBuilder(), Blocks = new Dictionary<string, int[]>() } :
|
||||||
|
new TemplateReturnInfo { Sb = sb, Blocks = new Dictionary<string, int[]>() };
|
||||||
|
ret.Sb.Append(refererFilename);
|
||||||
|
ret.Sb.Append(" -> ");
|
||||||
|
ret.Sb.Append(filename);
|
||||||
|
ret.Sb.Append("\r\n");
|
||||||
|
ret.Sb.Append(ex.Message);
|
||||||
|
ret.Sb.Append("\r\n");
|
||||||
|
ret.Sb.Append(ex.StackTrace);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string RenderFile(string filename, IDictionary options) {
|
||||||
|
TemplateReturnInfo ret = this.RenderFile2(null, options, filename, null);
|
||||||
|
return ret.Sb.ToString();
|
||||||
|
}
|
||||||
|
private static ITemplateOutput Parser(string tplcode, string[] usings, IDictionary options) {
|
||||||
|
int view = Interlocked.Increment(ref _view);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
IDictionary options_copy = new Hashtable();
|
||||||
|
foreach (DictionaryEntry options_de in options) options_copy[options_de.Key] = options_de.Value;
|
||||||
|
sb.AppendFormat(@"
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;{1}
|
||||||
|
|
||||||
|
//namespace TplDynamicCodeGenerate {{
|
||||||
|
public class TplDynamicCodeGenerate_view{0} : FreeSql.Generator.TemplateEngin.ITemplateOutput {{
|
||||||
|
public FreeSql.Generator.TemplateEngin.TemplateReturnInfo OuTpUt(StringBuilder tOuTpUt, IDictionary oPtIoNs, string rEfErErFiLeNaMe, FreeSql.Generator.TemplateEngin tEmPlAtEsEnDeR) {{
|
||||||
|
FreeSql.Generator.TemplateEngin.TemplateReturnInfo rTn = tOuTpUt == null ?
|
||||||
|
new FreeSql.Generator.TemplateEngin.TemplateReturnInfo {{ Sb = (tOuTpUt = new StringBuilder()), Blocks = new Dictionary<string, int[]>() }} :
|
||||||
|
new FreeSql.Generator.TemplateEngin.TemplateReturnInfo {{ Sb = tOuTpUt, Blocks = new Dictionary<string, int[]>() }};
|
||||||
|
Dictionary<string, int[]> TPL__blocks = rTn.Blocks;
|
||||||
|
Stack<int[]> TPL__blocks_stack = new Stack<int[]>();
|
||||||
|
int[] TPL__blocks_stack_peek;
|
||||||
|
List<IDictionary> TPL__forc = new List<IDictionary>();
|
||||||
|
Func<IDictionary> pRoCeSsOpTiOnS = new Func<IDictionary>(delegate () {{
|
||||||
|
IDictionary nEwoPtIoNs = new Hashtable();
|
||||||
|
foreach (DictionaryEntry oPtIoNs_dE in oPtIoNs)
|
||||||
|
nEwoPtIoNs[oPtIoNs_dE.Key] = oPtIoNs_dE.Value;
|
||||||
|
foreach (IDictionary TPL__forc_dIc in TPL__forc)
|
||||||
|
foreach (DictionaryEntry TPL__forc_dIc_dE in TPL__forc_dIc)
|
||||||
|
nEwoPtIoNs[TPL__forc_dIc_dE.Key] = TPL__forc_dIc_dE.Value;
|
||||||
|
return nEwoPtIoNs;
|
||||||
|
}});
|
||||||
|
FreeSql.Generator.TemplateEngin.TemplateIf tPlIf = delegate(object exp) {{
|
||||||
|
if (exp is bool) return (bool)exp;
|
||||||
|
if (exp == null) return false;
|
||||||
|
if (exp is int && (int)exp == 0) return false;
|
||||||
|
if (exp is string && (string)exp == string.Empty) return false;
|
||||||
|
if (exp is long && (long)exp == 0) return false;
|
||||||
|
if (exp is short && (short)exp == 0) return false;
|
||||||
|
if (exp is byte && (byte)exp == 0) return false;
|
||||||
|
if (exp is double && (double)exp == 0) return false;
|
||||||
|
if (exp is float && (float)exp == 0) return false;
|
||||||
|
if (exp is decimal && (decimal)exp == 0) return false;
|
||||||
|
return true;
|
||||||
|
}};
|
||||||
|
FreeSql.Generator.TemplateEngin.TemplatePrint print = delegate(object[] pArMs) {{
|
||||||
|
if (pArMs == null || pArMs.Length == 0) return;
|
||||||
|
foreach (object pArMs_A in pArMs) if (pArMs_A != null) tOuTpUt.Append(pArMs_A);
|
||||||
|
}};
|
||||||
|
FreeSql.Generator.TemplateEngin.TemplatePrint Print = print;", view, usings?.Any() == true ? $"\r\nusing {string.Join(";\r\nusing ", usings)};" : "");
|
||||||
|
|
||||||
|
#region {miss}...{/miss}块内容将不被解析
|
||||||
|
string[] tmp_content_arr = _reg_miss.Split(tplcode);
|
||||||
|
if (tmp_content_arr.Length > 1) {
|
||||||
|
sb.AppendFormat(@"
|
||||||
|
string[] TPL__MISS = new string[{0}];", Math.Ceiling(1.0 * (tmp_content_arr.Length - 1) / 2));
|
||||||
|
int miss_len = -1;
|
||||||
|
for (int a = 1; a < tmp_content_arr.Length; a += 2) {
|
||||||
|
sb.Append(string.Concat(@"
|
||||||
|
TPL__MISS[", ++miss_len, @"] = """, Utils.GetConstString(tmp_content_arr[a]), @""";"));
|
||||||
|
tmp_content_arr[a] = string.Concat("{#TPL__MISS[", miss_len, "]}");
|
||||||
|
}
|
||||||
|
tplcode = string.Join("", tmp_content_arr);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region 扩展语法如 <div @if="表达式"></div>
|
||||||
|
tplcode = htmlSyntax(tplcode, 3); //<div @if="c#表达式" @for="index 1,100"></div>
|
||||||
|
//处理 {% %} 块 c#代码
|
||||||
|
tmp_content_arr = _reg_code.Split(tplcode);
|
||||||
|
if (tmp_content_arr.Length == 1) {
|
||||||
|
tplcode = Utils.GetConstString(tplcode)
|
||||||
|
.Replace("{%", "{$TEMPLATE__CODE}")
|
||||||
|
.Replace("%}", "{/$TEMPLATE__CODE}");
|
||||||
|
} else {
|
||||||
|
tmp_content_arr[0] = Utils.GetConstString(tmp_content_arr[0]);
|
||||||
|
for (int a = 1; a < tmp_content_arr.Length; a += 4) {
|
||||||
|
tmp_content_arr[a] = "{$TEMPLATE__CODE}";
|
||||||
|
tmp_content_arr[a + 2] = "{/$TEMPLATE__CODE}";
|
||||||
|
tmp_content_arr[a + 3] = Utils.GetConstString(tmp_content_arr[a + 3]);
|
||||||
|
}
|
||||||
|
tplcode = string.Join("", tmp_content_arr);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
sb.Append(@"
|
||||||
|
tOuTpUt.Append(""");
|
||||||
|
|
||||||
|
string error = null;
|
||||||
|
int tpl_tmpid = 0;
|
||||||
|
int forc_i = 0;
|
||||||
|
string extends = null;
|
||||||
|
Stack<string> codeTree = new Stack<string>();
|
||||||
|
Stack<string> forEndRepl = new Stack<string>();
|
||||||
|
sb.Append(_reg.Replace(tplcode, delegate (Match m) {
|
||||||
|
string _0 = m.Groups[0].Value;
|
||||||
|
if (!string.IsNullOrEmpty(error)) return _0;
|
||||||
|
|
||||||
|
string _1 = m.Groups[1].Value.Trim(' ', '\t');
|
||||||
|
string _2 = m.Groups[2].Value
|
||||||
|
.Replace("\\\\", "\\")
|
||||||
|
.Replace("\\\"", "\"");
|
||||||
|
_2 = Utils.ReplaceSingleQuote(_2);
|
||||||
|
|
||||||
|
switch (_1) {
|
||||||
|
#region $TEMPLATE__CODE--------------------------------------------------
|
||||||
|
case "$TEMPLATE__CODE":
|
||||||
|
codeTree.Push(_1);
|
||||||
|
return @""");
|
||||||
|
";
|
||||||
|
case "/$TEMPLATE__CODE":
|
||||||
|
string pop = codeTree.Pop();
|
||||||
|
if (pop != "$TEMPLATE__CODE") {
|
||||||
|
codeTree.Push(pop);
|
||||||
|
error = "编译出错,{% 与 %} 并没有配对";
|
||||||
|
return _0;
|
||||||
|
}
|
||||||
|
return @"
|
||||||
|
tOuTpUt.Append(""";
|
||||||
|
#endregion
|
||||||
|
case "include":
|
||||||
|
return string.Format(@""");
|
||||||
|
tEmPlAtEsEnDeR.RenderFile2(tOuTpUt, pRoCeSsOpTiOnS(), ""{0}"", rEfErErFiLeNaMe);
|
||||||
|
tOuTpUt.Append(""", _2);
|
||||||
|
case "import":
|
||||||
|
return _0;
|
||||||
|
case "module":
|
||||||
|
return _0;
|
||||||
|
case "/module":
|
||||||
|
return _0;
|
||||||
|
case "extends":
|
||||||
|
//{extends ../inc/layout.html}
|
||||||
|
if (string.IsNullOrEmpty(extends) == false) return _0;
|
||||||
|
extends = _2;
|
||||||
|
return string.Empty;
|
||||||
|
case "block":
|
||||||
|
codeTree.Push("block");
|
||||||
|
return string.Format(@""");
|
||||||
|
TPL__blocks_stack_peek = new int[] {{ tOuTpUt.Length, 0 }};
|
||||||
|
TPL__blocks_stack.Push(TPL__blocks_stack_peek);
|
||||||
|
TPL__blocks.Add(""{0}"", TPL__blocks_stack_peek);
|
||||||
|
tOuTpUt.Append(""", _2.Trim(' ', '\t'));
|
||||||
|
case "/block":
|
||||||
|
codeTreeEnd(codeTree, "block");
|
||||||
|
return @""");
|
||||||
|
TPL__blocks_stack_peek = TPL__blocks_stack.Pop();
|
||||||
|
TPL__blocks_stack_peek[1] = tOuTpUt.Length - TPL__blocks_stack_peek[0];
|
||||||
|
tOuTpUt.Append(""";
|
||||||
|
|
||||||
|
#region ##---------------------------------------------------------
|
||||||
|
case "#":
|
||||||
|
if (_2[0] == '#')
|
||||||
|
return string.Format(@""");
|
||||||
|
try {{ Print({0}); }} catch {{ }}
|
||||||
|
tOuTpUt.Append(""", _2.Substring(1));
|
||||||
|
return string.Format(@""");
|
||||||
|
Print({0});
|
||||||
|
tOuTpUt.Append(""", _2);
|
||||||
|
#endregion
|
||||||
|
#region for--------------------------------------------------------
|
||||||
|
case "for":
|
||||||
|
forc_i++;
|
||||||
|
int cur_tpl_tmpid = tpl_tmpid;
|
||||||
|
string sb_endRepl = string.Empty;
|
||||||
|
StringBuilder sbfor = new StringBuilder();
|
||||||
|
sbfor.Append(@""");");
|
||||||
|
Match mfor = _reg_forin.Match(_2);
|
||||||
|
if (mfor.Success) {
|
||||||
|
string mfor1 = mfor.Groups[1].Value.Trim(' ', '\t');
|
||||||
|
string mfor2 = mfor.Groups[2].Value.Trim(' ', '\t');
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
//new Action(delegate () {{
|
||||||
|
IDictionary TPL__tmp{0} = new Hashtable();
|
||||||
|
TPL__forc.Add(TPL__tmp{0});
|
||||||
|
var TPL__tmp{1} = {3};
|
||||||
|
var TPL__tmp{2} = {4};", ++tpl_tmpid, ++tpl_tmpid, ++tpl_tmpid, mfor.Groups[3].Value, mfor1);
|
||||||
|
sb_endRepl = string.Concat(sb_endRepl, string.Format(@"
|
||||||
|
{0} = TPL__tmp{1};", mfor1, cur_tpl_tmpid + 3));
|
||||||
|
if (options_copy.Contains(mfor1) == false) options_copy[mfor1] = null;
|
||||||
|
if (!string.IsNullOrEmpty(mfor2)) {
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
var TPL__tmp{1} = {0};
|
||||||
|
{0} = 0;", mfor2, ++tpl_tmpid);
|
||||||
|
sb_endRepl = string.Concat(sb_endRepl, string.Format(@"
|
||||||
|
{0} = TPL__tmp{1};", mfor2, tpl_tmpid));
|
||||||
|
if (options_copy.Contains(mfor2) == false) options_copy[mfor2] = null;
|
||||||
|
}
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
if (TPL__tmp{1} != null)
|
||||||
|
foreach (var TPL__tmp{0} in TPL__tmp{1}) {{", ++tpl_tmpid, cur_tpl_tmpid + 2);
|
||||||
|
if (!string.IsNullOrEmpty(mfor2))
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
TPL__tmp{1}[""{0}""] = ++ {0};", mfor2, cur_tpl_tmpid + 1);
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
TPL__tmp{1}[""{0}""] = TPL__tmp{2};
|
||||||
|
{0} = TPL__tmp{2};
|
||||||
|
tOuTpUt.Append(""", mfor1, cur_tpl_tmpid + 1, tpl_tmpid);
|
||||||
|
codeTree.Push("for");
|
||||||
|
forEndRepl.Push(sb_endRepl);
|
||||||
|
return sbfor.ToString();
|
||||||
|
}
|
||||||
|
mfor = _reg_foron.Match(_2);
|
||||||
|
if (mfor.Success) {
|
||||||
|
string mfor1 = mfor.Groups[1].Value.Trim(' ', '\t');
|
||||||
|
string mfor2 = mfor.Groups[2].Value.Trim(' ', '\t');
|
||||||
|
string mfor3 = mfor.Groups[3].Value.Trim(' ', '\t');
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
//new Action(delegate () {{
|
||||||
|
IDictionary TPL__tmp{0} = new Hashtable();
|
||||||
|
TPL__forc.Add(TPL__tmp{0});
|
||||||
|
var TPL__tmp{1} = {3};
|
||||||
|
var TPL__tmp{2} = {4};", ++tpl_tmpid, ++tpl_tmpid, ++tpl_tmpid, mfor.Groups[4].Value, mfor1);
|
||||||
|
sb_endRepl = string.Concat(sb_endRepl, string.Format(@"
|
||||||
|
{0} = TPL__tmp{1};", mfor1, cur_tpl_tmpid + 3));
|
||||||
|
if (options_copy.Contains(mfor1) == false) options_copy[mfor1] = null;
|
||||||
|
if (!string.IsNullOrEmpty(mfor2)) {
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
var TPL__tmp{1} = {0};", mfor2, ++tpl_tmpid);
|
||||||
|
sb_endRepl = string.Concat(sb_endRepl, string.Format(@"
|
||||||
|
{0} = TPL__tmp{1};", mfor2, tpl_tmpid));
|
||||||
|
if (options_copy.Contains(mfor2) == false) options_copy[mfor2] = null;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(mfor3)) {
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
var TPL__tmp{1} = {0};
|
||||||
|
{0} = 0;", mfor3, ++tpl_tmpid);
|
||||||
|
sb_endRepl = string.Concat(sb_endRepl, string.Format(@"
|
||||||
|
{0} = TPL__tmp{1};", mfor3, tpl_tmpid));
|
||||||
|
if (options_copy.Contains(mfor3) == false) options_copy[mfor3] = null;
|
||||||
|
}
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
if (TPL__tmp{2} != null)
|
||||||
|
foreach (DictionaryEntry TPL__tmp{1} in TPL__tmp{2}) {{
|
||||||
|
{0} = TPL__tmp{1}.Key;
|
||||||
|
TPL__tmp{3}[""{0}""] = {0};", mfor1, ++tpl_tmpid, cur_tpl_tmpid + 2, cur_tpl_tmpid + 1);
|
||||||
|
if (!string.IsNullOrEmpty(mfor2))
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
{0} = TPL__tmp{1}.Value;
|
||||||
|
TPL__tmp{2}[""{0}""] = {0};", mfor2, tpl_tmpid, cur_tpl_tmpid + 1);
|
||||||
|
if (!string.IsNullOrEmpty(mfor3))
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
TPL__tmp{1}[""{0}""] = ++ {0};", mfor3, cur_tpl_tmpid + 1);
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
tOuTpUt.Append(""");
|
||||||
|
codeTree.Push("for");
|
||||||
|
forEndRepl.Push(sb_endRepl);
|
||||||
|
return sbfor.ToString();
|
||||||
|
}
|
||||||
|
mfor = _reg_forab.Match(_2);
|
||||||
|
if (mfor.Success) {
|
||||||
|
string mfor1 = mfor.Groups[1].Value.Trim(' ', '\t');
|
||||||
|
sbfor.AppendFormat(@"
|
||||||
|
//new Action(delegate () {{
|
||||||
|
IDictionary TPL__tmp{0} = new Hashtable();
|
||||||
|
TPL__forc.Add(TPL__tmp{0});
|
||||||
|
var TPL__tmp{1} = {5};
|
||||||
|
{5} = {3} - 1;
|
||||||
|
if ({5} == null) {5} = 0;
|
||||||
|
var TPL__tmp{2} = {4} + 1;
|
||||||
|
while (++{5} < TPL__tmp{2}) {{
|
||||||
|
TPL__tmp{0}[""{5}""] = {5};
|
||||||
|
tOuTpUt.Append(""", ++tpl_tmpid, ++tpl_tmpid, ++tpl_tmpid, mfor.Groups[2].Value, mfor.Groups[3].Value, mfor1);
|
||||||
|
sb_endRepl = string.Concat(sb_endRepl, string.Format(@"
|
||||||
|
{0} = TPL__tmp{1};", mfor1, cur_tpl_tmpid + 1));
|
||||||
|
if (options_copy.Contains(mfor1) == false) options_copy[mfor1] = null;
|
||||||
|
codeTree.Push("for");
|
||||||
|
forEndRepl.Push(sb_endRepl);
|
||||||
|
return sbfor.ToString();
|
||||||
|
}
|
||||||
|
return _0;
|
||||||
|
case "/for":
|
||||||
|
if (--forc_i < 0) return _0;
|
||||||
|
codeTreeEnd(codeTree, "for");
|
||||||
|
return string.Format(@""");
|
||||||
|
}}{0}
|
||||||
|
TPL__forc.RemoveAt(TPL__forc.Count - 1);
|
||||||
|
//}})();
|
||||||
|
tOuTpUt.Append(""", forEndRepl.Pop());
|
||||||
|
#endregion
|
||||||
|
#region if---------------------------------------------------------
|
||||||
|
case "if":
|
||||||
|
codeTree.Push("if");
|
||||||
|
return string.Format(@""");
|
||||||
|
if ({1}tPlIf({0})) {{
|
||||||
|
tOuTpUt.Append(""", _2[0] == '!' ? _2.Substring(1) : _2, _2[0] == '!' ? '!' : ' ');
|
||||||
|
case "elseif":
|
||||||
|
codeTreeEnd(codeTree, "if");
|
||||||
|
codeTree.Push("if");
|
||||||
|
return string.Format(@""");
|
||||||
|
}} else if ({1}tPlIf({0})) {{
|
||||||
|
tOuTpUt.Append(""", _2[0] == '!' ? _2.Substring(1) : _2, _2[0] == '!' ? '!' : ' ');
|
||||||
|
case "else":
|
||||||
|
codeTreeEnd(codeTree, "if");
|
||||||
|
codeTree.Push("if");
|
||||||
|
return @""");
|
||||||
|
} else {
|
||||||
|
tOuTpUt.Append(""";
|
||||||
|
case "/if":
|
||||||
|
codeTreeEnd(codeTree, "if");
|
||||||
|
return @""");
|
||||||
|
}
|
||||||
|
tOuTpUt.Append(""";
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
return _0;
|
||||||
|
}));
|
||||||
|
|
||||||
|
sb.Append(@""");");
|
||||||
|
if (string.IsNullOrEmpty(extends) == false) {
|
||||||
|
sb.AppendFormat(@"
|
||||||
|
FreeSql.Generator.TemplateEngin.TemplateReturnInfo eXtEnDs_ReT = tEmPlAtEsEnDeR.RenderFile2(null, pRoCeSsOpTiOnS(), ""{0}"", rEfErErFiLeNaMe);
|
||||||
|
string rTn_Sb_string = rTn.Sb.ToString();
|
||||||
|
foreach(string eXtEnDs_ReT_blocks_key in eXtEnDs_ReT.Blocks.Keys) {{
|
||||||
|
if (rTn.Blocks.ContainsKey(eXtEnDs_ReT_blocks_key)) {{
|
||||||
|
int[] eXtEnDs_ReT_blocks_value = eXtEnDs_ReT.Blocks[eXtEnDs_ReT_blocks_key];
|
||||||
|
eXtEnDs_ReT.Sb.Remove(eXtEnDs_ReT_blocks_value[0], eXtEnDs_ReT_blocks_value[1]);
|
||||||
|
int[] rTn_blocks_value = rTn.Blocks[eXtEnDs_ReT_blocks_key];
|
||||||
|
eXtEnDs_ReT.Sb.Insert(eXtEnDs_ReT_blocks_value[0], rTn_Sb_string.Substring(rTn_blocks_value[0], rTn_blocks_value[1]));
|
||||||
|
foreach(string eXtEnDs_ReT_blocks_keyb in eXtEnDs_ReT.Blocks.Keys) {{
|
||||||
|
if (eXtEnDs_ReT_blocks_keyb == eXtEnDs_ReT_blocks_key) continue;
|
||||||
|
int[] eXtEnDs_ReT_blocks_valueb = eXtEnDs_ReT.Blocks[eXtEnDs_ReT_blocks_keyb];
|
||||||
|
if (eXtEnDs_ReT_blocks_valueb[0] >= eXtEnDs_ReT_blocks_value[0])
|
||||||
|
eXtEnDs_ReT_blocks_valueb[0] = eXtEnDs_ReT_blocks_valueb[0] - eXtEnDs_ReT_blocks_value[1] + rTn_blocks_value[1];
|
||||||
|
}}
|
||||||
|
eXtEnDs_ReT_blocks_value[1] = rTn_blocks_value[1];
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
return eXtEnDs_ReT;
|
||||||
|
", extends);
|
||||||
|
} else {
|
||||||
|
sb.Append(@"
|
||||||
|
return rTn;");
|
||||||
|
}
|
||||||
|
sb.Append(@"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
");
|
||||||
|
var str = "FreeSql.Generator.TemplateEngin.TemplatePrint Print = print;";
|
||||||
|
int dim_idx = sb.ToString().IndexOf(str) + str.Length;
|
||||||
|
foreach (string dic_name in options_copy.Keys) {
|
||||||
|
sb.Insert(dim_idx, string.Format(@"
|
||||||
|
dynamic {0} = oPtIoNs[""{0}""];", dic_name));
|
||||||
|
}
|
||||||
|
//Console.WriteLine(sb.ToString());
|
||||||
|
return Complie(sb.ToString(), @"TplDynamicCodeGenerate_view" + view);
|
||||||
|
}
|
||||||
|
private static string codeTreeEnd(Stack<string> codeTree, string tag) {
|
||||||
|
string ret = string.Empty;
|
||||||
|
Stack<int> pop = new Stack<int>();
|
||||||
|
foreach (string ct in codeTree) {
|
||||||
|
if (ct == "import" ||
|
||||||
|
ct == "include") {
|
||||||
|
pop.Push(1);
|
||||||
|
} else if (ct == tag) {
|
||||||
|
pop.Push(2);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (string.IsNullOrEmpty(tag) == false) pop.Clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pop.Count == 0 && string.IsNullOrEmpty(tag) == false)
|
||||||
|
return string.Concat("语法错误,{", tag, "} {/", tag, "} 并没配对");
|
||||||
|
while (pop.Count > 0 && pop.Pop() > 0) codeTree.Pop();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#region htmlSyntax
|
||||||
|
private static string htmlSyntax(string tplcode, int num) {
|
||||||
|
|
||||||
|
while (num-- > 0) {
|
||||||
|
string[] arr = _reg_syntax.Split(tplcode);
|
||||||
|
|
||||||
|
if (arr.Length == 1) break;
|
||||||
|
for (int a = 1; a < arr.Length; a += 4) {
|
||||||
|
string tag = string.Concat('<', arr[a]);
|
||||||
|
string end = string.Concat("</", arr[a], '>');
|
||||||
|
int fc = 1;
|
||||||
|
for (int b = a; fc > 0 && b < arr.Length; b += 4) {
|
||||||
|
if (b > a && arr[a].ToLower() == arr[b].ToLower()) fc++;
|
||||||
|
int bpos = 0;
|
||||||
|
while (true) {
|
||||||
|
int fa = arr[b + 3].IndexOf(tag, bpos);
|
||||||
|
int fb = arr[b + 3].IndexOf(end, bpos);
|
||||||
|
if (b == a) {
|
||||||
|
var z = arr[b + 3].IndexOf("/>");
|
||||||
|
if ((fb == -1 || z < fb) && z != -1) {
|
||||||
|
var y = arr[b + 3].Substring(0, z + 2);
|
||||||
|
if (_reg_htmltag.IsMatch(y) == false)
|
||||||
|
fb = z - end.Length + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fa == -1 && fb == -1) break;
|
||||||
|
if (fa != -1 && (fa < fb || fb == -1)) {
|
||||||
|
fc++;
|
||||||
|
bpos = fa + tag.Length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fb != -1) fc--;
|
||||||
|
if (fc <= 0) {
|
||||||
|
var a1 = arr[a + 1];
|
||||||
|
var end3 = string.Concat("{/", a1, "}");
|
||||||
|
if (a1.ToLower() == "else") {
|
||||||
|
if (_reg_blank.Replace(arr[a - 4 + 3], "").EndsWith("{/if}", StringComparison.CurrentCultureIgnoreCase) == true) {
|
||||||
|
var idx = arr[a - 4 + 3].IndexOf("{/if}");
|
||||||
|
arr[a - 4 + 3] = string.Concat(arr[a - 4 + 3].Substring(0, idx), arr[a - 4 + 3].Substring(idx + 5));
|
||||||
|
//如果 @else="有条件内容",则变换成 elseif 条件内容
|
||||||
|
if (_reg_blank.Replace(arr[a + 2], "").Length > 0) a1 = "elseif";
|
||||||
|
end3 = "{/if}";
|
||||||
|
} else {
|
||||||
|
arr[a] = string.Concat("指令 @", arr[a + 1], "='", arr[a + 2], "' 没紧接着 if/else 指令之后,无效. <", arr[a]);
|
||||||
|
arr[a + 1] = arr[a + 2] = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (arr[a + 1].Length > 0) {
|
||||||
|
if (_reg_blank.Replace(arr[a + 2], "").Length > 0 || a1.ToLower() == "else") {
|
||||||
|
arr[b + 3] = string.Concat(arr[b + 3].Substring(0, fb + end.Length), end3, arr[b + 3].Substring(fb + end.Length));
|
||||||
|
arr[a] = string.Concat("{", a1, " ", arr[a + 2], "}<", arr[a]);
|
||||||
|
arr[a + 1] = arr[a + 2] = string.Empty;
|
||||||
|
} else {
|
||||||
|
arr[a] = string.Concat('<', arr[a]);
|
||||||
|
arr[a + 1] = arr[a + 2] = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bpos = fb + end.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fc > 0) {
|
||||||
|
arr[a] = string.Concat("不严谨的html格式,请检查 ", arr[a], " 的结束标签, @", arr[a + 1], "='", arr[a + 2], "' 指令无效. <", arr[a]);
|
||||||
|
arr[a + 1] = arr[a + 2] = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (arr.Length > 0) tplcode = string.Join(string.Empty, arr);
|
||||||
|
}
|
||||||
|
return tplcode;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region Complie
|
||||||
|
private static ITemplateOutput Complie(string cscode, string typename) {
|
||||||
|
var assemly = _compiler.Value.CompileCode(cscode);
|
||||||
|
return assemly.CreateObject(typename) as ITemplateOutput;
|
||||||
|
}
|
||||||
|
static ConcurrentDictionary<string, (DateTime, object)> _compiler_objs = new ConcurrentDictionary<string, (DateTime, object)>();
|
||||||
|
static Lazy<CSScriptLib.RoslynEvaluator> _compiler = new Lazy<CSScriptLib.RoslynEvaluator>(() => {
|
||||||
|
var dlls = Directory.GetFiles(Directory.GetParent(Type.GetType("IFreeSql, FreeSql").Assembly.Location).FullName, "*.dll");
|
||||||
|
var compiler = new CSScriptLib.RoslynEvaluator();
|
||||||
|
compiler.DisableReferencingFromCode = false;
|
||||||
|
compiler.DebugBuild = true;
|
||||||
|
foreach (var dll in dlls) {
|
||||||
|
var ass = Assembly.LoadFile(dll);
|
||||||
|
compiler.ReferenceAssembly(ass);
|
||||||
|
}
|
||||||
|
return compiler;
|
||||||
|
});
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Utils
|
||||||
|
public class Utils {
|
||||||
|
public static string ReplaceSingleQuote(object exp) {
|
||||||
|
//将 ' 转换成 "
|
||||||
|
string exp2 = string.Concat(exp);
|
||||||
|
int quote_pos = -1;
|
||||||
|
while (true) {
|
||||||
|
int first_pos = quote_pos = exp2.IndexOf('\'', quote_pos + 1);
|
||||||
|
if (quote_pos == -1) break;
|
||||||
|
while (true) {
|
||||||
|
quote_pos = exp2.IndexOf('\'', quote_pos + 1);
|
||||||
|
if (quote_pos == -1) break;
|
||||||
|
int r_cout = 0;
|
||||||
|
for (int p = 1; true; p++) {
|
||||||
|
if (exp2[quote_pos - p] == '\\') r_cout++;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
if (r_cout % 2 == 0/* && quote_pos - first_pos > 2*/) {
|
||||||
|
string str1 = exp2.Substring(0, first_pos);
|
||||||
|
string str2 = exp2.Substring(first_pos + 1, quote_pos - first_pos - 1);
|
||||||
|
string str3 = exp2.Substring(quote_pos + 1);
|
||||||
|
string str4 = str2.Replace("\"", "\\\"");
|
||||||
|
quote_pos += str4.Length - str2.Length;
|
||||||
|
exp2 = string.Concat(str1, "\"", str4, "\"", str3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (quote_pos == -1) break;
|
||||||
|
}
|
||||||
|
return exp2;
|
||||||
|
}
|
||||||
|
public static string GetConstString(object obj) {
|
||||||
|
return string.Concat(obj)
|
||||||
|
.Replace("\\", "\\\\")
|
||||||
|
.Replace("\"", "\\\"")
|
||||||
|
.Replace("\r", "\\r")
|
||||||
|
.Replace("\n", "\\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ReadTextFile(string path) {
|
||||||
|
byte[] bytes = ReadFile(path);
|
||||||
|
return Encoding.UTF8.GetString(bytes).TrimStart((char)65279);
|
||||||
|
}
|
||||||
|
public static byte[] ReadFile(string path) {
|
||||||
|
if (File.Exists(path)) {
|
||||||
|
string destFileName = Path.GetTempFileName();
|
||||||
|
File.Copy(path, destFileName, true);
|
||||||
|
int read = 0;
|
||||||
|
byte[] data = new byte[1024];
|
||||||
|
using (MemoryStream ms = new MemoryStream()) {
|
||||||
|
using (FileStream fs = new FileStream(destFileName, FileMode.OpenOrCreate, FileAccess.Read)) {
|
||||||
|
do {
|
||||||
|
read = fs.Read(data, 0, data.Length);
|
||||||
|
if (read <= 0) break;
|
||||||
|
ms.Write(data, 0, read);
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
File.Delete(destFileName);
|
||||||
|
data = ms.ToArray();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return new byte[] { };
|
||||||
|
}
|
||||||
|
public static string TranslateUrl(string url) {
|
||||||
|
return TranslateUrl(url, null);
|
||||||
|
}
|
||||||
|
public static string TranslateUrl(string url, string baseDir) {
|
||||||
|
if (string.IsNullOrEmpty(baseDir)) baseDir = AppContext.BaseDirectory + "/";
|
||||||
|
if (string.IsNullOrEmpty(url)) return Path.GetDirectoryName(baseDir);
|
||||||
|
if (url.StartsWith("~/")) url = url.Substring(1);
|
||||||
|
if (url.StartsWith("/")) return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(baseDir), url.TrimStart('/')));
|
||||||
|
if (url.StartsWith("\\")) return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(baseDir), url.TrimStart('\\')));
|
||||||
|
if (url.IndexOf(":\\") != -1) return url;
|
||||||
|
return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(baseDir), url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
71
FreeSql/Generator/TemplateGenerator.cs
Normal file
71
FreeSql/Generator/TemplateGenerator.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using FreeSql.DatabaseModel;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Generator {
|
||||||
|
public class TemplateGenerator {
|
||||||
|
|
||||||
|
public void Build(IDbFirst dbfirst, string templateDirectory, string outputDirectory, params string[] database) {
|
||||||
|
if (dbfirst == null) throw new ArgumentException("dbfirst 参数不能为 null");
|
||||||
|
if (string.IsNullOrEmpty(templateDirectory) || Directory.Exists(templateDirectory) == false) throw new ArgumentException("templateDirectory 目录不存在");
|
||||||
|
if (string.IsNullOrEmpty(templateDirectory)) throw new ArgumentException("outputDirectory 不能为 null");
|
||||||
|
if (database == null || database.Any() == false) throw new ArgumentException("database 参数不能为空");
|
||||||
|
if (Directory.Exists(outputDirectory) == false) Directory.CreateDirectory(outputDirectory);
|
||||||
|
templateDirectory = new DirectoryInfo(templateDirectory).FullName;
|
||||||
|
outputDirectory = new DirectoryInfo(outputDirectory).FullName;
|
||||||
|
if (templateDirectory.IndexOf(outputDirectory, StringComparison.CurrentCultureIgnoreCase) != -1) throw new ArgumentException("outputDirectory 目录不能设置在 templateDirectory 目录内");
|
||||||
|
var tables = dbfirst.GetTablesByDatabase(database);
|
||||||
|
var tpl = new TemplateEngin(templateDirectory, "FreeSql", "FreeSql.DatabaseModel");
|
||||||
|
BuildEachDirectory(templateDirectory, outputDirectory, tpl, dbfirst, tables);
|
||||||
|
tpl.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildEachDirectory(string templateDirectory, string outputDirectory, TemplateEngin tpl, IDbFirst dbfirst, List<DbTableInfo> tables) {
|
||||||
|
if (Directory.Exists(outputDirectory) == false) Directory.CreateDirectory(outputDirectory);
|
||||||
|
var files = Directory.GetFiles(templateDirectory);
|
||||||
|
foreach (var file in files) {
|
||||||
|
var fi = new FileInfo(file);
|
||||||
|
if (string.Compare(fi.Extension, ".FreeSql", true) == 0) {
|
||||||
|
var outputExtension = "." + fi.Name.Split('.')[1];
|
||||||
|
if (fi.Name.StartsWith("for-table.")) {
|
||||||
|
foreach (var table in tables) {
|
||||||
|
var result = tpl.RenderFile(file, new Dictionary<string, object>() { { "table", table }, { "dbfirst", dbfirst } });
|
||||||
|
var outputName = table.Name + outputExtension;
|
||||||
|
var mcls = Regex.Match(result, @"\s+class\s+(\w+)");
|
||||||
|
if (mcls.Success) outputName = mcls.Groups[1].Value + outputExtension;
|
||||||
|
var outputStream = Encoding.UTF8.GetBytes(result);
|
||||||
|
var fullname = outputDirectory + "/" + outputName;
|
||||||
|
if (File.Exists(fullname)) File.Delete(fullname);
|
||||||
|
using (var outfs = File.Open(fullname, FileMode.OpenOrCreate, FileAccess.Write)) {
|
||||||
|
outfs.Write(outputStream, 0, outputStream.Length);
|
||||||
|
outfs.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
var result = tpl.RenderFile(file, new Dictionary<string, object>() { { "tables", tables }, { "dbfirst", dbfirst } });
|
||||||
|
var outputName = fi.Name;
|
||||||
|
var mcls = Regex.Match(result, @"\s+class\s+(\w+)");
|
||||||
|
if (mcls.Success) outputName = mcls.Groups[1].Value + outputExtension;
|
||||||
|
var outputStream = Encoding.UTF8.GetBytes(result);
|
||||||
|
var fullname = outputDirectory + "/" + outputName;
|
||||||
|
if (File.Exists(fullname)) File.Delete(fullname);
|
||||||
|
using (var outfs = File.Open(fullname, FileMode.OpenOrCreate, FileAccess.Write)) {
|
||||||
|
outfs.Write(outputStream, 0, outputStream.Length);
|
||||||
|
outfs.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File.Copy(file, outputDirectory + file.Replace(templateDirectory, ""), true);
|
||||||
|
}
|
||||||
|
var dirs = Directory.GetDirectories(templateDirectory);
|
||||||
|
foreach(var dir in dirs) {
|
||||||
|
BuildEachDirectory(dir, outputDirectory + dir.Replace(templateDirectory, ""), tpl, dbfirst, tables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
FreeSql/Interface/Curd/IDelete.cs
Normal file
57
FreeSql/Interface/Curd/IDelete.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface IDelete<T1> where T1 : class {
|
||||||
|
/// <summary>
|
||||||
|
/// lambda表达式条件,仅支持实体基础成员(不包含导航对象)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exp">lambda表达式条件</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDelete<T1> Where(Expression<Func<T1, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 原生sql语法条件,Where("id = ?id", new { id = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法条件</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDelete<T1> Where(string sql, object parms = null);
|
||||||
|
/// <summary>
|
||||||
|
/// 传入实体,将主键作为条件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">实体</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDelete<T1> Where(T1 item);
|
||||||
|
/// <summary>
|
||||||
|
/// 传入实体集合,将主键作为条件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">实体集合</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDelete<T1> Where(IEnumerable<T1> items);
|
||||||
|
/// <summary>
|
||||||
|
/// 子查询是否存在
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TEntity2"></typeparam>
|
||||||
|
/// <param name="select">子查询</param>
|
||||||
|
/// <param name="notExists">不存在</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDelete<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回即将执行的SQL语句
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
string ToSql();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL语句,返回影响的行数
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
long ExecuteAffrows();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL语句,返回被删除的记录
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<T1> ExecuteDeleted();
|
||||||
|
}
|
||||||
|
}
|
55
FreeSql/Interface/Curd/IInsert.cs
Normal file
55
FreeSql/Interface/Curd/IInsert.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface IInsert<T1> where T1 : class {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 追加准备插入的实体
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">实体</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IInsert<T1> AppendData(T1 source);
|
||||||
|
/// <summary>
|
||||||
|
/// 追加准备插入的实体集合
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">实体集合</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IInsert<T1> AppendData(IEnumerable<T1> source);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 只插入的列,InsertColumns(a => a.Name) | InsertColumns(a => new{a.Name,a.Time}) | InsertColumns(a => new[]{"name","time"})
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columns">lambda选择列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IInsert<T1> InsertColumns(Expression<Func<T1, object>> columns);
|
||||||
|
/// <summary>
|
||||||
|
/// 忽略的列,IgnoreColumns(a => a.Name) | IgnoreColumns(a => new{a.Name,a.Time}) | IgnoreColumns(a => new[]{"name","time"})
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columns">lambda选择列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IInsert<T1> IgnoreColumns(Expression<Func<T1, object>> columns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回即将执行的SQL语句
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
string ToSql();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL语句,返回影响的行数
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
long ExecuteAffrows();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL语句,返回自增值
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
long ExecuteIdentity();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL语句,返回插入后的记录
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<T1> ExecuteInserted();
|
||||||
|
}
|
||||||
|
}
|
198
FreeSql/Interface/Curd/ISelect/ISelect0.cs
Normal file
198
FreeSql/Interface/Curd/ISelect/ISelect0.cs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect0<TSelect, T1> {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL查询,返回 T1 实体所有字段的记录,记录不存在时返回 Count 为 0 的列表
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<T1> ToList();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL查询,返回 field 指定字段的记录,并以元组或基础类型(int,string,long)接收,记录不存在时返回 Count 为 0 的列表
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TTuple"></typeparam>
|
||||||
|
/// <param name="field"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<TTuple> ToList<TTuple>(string field);
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL查询,返回 T1 实体所有字段的第一条记录,记录不存在时返回 null
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
T1 ToOne();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回即将执行的SQL语句
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">指定字段</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string ToSql(string field = null);
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL查询,是否有记录
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool Any();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询的记录数量
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
long Count();
|
||||||
|
/// <summary>
|
||||||
|
/// 查询的记录数量,以参数out形式返回
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">返回的变量</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Count(out long count);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定从主库查询(默认查询从库)
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Master();
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存查询结果
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="seconds">缓存秒数</param>
|
||||||
|
/// <param name="key">缓存key</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Caching(int seconds, string key = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 左联查询,使用导航属性自动生成SQL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exp">表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect LeftJoin(Expression<Func<T1, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 联接查询,使用导航属性自动生成SQL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exp">表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect InnerJoin(Expression<Func<T1, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 右联查询,使用导航属性自动生成SQL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exp">表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect RightJoin(Expression<Func<T1, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 左联查询,指定关联的实体类型
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2">关联的实体类型</typeparam>
|
||||||
|
/// <param name="exp">表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect LeftJoin<T2>(Expression<Func<T1, T2, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 联接查询,指定关联的实体类型
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2">关联的实体类型</typeparam>
|
||||||
|
/// <param name="exp">表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect InnerJoin<T2>(Expression<Func<T1, T2, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 右联查询,指定关联的实体类型
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2">关联的实体类型</typeparam>
|
||||||
|
/// <param name="exp">表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect RightJoin<T2>(Expression<Func<T1, T2, bool>> exp);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 左联查询,使用原生sql语法,LeftJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法条件</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect LeftJoin(string sql, object parms = null);
|
||||||
|
/// <summary>
|
||||||
|
/// 联接查询,使用原生sql语法,InnerJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法条件</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect InnerJoin(string sql, object parms = null);
|
||||||
|
/// <summary>
|
||||||
|
/// 右联查询,使用原生sql语法,RightJoin("type b on b.id = a.id and b.clicks > ?clicks", new { clicks = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法条件</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect RightJoin(string sql, object parms = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 原生sql语法条件,Where("id = ?id", new { id = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法条件</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Where(string sql, object parms = null);
|
||||||
|
/// <summary>
|
||||||
|
/// 原生sql语法条件,WhereIf(true, "id = ?id", new { id = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="condition">true 时生效</param>
|
||||||
|
/// <param name="sql">sql语法条件</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect WhereIf(bool condition, string sql, object parms = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按原生sql语法分组,GroupBy("concat(name, ?cc)", new { cc = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect GroupBy(string sql, object parms = null);
|
||||||
|
/// <summary>
|
||||||
|
/// 按原生sql语法聚合条件过滤,Having("count(name) = ?cc", new { cc = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法条件</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Having(string sql, object parms = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按原生sql语法排序,OrderBy("count(name) + ?cc", new { cc = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect OrderBy(string sql, object parms = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询向后偏移行数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Skip(int offset);
|
||||||
|
/// <summary>
|
||||||
|
/// 查询向后偏移行数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">行数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Offset(int offset);
|
||||||
|
/// <summary>
|
||||||
|
/// 查询多少条数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="limit"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Limit(int limit);
|
||||||
|
/// <summary>
|
||||||
|
/// 查询多少条数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="limit"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Take(int limit);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分页
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pageIndex">第几页</param>
|
||||||
|
/// <param name="pageSize">每页多少</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TSelect Page(int pageIndex, int pageSize);
|
||||||
|
}
|
||||||
|
}
|
230
FreeSql/Interface/Curd/ISelect/ISelect1.cs
Normal file
230
FreeSql/Interface/Curd/ISelect/ISelect1.cs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1> : ISelect0<ISelect<T1>, T1> where T1 : class {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL查询,返回指定字段的记录,记录不存在时返回 Count 为 0 的列表
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TReturn">返回类型</typeparam>
|
||||||
|
/// <param name="select">选择列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, TReturn>> select);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 求和
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TMember">返回类型</typeparam>
|
||||||
|
/// <param name="column">列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, TMember>> column);
|
||||||
|
/// <summary>
|
||||||
|
/// 最小值
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TMember">返回类型</typeparam>
|
||||||
|
/// <param name="column">列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, TMember>> column);
|
||||||
|
/// <summary>
|
||||||
|
/// 最大值
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TMember">返回类型</typeparam>
|
||||||
|
/// <param name="column">列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, TMember>> column);
|
||||||
|
/// <summary>
|
||||||
|
/// 平均值
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TMember">返回类型</typeparam>
|
||||||
|
/// <param name="column">列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, TMember>> column);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 指定别名
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="alias">别名</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> As(string alias = "a");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 多表查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <param name="exp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <param name="exp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <typeparam name="T5"></typeparam>
|
||||||
|
/// <param name="exp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <typeparam name="T5"></typeparam>
|
||||||
|
/// <typeparam name="T6"></typeparam>
|
||||||
|
/// <param name="exp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <typeparam name="T5"></typeparam>
|
||||||
|
/// <typeparam name="T6"></typeparam>
|
||||||
|
/// <typeparam name="T7"></typeparam>
|
||||||
|
/// <param name="exp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <typeparam name="T5"></typeparam>
|
||||||
|
/// <typeparam name="T6"></typeparam>
|
||||||
|
/// <typeparam name="T7"></typeparam>
|
||||||
|
/// <typeparam name="T8"></typeparam>
|
||||||
|
/// <param name="exp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <typeparam name="T5"></typeparam>
|
||||||
|
/// <typeparam name="T6"></typeparam>
|
||||||
|
/// <typeparam name="T7"></typeparam>
|
||||||
|
/// <typeparam name="T8"></typeparam>
|
||||||
|
/// <typeparam name="T9"></typeparam>
|
||||||
|
/// <param name="exp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <typeparam name="T5"></typeparam>
|
||||||
|
/// <typeparam name="T6"></typeparam>
|
||||||
|
/// <typeparam name="T7"></typeparam>
|
||||||
|
/// <typeparam name="T8"></typeparam>
|
||||||
|
/// <typeparam name="T9"></typeparam>
|
||||||
|
/// <typeparam name="T10"></typeparam>
|
||||||
|
/// <param name="exp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exp">lambda表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> Where(Expression<Func<T1, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 查询条件,Where(true, a => a.Id > 10),支导航对象查询,Where(true, a => a.Author.Email == "2881099@qq.com")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="condition">true 时生效</param>
|
||||||
|
/// <param name="exp">lambda表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> WhereIf(bool condition, Expression<Func<T1, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 多表条件查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <param name="exp">lambda表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> Where<T2>(Expression<Func<T1, T2, bool>> exp) where T2 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表条件查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <param name="exp">lambda表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> Where<T2, T3>(Expression<Func<T1, T2, T3, bool>> exp) where T2 : class where T3 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表条件查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <param name="exp">lambda表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> Where<T2, T3, T4>(Expression<Func<T1, T2, T3, T4, bool>> exp) where T2 : class where T3 : class where T4 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 多表条件查询
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T2"></typeparam>
|
||||||
|
/// <typeparam name="T3"></typeparam>
|
||||||
|
/// <typeparam name="T4"></typeparam>
|
||||||
|
/// <param name="exp">lambda表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> Where<T2, T3, T4, T5>(Expression<Func<T1, T2, T3, T4, T5, bool>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模糊查询,选择多个列 OR,WhereLike(a => new[] { a.Title, a.Content }, "%sql%")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columns">lambda选择列</param>
|
||||||
|
/// <param name="pattern">查询内容</param>
|
||||||
|
/// <param name="notLike">not like</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> WhereLike(Expression<Func<T1, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
/// <summary>
|
||||||
|
/// 模糊查询,WhereLike(a => a.Title, "%sql")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column">lambda选择列</param>
|
||||||
|
/// <param name="pattern">查询内容</param>
|
||||||
|
/// <param name="notLike">not like</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> WhereLike(Expression<Func<T1, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.Time}) | GroupBy(a => new[]{"name","time"})
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columns"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> GroupBy(Expression<Func<T1, object>> columns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按列排序,OrderBy(a => a.Time)
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TMember"></typeparam>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> OrderBy<TMember>(Expression<Func<T1, TMember>> column);
|
||||||
|
/// <summary>
|
||||||
|
/// 按列倒向排序,OrderByDescending(a => a.Time)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column">列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect10.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect10.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : ISelect0<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, T1> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect2.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect2.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2> : ISelect0<ISelect<T1, T2>, T1> where T1 : class where T2 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2> Where(Expression<Func<T1, T2, bool>> exp);
|
||||||
|
ISelect<T1, T2> WhereIf(bool condition, Expression<Func<T1, T2, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2> WhereLike(Expression<Func<T1, T2, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2> WhereLike(Expression<Func<T1, T2, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2> GroupBy(Expression<Func<T1, T2, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2> OrderBy<TMember>(Expression<Func<T1, T2, TMember>> column);
|
||||||
|
ISelect<T1, T2> OrderByDescending<TMember>(Expression<Func<T1, T2, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect3.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect3.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2, T3> : ISelect0<ISelect<T1, T2, T3>, T1> where T1 : class where T2 : class where T3 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, T3, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> Where(Expression<Func<T1, T2, T3, bool>> exp);
|
||||||
|
ISelect<T1, T2, T3> WhereIf(bool condition, Expression<Func<T1, T2, T3, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> WhereLike(Expression<Func<T1, T2, T3, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2, T3> WhereLike(Expression<Func<T1, T2, T3, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> GroupBy(Expression<Func<T1, T2, T3, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> OrderBy<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
|
||||||
|
ISelect<T1, T2, T3> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect4.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect4.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2, T3, T4> : ISelect0<ISelect<T1, T2, T3, T4>, T1> where T1 : class where T2 : class where T3 : class where T4 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, T3, T4, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> Where(Expression<Func<T1, T2, T3, T4, bool>> exp);
|
||||||
|
ISelect<T1, T2, T3, T4> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> WhereLike(Expression<Func<T1, T2, T3, T4, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2, T3, T4> WhereLike(Expression<Func<T1, T2, T3, T4, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> GroupBy(Expression<Func<T1, T2, T3, T4, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
|
||||||
|
ISelect<T1, T2, T3, T4> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect5.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect5.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2, T3, T4, T5> : ISelect0<ISelect<T1, T2, T3, T4, T5>, T1> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> Where(Expression<Func<T1, T2, T3, T4, T5, bool>> exp);
|
||||||
|
ISelect<T1, T2, T3, T4, T5> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> WhereLike(Expression<Func<T1, T2, T3, T4, T5, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2, T3, T4, T5> WhereLike(Expression<Func<T1, T2, T3, T4, T5, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> GroupBy(Expression<Func<T1, T2, T3, T4, T5, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
|
||||||
|
ISelect<T1, T2, T3, T4, T5> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect6.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect6.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2, T3, T4, T5, T6> : ISelect0<ISelect<T1, T2, T3, T4, T5, T6>, T1> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> Where(Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect7.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect7.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2, T3, T4, T5, T6, T7> : ISelect0<ISelect<T1, T2, T3, T4, T5, T6, T7>, T1> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect8.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect8.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2, T3, T4, T5, T6, T7, T8> : ISelect0<ISelect<T1, T2, T3, T4, T5, T6, T7, T8>, T1> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
26
FreeSql/Interface/Curd/ISelect/ISelect9.cs
Normal file
26
FreeSql/Interface/Curd/ISelect/ISelect9.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : ISelect0<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>, T1> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class {
|
||||||
|
|
||||||
|
List<TReturn> ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TReturn>> select);
|
||||||
|
|
||||||
|
TMember Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
|
||||||
|
TMember Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
|
||||||
|
TMember Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
|
||||||
|
TMember Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, object>> columns);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
64
FreeSql/Interface/Curd/ISelect/ISelectFrom.cs
Normal file
64
FreeSql/Interface/Curd/ISelect/ISelectFrom.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ISelectFromExpression<T1> where T1 : class {
|
||||||
|
|
||||||
|
ISelectFromExpression<T1> LeftJoin(Expression<Func<T1, bool>> exp);
|
||||||
|
ISelectFromExpression<T1> InnerJoin(Expression<Func<T1, bool>> exp);
|
||||||
|
ISelectFromExpression<T1> RightJoin(Expression<Func<T1, bool>> exp);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询条件,Where(a => a.Id > 10),支持导航对象查询,Where(a => a.Author.Email == "2881099@qq.com")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exp">lambda表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelectFromExpression<T1> Where(Expression<Func<T1, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 查询条件,Where(true, a => a.Id > 10),支导航对象查询,Where(true, a => a.Author.Email == "2881099@qq.com")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="condition">true 时生效</param>
|
||||||
|
/// <param name="exp">lambda表达式</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelectFromExpression<T1> WhereIf(bool condition, Expression<Func<T1, bool>> exp);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模糊查询,选择多个列 OR,WhereLike(a => new[] { a.Title, a.Content }, "%sql%")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columns">lambda选择列</param>
|
||||||
|
/// <param name="pattern">查询内容</param>
|
||||||
|
/// <param name="notLike">not like</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelectFromExpression<T1> WhereLike(Expression<Func<T1, string[]>> columns, string pattern, bool notLike = false);
|
||||||
|
/// <summary>
|
||||||
|
/// 模糊查询,WhereLike(a => a.Title, "%sql")
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column">lambda选择列</param>
|
||||||
|
/// <param name="pattern">查询内容</param>
|
||||||
|
/// <param name="notLike">not like</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelectFromExpression<T1> WhereLike(Expression<Func<T1, string>> column, string pattern, bool notLike = false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.Time}) | GroupBy(a => new[]{"name","time"})
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columns"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelectFromExpression<T1> GroupBy(Expression<Func<T1, object>> columns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 按列排序,OrderBy(a => a.Time)
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TMember"></typeparam>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelectFromExpression<T1> OrderBy<TMember>(Expression<Func<T1, TMember>> column);
|
||||||
|
/// <summary>
|
||||||
|
/// 按列倒向排序,OrderByDescending(a => a.Time)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column">列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelectFromExpression<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column);
|
||||||
|
}
|
||||||
|
}
|
100
FreeSql/Interface/Curd/IUpdate.cs
Normal file
100
FreeSql/Interface/Curd/IUpdate.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface IUpdate<T1> where T1 : class {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新数据,设置更新的实体
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">实体</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> SetSource(T1 source);
|
||||||
|
/// <summary>
|
||||||
|
/// 更新数据,设置更新的实体集合
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">实体集合</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> SetSource(IEnumerable<T1> source);
|
||||||
|
/// <summary>
|
||||||
|
/// 忽略的列,IgnoreColumns(a => a.Name) | IgnoreColumns(a => new{a.Name,a.Time}) | IgnoreColumns(a => new[]{"name","time"})
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="columns">lambda选择列</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置列的新值,Set(a => a.Name, "newvalue")
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TMember"></typeparam>
|
||||||
|
/// <param name="column">lambda选择列</param>
|
||||||
|
/// <param name="value">新值</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value);
|
||||||
|
/// <summary>
|
||||||
|
/// 设置列的的新值为基础上增加,格式:Set(a => a.Clicks + 1) 相当于 clicks=clicks+1
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TMember"></typeparam>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> binaryExpression);
|
||||||
|
/// <summary>
|
||||||
|
/// 设置值,自定义SQL语法,SetRaw("title = ?title", new { title = "newtitle" })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> SetRaw(string sql, object parms = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// lambda表达式条件,仅支持实体基础成员(不包含导航对象)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exp">lambda表达式条件</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> Where(Expression<Func<T1, bool>> exp);
|
||||||
|
/// <summary>
|
||||||
|
/// 原生sql语法条件,Where("id = ?id", new { id = 1 })
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sql">sql语法条件</param>
|
||||||
|
/// <param name="parms">参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> Where(string sql, object parms = null);
|
||||||
|
/// <summary>
|
||||||
|
/// 传入实体,将主键作为条件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">实体</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> Where(T1 item);
|
||||||
|
/// <summary>
|
||||||
|
/// 传入实体集合,将主键作为条件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="items">实体集合</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> Where(IEnumerable<T1> items);
|
||||||
|
/// <summary>
|
||||||
|
/// 子查询是否存在
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TEntity2"></typeparam>
|
||||||
|
/// <param name="select">子查询</param>
|
||||||
|
/// <param name="notExists">不存在</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回即将执行的SQL语句
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
string ToSql();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL语句,返回影响的行数
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
long ExecuteAffrows();
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL语句,返回更新后的记录
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<T1> ExecuteUpdated();
|
||||||
|
}
|
||||||
|
}
|
138
FreeSql/Interface/IAdo.cs
Normal file
138
FreeSql/Interface/IAdo.cs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
using FreeSql.DatabaseModel;
|
||||||
|
using SafeObjectPool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public partial interface IAdo {
|
||||||
|
/// <summary>
|
||||||
|
/// 主库连接池
|
||||||
|
/// </summary>
|
||||||
|
ObjectPool<DbConnection> MasterPool { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// 从库连接池
|
||||||
|
/// </summary>
|
||||||
|
List<ObjectPool<DbConnection>> SlavePools { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// 是否跟踪记录SQL执行性能日志
|
||||||
|
/// </summary>
|
||||||
|
bool IsTracePerformance { get; set; }
|
||||||
|
|
||||||
|
#region 事务
|
||||||
|
/// <summary>
|
||||||
|
/// 开启事务(不支持异步),60秒未执行完将自动提交
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">事务体 () => {}</param>
|
||||||
|
void Transaction(Action handler);
|
||||||
|
/// <summary>
|
||||||
|
/// 开启事务(不支持异步)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">事务体 () => {}</param>
|
||||||
|
/// <param name="timeout">超时,未执行完将自动提交</param>
|
||||||
|
void Transaction(Action handler, TimeSpan timeout);
|
||||||
|
/// <summary>
|
||||||
|
/// 当前线程的事务
|
||||||
|
/// </summary>
|
||||||
|
DbTransaction TransactionCurrentThread { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// 事务完成前预删除缓存
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keys"></param>
|
||||||
|
void TransactionPreRemoveCache(params string[] keys);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="readerHander"></param>
|
||||||
|
/// <param name="cmdType"></param>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
void ExecuteReader(Action<DbDataReader> readerHander, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
/// <summary>
|
||||||
|
/// 若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
object[][] ExecuteArray(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
/// <summary>
|
||||||
|
/// 若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
DataTable ExecuteDataTable(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
/// <summary>
|
||||||
|
/// 在【主库】执行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdType"></param>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
int ExecuteNonQuery(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
/// <summary>
|
||||||
|
/// 在【主库】执行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdType"></param>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
object ExecuteScalar(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL返回对象集合,Query<User>("select * from user where age > @age", new { age = 25 })
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="parms"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<T> Query<T>(string cmdText, object parms = null);
|
||||||
|
|
||||||
|
#region async
|
||||||
|
/// <summary>
|
||||||
|
/// 若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="readerHander"></param>
|
||||||
|
/// <param name="cmdType"></param>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
Task ExecuteReaderAsync(Func<DbDataReader, Task> readerHander, CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
/// <summary>
|
||||||
|
/// 若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
Task<object[][]> ExecuteArrayAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
/// <summary>
|
||||||
|
/// 若使用读写分离,查询【从库】条件cmdText.StartsWith("SELECT "),否则查询【主库】
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
Task<DataTable> ExecuteDataTableAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
/// <summary>
|
||||||
|
/// 在【主库】执行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdType"></param>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
Task<int> ExecuteNonQueryAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
/// <summary>
|
||||||
|
/// 在【主库】执行
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdType"></param>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="cmdParms"></param>
|
||||||
|
Task<object> ExecuteScalarAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行SQL返回对象集合,Query<User>("select * from user where age > @age", new { age = 25 })
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="cmdText"></param>
|
||||||
|
/// <param name="parms"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<List<T>> QueryAsync<T>(string cmdText, object parms = null);
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
118
FreeSql/Interface/ICache.cs
Normal file
118
FreeSql/Interface/ICache.cs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ICache {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存数据时序列化方法,若无设置则默认使用 Json.net
|
||||||
|
/// </summary>
|
||||||
|
Func<object, string> Serialize { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 获取缓存数据时反序列化方法,若无设置则默认使用 Json.net
|
||||||
|
/// </summary>
|
||||||
|
Func<string, Type, object> Deserialize { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存可序列化数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <param name="data">可序列化数据</param>
|
||||||
|
/// <param name="timeoutSeconds">缓存秒数,<=0时永久缓存</param>
|
||||||
|
void Set<T>(string key, T data, int timeoutSeconds = 0);
|
||||||
|
/// <summary>
|
||||||
|
/// 循环或批量获取缓存数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
T Get<T>(string key);
|
||||||
|
/// <summary>
|
||||||
|
/// 循环或批量获取缓存数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string Get(string key);
|
||||||
|
/// <summary>
|
||||||
|
/// 循环或批量删除缓存键
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keys">缓存键[数组]</param>
|
||||||
|
void Remove(params string[] keys);
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存壳
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">缓存类型</typeparam>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <param name="timeoutSeconds">缓存秒数</param>
|
||||||
|
/// <param name="getData">获取源数据的函数</param>
|
||||||
|
/// <param name="serialize">序列化函数</param>
|
||||||
|
/// <param name="deserialize">反序列化函数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
T Shell<T>(string key, int timeoutSeconds, Func<T> getData);
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存壳(哈希表)
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">缓存类型</typeparam>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <param name="field">字段</param>
|
||||||
|
/// <param name="timeoutSeconds">缓存秒数</param>
|
||||||
|
/// <param name="getData">获取源数据的函数</param>
|
||||||
|
/// <param name="serialize">序列化函数</param>
|
||||||
|
/// <param name="deserialize">反序列化函数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
T Shell<T>(string key, string field, int timeoutSeconds, Func<T> getData);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存可序列化数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <param name="data">可序列化数据</param>
|
||||||
|
/// <param name="timeoutSeconds">缓存秒数,<=0时永久缓存</param>
|
||||||
|
Task SetAsync<T>(string key, T data, int timeoutSeconds = 0);
|
||||||
|
/// <summary>
|
||||||
|
/// 循环或批量获取缓存数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<T> GetAsync<T>(string key);
|
||||||
|
/// <summary>
|
||||||
|
/// 循环或批量获取缓存数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<string> GetAsync(string key);
|
||||||
|
/// <summary>
|
||||||
|
/// 循环或批量删除缓存键
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keys">缓存键[数组]</param>
|
||||||
|
Task RemoveAsync(params string[] keys);
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存壳
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">缓存类型</typeparam>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <param name="timeoutSeconds">缓存秒数</param>
|
||||||
|
/// <param name="getData">获取源数据的函数</param>
|
||||||
|
/// <param name="serialize">序列化函数</param>
|
||||||
|
/// <param name="deserialize">反序列化函数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<T> ShellAsync<T>(string key, int timeoutSeconds, Func<Task<T>> getDataAsync);
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存壳(哈希表)
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">缓存类型</typeparam>
|
||||||
|
/// <param name="key">缓存键</param>
|
||||||
|
/// <param name="field">字段</param>
|
||||||
|
/// <param name="timeoutSeconds">缓存秒数</param>
|
||||||
|
/// <param name="getData">获取源数据的函数</param>
|
||||||
|
/// <param name="serialize">序列化函数</param>
|
||||||
|
/// <param name="deserialize">反序列化函数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<T> ShellAsync<T>(string key, string field, int timeoutSeconds, Func<Task<T>> getDataAsync);
|
||||||
|
}
|
||||||
|
}
|
43
FreeSql/Interface/ICodeFirst.cs
Normal file
43
FreeSql/Interface/ICodeFirst.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface ICodeFirst {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 【开发环境必备】自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改
|
||||||
|
/// </summary>
|
||||||
|
bool IsAutoSyncStructure { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将实体类型与数据库对比,返回DDL语句
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TEntity"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
string GetComparisonDDLStatements<TEntity>();
|
||||||
|
/// <summary>
|
||||||
|
/// 将实体类型集合与数据库对比,返回DDL语句
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entityTypes"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string GetComparisonDDLStatements(params Type[] entityTypes);
|
||||||
|
/// <summary>
|
||||||
|
/// 同步实体类型到数据库
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TEntity"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool SyncStructure<TEntity>();
|
||||||
|
/// <summary>
|
||||||
|
/// 同步实体类型集合到数据库
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entityTypes"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool SyncStructure(params Type[] entityTypes);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据 System.Type 获取数据库信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
(int type, string dbtype, string dbtypeFull, bool? isnullable)? GetDbInfo(Type type);
|
||||||
|
}
|
||||||
|
}
|
100
FreeSql/Interface/IDasql.cs
Normal file
100
FreeSql/Interface/IDasql.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
using FreeSql;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
public interface IFreeSql {
|
||||||
|
/// <summary>
|
||||||
|
/// 插入数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
IInsert<T1> Insert<T1>() where T1 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 插入数据,传入实体
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <param name="source"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IInsert<T1> Insert<T1>(T1 source) where T1 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 插入数据,传入实体集合
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <param name="source"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 修改数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> Update<T1>() where T1 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 修改数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IUpdate<T1> Update<T1>(object dywhere) where T1 : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> Select<T1>() where T1 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 查询数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISelect<T1> Select<T1>(object dywhere) where T1 : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 删除数据
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDelete<T1> Delete<T1>() where T1 : class;
|
||||||
|
/// <summary>
|
||||||
|
/// 删除数据,传入动态对象如:主键值 | new[]{主键值1,主键值2} | TEntity1 | new[]{TEntity1,TEntity2} | new{id=1}
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T1"></typeparam>
|
||||||
|
/// <param name="dywhere">主键值、主键值集合、实体、实体集合、匿名对象、匿名对象集合</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
IDelete<T1> Delete<T1>(object dywhere) where T1 : class;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启事务(不支持异步),60秒未执行完将自动提交
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">事务体 () => {}</param>
|
||||||
|
void Transaction(Action handler);
|
||||||
|
/// <summary>
|
||||||
|
/// 开启事务(不支持异步)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">事务体 () => {}</param>
|
||||||
|
/// <param name="timeout">超时,未执行完将自动提交</param>
|
||||||
|
void Transaction(Action handler, TimeSpan timeout);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存
|
||||||
|
/// </summary>
|
||||||
|
ICache Cache { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库访问对象
|
||||||
|
/// </summary>
|
||||||
|
IAdo Ado { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CodeFirst 模式开发相关方法
|
||||||
|
/// </summary>
|
||||||
|
ICodeFirst CodeFirst { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// DbFirst 模式开发相关方法
|
||||||
|
/// </summary>
|
||||||
|
IDbFirst DbFirst { get; }
|
||||||
|
}
|
70
FreeSql/Interface/iDbFirst.cs
Normal file
70
FreeSql/Interface/iDbFirst.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
using FreeSql.DatabaseModel;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace FreeSql {
|
||||||
|
public interface IDbFirst {
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有数据库
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<string> GetDatabases();
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定数据库的表信息,包括表、列详情、主键、唯一键、索引、外键
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="database"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
List<DbTableInfo> GetTablesByDatabase(params string[] database);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取数据库枚举类型int值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int GetDbType(DbColumnInfo column);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取c#转换,(int)、(long)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string GetCsConvert(DbColumnInfo column);
|
||||||
|
/// <summary>
|
||||||
|
/// 获取c#值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string GetCsTypeValue(DbColumnInfo column);
|
||||||
|
/// <summary>
|
||||||
|
/// 获取c#类型,int、long
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string GetCsType(DbColumnInfo column);
|
||||||
|
/// <summary>
|
||||||
|
/// 获取c#类型对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Type GetCsTypeInfo(DbColumnInfo column);
|
||||||
|
/// <summary>
|
||||||
|
/// 获取ado.net读取方法, GetBoolean、GetInt64
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string GetDataReaderMethod(DbColumnInfo column);
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string GetCsStringify(DbColumnInfo column);
|
||||||
|
/// <summary>
|
||||||
|
/// 反序列化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="column"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
string GetCsParse(DbColumnInfo column);
|
||||||
|
}
|
||||||
|
}
|
256
FreeSql/Internal/CommonExpression.cs
Normal file
256
FreeSql/Internal/CommonExpression.cs
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal {
|
||||||
|
internal abstract class CommonExpression {
|
||||||
|
|
||||||
|
internal CommonUtils _common;
|
||||||
|
internal CommonExpression(CommonUtils common) {
|
||||||
|
_common = common;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool ReadAnonymousField(List<SelectTableInfo> _tables, StringBuilder field, ReadAnonymousTypeInfo parent, ref int index, Expression exp) {
|
||||||
|
switch (exp.NodeType) {
|
||||||
|
case ExpressionType.Quote: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand);
|
||||||
|
case ExpressionType.Lambda: return ReadAnonymousField(_tables, field, parent, ref index, (exp as LambdaExpression)?.Body);
|
||||||
|
case ExpressionType.Convert: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand);
|
||||||
|
case ExpressionType.Constant:
|
||||||
|
var constExp = exp as ConstantExpression;
|
||||||
|
field.Append(", ").Append(constExp?.Value).Append(" as").Append(++index);
|
||||||
|
return false;
|
||||||
|
case ExpressionType.MemberAccess:
|
||||||
|
var map = new List<SelectColumnInfo>();
|
||||||
|
ExpressionSelectColumn_MemberAccess(_tables, map, SelectTableInfoType.From, exp, true);
|
||||||
|
if (map.Count > 1) {
|
||||||
|
parent.Consturctor = map.First().Table.Table.Type.GetConstructor(new Type[0]);
|
||||||
|
parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
|
||||||
|
}
|
||||||
|
for (var idx = 0; idx < map.Count; idx++) {
|
||||||
|
field.Append(", ").Append(map[idx].Table.Alias).Append(".").Append(_common.QuoteSqlName(map[idx].Column.Attribute.Name)).Append(" as").Append(++index);
|
||||||
|
if (map.Count > 1) parent.Childs.Add(new ReadAnonymousTypeInfo { CsName = map[idx].Column.CsName });
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case ExpressionType.New:
|
||||||
|
var newExp = exp as NewExpression;
|
||||||
|
parent.Consturctor = newExp.Type.GetConstructors()[0];
|
||||||
|
parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Arguments;
|
||||||
|
for (var a = 0; a < newExp.Members.Count; a++) {
|
||||||
|
var child = new ReadAnonymousTypeInfo { CsName = newExp.Members[a].Name };
|
||||||
|
parent.Childs.Add(child);
|
||||||
|
ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
internal object ReadAnonymous(ReadAnonymousTypeInfo parent, object[] dr, ref int index) {
|
||||||
|
if (parent.Childs.Any() == false) return dr[++index];
|
||||||
|
switch (parent.ConsturctorType) {
|
||||||
|
case ReadAnonymousTypeInfoConsturctorType.Arguments:
|
||||||
|
var args = new object[parent.Childs.Count];
|
||||||
|
for (var a = 0; a < parent.Childs.Count; a++) {
|
||||||
|
args[a] = ReadAnonymous(parent.Childs[a], dr, ref index);
|
||||||
|
}
|
||||||
|
return parent.Consturctor.Invoke(args);
|
||||||
|
case ReadAnonymousTypeInfoConsturctorType.Properties:
|
||||||
|
var ret = parent.Consturctor.Invoke(null);
|
||||||
|
for (var b = 0; b < parent.Childs.Count; b++) {
|
||||||
|
Utils.FillPropertyValue(ret, parent.Childs[b].CsName, ReadAnonymous(parent.Childs[b], dr, ref index));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string ExpressionConstant(ConstantExpression exp) => _common.FormatSql("{0}", exp?.Value);
|
||||||
|
|
||||||
|
internal string ExpressionSelectColumn_MemberAccess(List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, Expression exp, bool isQuoteName) {
|
||||||
|
return ExpressionLambdaToSql(exp, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string[] ExpressionSelectColumns_MemberAccess_New_NewArrayInit(List<SelectTableInfo> _tables, Expression exp, bool isQuoteName) {
|
||||||
|
switch (exp?.NodeType) {
|
||||||
|
case ExpressionType.Quote: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName);
|
||||||
|
case ExpressionType.Lambda: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as LambdaExpression)?.Body, isQuoteName);
|
||||||
|
case ExpressionType.Convert: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName);
|
||||||
|
case ExpressionType.Constant: return new[] { ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, isQuoteName) };
|
||||||
|
case ExpressionType.MemberAccess: return new[] { ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, isQuoteName) };
|
||||||
|
case ExpressionType.New:
|
||||||
|
var newExp = exp as NewExpression;
|
||||||
|
if (newExp == null) break;
|
||||||
|
var newExpMembers = new string[newExp.Members.Count];
|
||||||
|
for (var a = 0; a < newExpMembers.Length; a++) newExpMembers[a] = ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, newExp.Arguments[a], isQuoteName);
|
||||||
|
return newExpMembers;
|
||||||
|
case ExpressionType.NewArrayInit:
|
||||||
|
var newArr = exp as NewArrayExpression;
|
||||||
|
if (newArr == null) break;
|
||||||
|
var newArrMembers = new List<string>();
|
||||||
|
foreach (var newArrExp in newArr.Expressions) newArrMembers.AddRange(ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, newArrExp, isQuoteName));
|
||||||
|
return newArrMembers.ToArray();
|
||||||
|
}
|
||||||
|
return new string[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly Dictionary<ExpressionType, string> dicExpressionOperator = new Dictionary<ExpressionType, string>() {
|
||||||
|
{ ExpressionType.OrElse, "OR" },
|
||||||
|
{ ExpressionType.Or, "|" },
|
||||||
|
{ ExpressionType.AndAlso, "AND" },
|
||||||
|
{ ExpressionType.And, "&" },
|
||||||
|
{ ExpressionType.GreaterThan, ">" },
|
||||||
|
{ ExpressionType.GreaterThanOrEqual, ">=" },
|
||||||
|
{ ExpressionType.LessThan, "<" },
|
||||||
|
{ ExpressionType.LessThanOrEqual, "<=" },
|
||||||
|
{ ExpressionType.NotEqual, "<>" },
|
||||||
|
{ ExpressionType.Add, "+" },
|
||||||
|
{ ExpressionType.Subtract, "-" },
|
||||||
|
{ ExpressionType.Multiply, "*" },
|
||||||
|
{ ExpressionType.Divide, "/" },
|
||||||
|
{ ExpressionType.Modulo, "%" },
|
||||||
|
{ ExpressionType.Equal, "=" },
|
||||||
|
};
|
||||||
|
internal string ExpressionWhereLambdaNoneForeignObject(List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, Expression exp) {
|
||||||
|
return ExpressionLambdaToSql(exp, _tables, _selectColumnMap, SelectTableInfoType.From, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string ExpressionWhereLambda(List<SelectTableInfo> _tables, Expression exp) {
|
||||||
|
return ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true);
|
||||||
|
}
|
||||||
|
internal void ExpressionJoinLambda(List<SelectTableInfo> _tables, SelectTableInfoType tbtype, Expression exp) {
|
||||||
|
var tbidx = _tables.Count;
|
||||||
|
var filter = ExpressionLambdaToSql(exp, _tables, null, tbtype, true);
|
||||||
|
if (_tables.Count > tbidx) {
|
||||||
|
_tables[tbidx].Type = tbtype;
|
||||||
|
_tables[tbidx].On = filter;
|
||||||
|
for (var a = tbidx + 1; a < _tables.Count; a++)
|
||||||
|
_tables[a].Type = SelectTableInfoType.From;
|
||||||
|
} else {
|
||||||
|
var find = _tables.Where((a, c) => c > 0 && a.Type == tbtype && string.IsNullOrEmpty(a.On)).LastOrDefault();
|
||||||
|
if (find != null) find.On = filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string ExpressionLambdaToSql(Expression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) {
|
||||||
|
switch( exp.NodeType) {
|
||||||
|
case ExpressionType.Quote: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
case ExpressionType.Lambda: return ExpressionLambdaToSql((exp as LambdaExpression)?.Body, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
case ExpressionType.Convert: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
case ExpressionType.Constant: return _common.FormatSql("{0}", (exp as ConstantExpression)?.Value);
|
||||||
|
case ExpressionType.MemberAccess:
|
||||||
|
var expStack = new Stack<Expression>();
|
||||||
|
expStack.Push(exp);
|
||||||
|
MethodCallExpression callExp = null;
|
||||||
|
var exp2 = (exp as MemberExpression).Expression;
|
||||||
|
while (true) {
|
||||||
|
switch(exp2.NodeType) {
|
||||||
|
case ExpressionType.Constant:
|
||||||
|
expStack.Push(exp2);
|
||||||
|
break;
|
||||||
|
case ExpressionType.Parameter:
|
||||||
|
expStack.Push(exp2);
|
||||||
|
break;
|
||||||
|
case ExpressionType.MemberAccess:
|
||||||
|
expStack.Push(exp2);
|
||||||
|
exp2 = (exp2 as MemberExpression).Expression;
|
||||||
|
if (exp2 == null) break;
|
||||||
|
continue;
|
||||||
|
case ExpressionType.Call:
|
||||||
|
callExp = exp2 as MethodCallExpression;
|
||||||
|
expStack.Push(exp2);
|
||||||
|
exp2 = callExp.Object;
|
||||||
|
if (exp2 == null) break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (expStack.First().NodeType != ExpressionType.Parameter) return _common.FormatSql("{0}", Expression.Lambda(exp).Compile().DynamicInvoke());
|
||||||
|
if (callExp != null) return ExpressionLambdaToSqlCall(callExp, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
if (_tables == null) {
|
||||||
|
var pp = expStack.Pop() as ParameterExpression;
|
||||||
|
var memberExp = expStack.Pop() as MemberExpression;
|
||||||
|
var tb = _common.GetTableByEntity(pp.Type);
|
||||||
|
if (tb.ColumnsByCs.ContainsKey(memberExp.Member.Name) == false) throw new ArgumentException($"{tb.DbName} 找不到列 {memberExp.Member.Name}");
|
||||||
|
if (_selectColumnMap != null) {
|
||||||
|
_selectColumnMap.Add(new SelectColumnInfo { Table = null, Column = tb.ColumnsByCs[memberExp.Member.Name] });
|
||||||
|
}
|
||||||
|
var name = tb.ColumnsByCs[memberExp.Member.Name].Attribute.Name;
|
||||||
|
if (isQuoteName) name = _common.QuoteSqlName(name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableInfo tb2 = null;
|
||||||
|
string alias2 = "", name2 = "";
|
||||||
|
SelectTableInfo find2 = null;
|
||||||
|
while (expStack.Count > 0) {
|
||||||
|
exp2 = expStack.Pop();
|
||||||
|
switch (exp2.NodeType) {
|
||||||
|
case ExpressionType.Constant:
|
||||||
|
throw new NotImplementedException("未现实 MemberAccess 下的 Constant");
|
||||||
|
case ExpressionType.Parameter:
|
||||||
|
case ExpressionType.MemberAccess:
|
||||||
|
var tb2tmp = _common.GetTableByEntity(exp2.Type);
|
||||||
|
var mp2 = exp2 as MemberExpression;
|
||||||
|
if (tb2tmp != null) {
|
||||||
|
if (exp2.NodeType == ExpressionType.Parameter) alias2 = (exp2 as ParameterExpression).Name;
|
||||||
|
else alias2 = $"{alias2}__{mp2.Member.Name}";
|
||||||
|
var find2s = _tables.Where((a2, c2) => a2.Table.CsName == tb2tmp.CsName).ToArray();
|
||||||
|
if (find2s.Length > 1) find2s = _tables.Where((a2, c2) => a2.Table.CsName == tb2tmp.CsName && a2.Alias == alias2).ToArray();
|
||||||
|
find2 = find2s.FirstOrDefault();
|
||||||
|
if (find2 == null) _tables.Add(find2 = new SelectTableInfo { Table = tb2tmp, Alias = alias2, On = null, Type = tbtype });
|
||||||
|
alias2 = find2.Alias;
|
||||||
|
tb2 = tb2tmp;
|
||||||
|
}
|
||||||
|
if (mp2 == null || expStack.Any()) continue;
|
||||||
|
if (tb2.ColumnsByCs.ContainsKey(mp2.Member.Name) == false) { //如果选的是对象,附加所有列
|
||||||
|
if (_selectColumnMap != null) {
|
||||||
|
var tb3 = _common.GetTableByEntity(mp2.Type);
|
||||||
|
if (tb3 != null) {
|
||||||
|
var alias3 = $"{alias2}__{mp2.Member.Name}";
|
||||||
|
var find3s = _tables.Where((a3, c3) => a3.Table.CsName == tb3.CsName).ToArray();
|
||||||
|
if (find3s.Length > 1) find3s = _tables.Where((a3, c3) => a3.Table.CsName == tb3.CsName && a3.Alias == alias3).ToArray();
|
||||||
|
var find3 = find3s.FirstOrDefault();
|
||||||
|
if (find3 == null) _tables.Add(find3 = new SelectTableInfo { Table = tb3, Alias = alias3, On = null, Type = tbtype });
|
||||||
|
alias3 = find3.Alias;
|
||||||
|
|
||||||
|
foreach (var tb3c in tb3.Columns.Values)
|
||||||
|
_selectColumnMap.Add(new SelectColumnInfo { Table = find3, Column = tb3c });
|
||||||
|
if (tb3.Columns.Any()) return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"{tb2.DbName} 找不到列 {mp2.Member.Name}");
|
||||||
|
}
|
||||||
|
var col2 = tb2.ColumnsByCs[mp2.Member.Name];
|
||||||
|
if (_selectColumnMap != null && find2 != null) {
|
||||||
|
_selectColumnMap.Add(new SelectColumnInfo { Table = find2, Column = col2 });
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
name2 = tb2.ColumnsByCs[mp2.Member.Name].Attribute.Name;
|
||||||
|
break;
|
||||||
|
case ExpressionType.Call:break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isQuoteName) name2 = _common.QuoteSqlName(name2);
|
||||||
|
return $"{alias2}.{name2}";
|
||||||
|
case ExpressionType.Call: return ExpressionLambdaToSqlCall(exp as MethodCallExpression, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
}
|
||||||
|
if (dicExpressionOperator.TryGetValue(exp.NodeType, out var tryoper) == false) return "";
|
||||||
|
var expBinary = exp as BinaryExpression;
|
||||||
|
if (expBinary == null) return "";
|
||||||
|
var left = ExpressionLambdaToSql(expBinary.Left, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
var right = ExpressionLambdaToSql(expBinary.Right, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
if (left == "NULL") {
|
||||||
|
var tmp = right;
|
||||||
|
right = left;
|
||||||
|
left = tmp;
|
||||||
|
}
|
||||||
|
if (right == "NULL") tryoper = tryoper == "=" ? " IS " : " IS NOT ";
|
||||||
|
return $"{left} {tryoper} {right}";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract string ExpressionLambdaToSqlCall(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
267
FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs
Normal file
267
FreeSql/Internal/CommonProvider/AdoProvider/AdoProvider.cs
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SafeObjectPool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
abstract partial class AdoProvider : IAdo {
|
||||||
|
|
||||||
|
protected abstract void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex);
|
||||||
|
protected abstract DbCommand CreateCommand();
|
||||||
|
protected abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
|
||||||
|
|
||||||
|
public bool IsTracePerformance { get; set; } = string.Compare(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), "Development", true) == 0;
|
||||||
|
|
||||||
|
public ObjectPool<DbConnection> MasterPool { get; protected set; }
|
||||||
|
public List<ObjectPool<DbConnection>> SlavePools { get; } = new List<ObjectPool<DbConnection>>();
|
||||||
|
protected ICache _cache { get; set; }
|
||||||
|
protected ILogger _log { get; set; }
|
||||||
|
protected int slaveUnavailables = 0;
|
||||||
|
private object slaveLock = new object();
|
||||||
|
private Random slaveRandom = new Random();
|
||||||
|
|
||||||
|
public AdoProvider(ICache cache, ILogger log) {
|
||||||
|
this._cache = cache;
|
||||||
|
this._log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoggerException(ObjectPool<DbConnection> pool, DbCommand cmd, Exception e, DateTime dt, string logtxt, bool isThrowException = true) {
|
||||||
|
if (IsTracePerformance) {
|
||||||
|
TimeSpan ts = DateTime.Now.Subtract(dt);
|
||||||
|
if (e == null && ts.TotalMilliseconds > 100)
|
||||||
|
_log.LogWarning($"{pool.Policy.Name}执行SQL语句耗时过长{ts.TotalMilliseconds}ms\r\n{cmd.CommandText}\r\n{logtxt}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e == null) return;
|
||||||
|
string log = $"{pool.Policy.Name}数据库出错(执行SQL)〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓\r\n{cmd.CommandText}\r\n";
|
||||||
|
foreach (DbParameter parm in cmd.Parameters)
|
||||||
|
log += parm.ParameterName.PadRight(20, ' ') + " = " + (parm.Value ?? "NULL") + "\r\n";
|
||||||
|
|
||||||
|
log += e.Message;
|
||||||
|
_log.LogError(log);
|
||||||
|
|
||||||
|
RollbackTransaction();
|
||||||
|
cmd.Parameters.Clear();
|
||||||
|
if (isThrowException) throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> Query<T>(string sql, object parms = null) => Query<T>(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
public List<T> Query<T>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
var names = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
var ds = new List<object[]>();
|
||||||
|
ExecuteReader(dr => {
|
||||||
|
if (names.Any() == false)
|
||||||
|
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
|
||||||
|
object[] values = new object[dr.FieldCount];
|
||||||
|
dr.GetValues(values);
|
||||||
|
ds.Add(values);
|
||||||
|
}, cmdType, cmdText, cmdParms);
|
||||||
|
var ret = new List<T>();
|
||||||
|
foreach (var row in ds) {
|
||||||
|
var read = Utils.ExecuteArrayRowReadClassOrTuple(typeof(T), names, row);
|
||||||
|
ret.Add(read.value == null ? default(T) : (T) read.value);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public void ExecuteReader(Action<DbDataReader> readerHander, string sql, object parms = null) => ExecuteReader(readerHander, CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
public void ExecuteReader(Action<DbDataReader> readerHander, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
DateTime dt = DateTime.Now;
|
||||||
|
string logtxt = "";
|
||||||
|
DateTime logtxt_dt = DateTime.Now;
|
||||||
|
var pool = this.MasterPool;
|
||||||
|
bool isSlave = false;
|
||||||
|
|
||||||
|
//读写分离规则
|
||||||
|
if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) {
|
||||||
|
var availables = slaveUnavailables == 0 ?
|
||||||
|
//查从库
|
||||||
|
this.SlavePools : (
|
||||||
|
//查主库
|
||||||
|
slaveUnavailables == this.SlavePools.Count ? new List<ObjectPool<DbConnection>>() :
|
||||||
|
//查从库可用
|
||||||
|
this.SlavePools.Where(sp => sp.IsAvailable).ToList());
|
||||||
|
if (availables.Any()) {
|
||||||
|
isSlave = true;
|
||||||
|
pool = availables.Count == 1 ? availables[0] : availables[slaveRandom.Next(availables.Count)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object<DbConnection> conn = null;
|
||||||
|
var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt);
|
||||||
|
if (IsTracePerformance) logtxt += $"PrepareCommand: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
Exception ex = null;
|
||||||
|
try {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
if (isSlave) {
|
||||||
|
//从库查询切换,恢复
|
||||||
|
bool isSlaveFail = false;
|
||||||
|
try {
|
||||||
|
if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = pool.Get()).Value;
|
||||||
|
//if (slaveRandom.Next(100) % 2 == 0) throw new Exception("测试从库抛出异常");
|
||||||
|
} catch {
|
||||||
|
isSlaveFail = true;
|
||||||
|
}
|
||||||
|
if (isSlaveFail) {
|
||||||
|
if (conn != null) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
ReturnConnection(pool, conn, ex); //pool.Return(conn, ex);
|
||||||
|
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||||
|
}
|
||||||
|
LoggerException(pool, pc.cmd, new Exception($"连接失败,准备切换其他可用服务器"), dt, logtxt, false);
|
||||||
|
pc.cmd.Parameters.Clear();
|
||||||
|
ExecuteReader(readerHander, cmdType, cmdText, cmdParms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//主库查询
|
||||||
|
if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = pool.Get()).Value;
|
||||||
|
}
|
||||||
|
if (IsTracePerformance) {
|
||||||
|
logtxt += $"Open: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
logtxt_dt = DateTime.Now;
|
||||||
|
}
|
||||||
|
using (var dr = pc.cmd.ExecuteReader()) {
|
||||||
|
if (IsTracePerformance) logtxt += $"ExecuteReader: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
while (true) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
bool isread = dr.Read();
|
||||||
|
if (IsTracePerformance) logtxt += $" dr.Read: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
if (isread == false) break;
|
||||||
|
|
||||||
|
if (readerHander != null) {
|
||||||
|
object[] values = null;
|
||||||
|
if (IsTracePerformance) {
|
||||||
|
logtxt_dt = DateTime.Now;
|
||||||
|
values = new object[dr.FieldCount];
|
||||||
|
dr.GetValues(values);
|
||||||
|
logtxt += $" dr.GetValues: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
logtxt_dt = DateTime.Now;
|
||||||
|
}
|
||||||
|
readerHander(dr);
|
||||||
|
if (IsTracePerformance) logtxt += $" readerHander: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms ({string.Join(",", values)})\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
dr.Close();
|
||||||
|
}
|
||||||
|
if (IsTracePerformance) logtxt += $"ExecuteReader_dispose: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
} catch (Exception ex2) {
|
||||||
|
ex = ex2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn != null) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
ReturnConnection(pool, conn, ex); //pool.Return(conn, ex);
|
||||||
|
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||||
|
}
|
||||||
|
LoggerException(pool, pc.cmd, ex, dt, logtxt);
|
||||||
|
pc.cmd.Parameters.Clear();
|
||||||
|
}
|
||||||
|
public object[][] ExecuteArray(string sql, object parms = null) => ExecuteArray(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
public object[][] ExecuteArray(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
List<object[]> ret = new List<object[]>();
|
||||||
|
ExecuteReader(dr => {
|
||||||
|
object[] values = new object[dr.FieldCount];
|
||||||
|
dr.GetValues(values);
|
||||||
|
ret.Add(values);
|
||||||
|
}, cmdType, cmdText, cmdParms);
|
||||||
|
return ret.ToArray();
|
||||||
|
}
|
||||||
|
public DataTable ExecuteDataTable(string sql, object parms = null) => ExecuteDataTable(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
public DataTable ExecuteDataTable(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
var ret = new DataTable();
|
||||||
|
ExecuteReader(dr => {
|
||||||
|
if (ret.Columns.Count == 0)
|
||||||
|
for (var a = 0; a < dr.FieldCount; a++) ret.Columns.Add(dr.GetName(a));
|
||||||
|
object[] values = new object[ret.Columns.Count];
|
||||||
|
dr.GetValues(values);
|
||||||
|
ret.Rows.Add(values);
|
||||||
|
}, cmdType, cmdText, cmdParms);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public int ExecuteNonQuery(string sql, object parms = null) => ExecuteNonQuery(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
public int ExecuteNonQuery(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
DateTime dt = DateTime.Now;
|
||||||
|
string logtxt = "";
|
||||||
|
DateTime logtxt_dt = DateTime.Now;
|
||||||
|
Object<DbConnection> conn = null;
|
||||||
|
var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt);
|
||||||
|
int val = 0;
|
||||||
|
Exception ex = null;
|
||||||
|
try {
|
||||||
|
if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = this.MasterPool.Get()).Value;
|
||||||
|
val = pc.cmd.ExecuteNonQuery();
|
||||||
|
} catch (Exception ex2) {
|
||||||
|
ex = ex2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn != null) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex);
|
||||||
|
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||||
|
}
|
||||||
|
LoggerException(this.MasterPool, pc.cmd, ex, dt, logtxt);
|
||||||
|
pc.cmd.Parameters.Clear();
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public object ExecuteScalar(string sql, object parms = null) => ExecuteScalar(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
public object ExecuteScalar(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
DateTime dt = DateTime.Now;
|
||||||
|
string logtxt = "";
|
||||||
|
DateTime logtxt_dt = DateTime.Now;
|
||||||
|
Object<DbConnection> conn = null;
|
||||||
|
var pc = PrepareCommand(cmdType, cmdText, cmdParms, ref logtxt);
|
||||||
|
object val = null;
|
||||||
|
Exception ex = null;
|
||||||
|
try {
|
||||||
|
if (pc.cmd.Connection == null) pc.cmd.Connection = (conn = this.MasterPool.Get()).Value;
|
||||||
|
val = pc.cmd.ExecuteScalar();
|
||||||
|
} catch (Exception ex2) {
|
||||||
|
ex = ex2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn != null) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex);
|
||||||
|
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||||
|
}
|
||||||
|
LoggerException(this.MasterPool, pc.cmd, ex, dt, logtxt);
|
||||||
|
pc.cmd.Parameters.Clear();
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private (DbTransaction tran, DbCommand cmd) PrepareCommand(CommandType cmdType, string cmdText, DbParameter[] cmdParms, ref string logtxt) {
|
||||||
|
var dt = DateTime.Now;
|
||||||
|
DbCommand cmd = CreateCommand();
|
||||||
|
cmd.CommandType = cmdType;
|
||||||
|
cmd.CommandText = cmdText;
|
||||||
|
|
||||||
|
if (cmdParms != null) {
|
||||||
|
foreach (var parm in cmdParms) {
|
||||||
|
if (parm == null) continue;
|
||||||
|
if (parm.Value == null) parm.Value = DBNull.Value;
|
||||||
|
cmd.Parameters.Add(parm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tran = TransactionCurrentThread;
|
||||||
|
if (IsTracePerformance) logtxt += $" PrepareCommand_part1: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms cmdParms: {cmdParms.Length}\r\n";
|
||||||
|
|
||||||
|
if (tran != null) {
|
||||||
|
if (IsTracePerformance) dt = DateTime.Now;
|
||||||
|
cmd.Connection = tran.Connection;
|
||||||
|
cmd.Transaction = tran;
|
||||||
|
if (IsTracePerformance) logtxt += $" PrepareCommand_tran!=null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsTracePerformance) dt = DateTime.Now;
|
||||||
|
AutoCommitTransaction();
|
||||||
|
if (IsTracePerformance) logtxt += $" AutoCommitTransaction: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
|
||||||
|
return (tran, cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
215
FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs
Normal file
215
FreeSql/Internal/CommonProvider/AdoProvider/AdoProviderAsync.cs
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
using SafeObjectPool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
partial class AdoProvider {
|
||||||
|
public Task<List<T>> QueryAsync<T>(string sql, object parms = null) => QueryAsync<T>(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
async public Task<List<T>> QueryAsync<T>(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
var names = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
var ds = new List<object[]>();
|
||||||
|
await ExecuteReaderAsync(async dr => {
|
||||||
|
if (names.Any() == false)
|
||||||
|
for (var a = 0; a < dr.FieldCount; a++) names.Add(dr.GetName(a), a);
|
||||||
|
object[] values = new object[dr.FieldCount];
|
||||||
|
for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync<object>(a);
|
||||||
|
ds.Add(values);
|
||||||
|
}, cmdType, cmdText, cmdParms);
|
||||||
|
var ret = new List<T>();
|
||||||
|
foreach (var row in ds) {
|
||||||
|
var read = Utils.ExecuteArrayRowReadClassOrTuple(typeof(T), names, row);
|
||||||
|
ret.Add(read.value == null ? default(T) : (T) read.value);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public Task ExecuteReaderAsync(Func<DbDataReader, Task> readerHander, string sql, object parms = null) => ExecuteReaderAsync(readerHander, CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
async public Task ExecuteReaderAsync(Func<DbDataReader, Task> readerHander, CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
DateTime dt = DateTime.Now;
|
||||||
|
string logtxt = "";
|
||||||
|
DateTime logtxt_dt = DateTime.Now;
|
||||||
|
var pool = this.MasterPool;
|
||||||
|
bool isSlave = false;
|
||||||
|
|
||||||
|
//读写分离规则
|
||||||
|
if (this.SlavePools.Any() && cmdText.StartsWith("SELECT ", StringComparison.CurrentCultureIgnoreCase)) {
|
||||||
|
var availables = slaveUnavailables == 0 ?
|
||||||
|
//查从库
|
||||||
|
this.SlavePools : (
|
||||||
|
//查主库
|
||||||
|
slaveUnavailables == this.SlavePools.Count ? new List<ObjectPool<DbConnection>>() :
|
||||||
|
//查从库可用
|
||||||
|
this.SlavePools.Where(sp => sp.IsAvailable).ToList());
|
||||||
|
if (availables.Any()) {
|
||||||
|
isSlave = true;
|
||||||
|
pool = availables.Count == 1 ? this.SlavePools[0] : availables[slaveRandom.Next(availables.Count)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object<DbConnection> conn = null;
|
||||||
|
var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt);
|
||||||
|
if (IsTracePerformance) logtxt += $"PrepareCommand: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
Exception ex = null;
|
||||||
|
try {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
if (isSlave) {
|
||||||
|
//从库查询切换,恢复
|
||||||
|
bool isSlaveFail = false;
|
||||||
|
try {
|
||||||
|
if (cmd.Connection == null) cmd.Connection = (conn = await pool.GetAsync()).Value;
|
||||||
|
//if (slaveRandom.Next(100) % 2 == 0) throw new Exception("测试从库抛出异常");
|
||||||
|
} catch {
|
||||||
|
isSlaveFail = true;
|
||||||
|
}
|
||||||
|
if (isSlaveFail) {
|
||||||
|
if (conn != null) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
ReturnConnection(pool, conn, ex); //pool.Return(conn, ex);
|
||||||
|
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||||
|
}
|
||||||
|
LoggerException(pool, cmd, new Exception($"连接失败,准备切换其他可用服务器"), dt, logtxt, false);
|
||||||
|
cmd.Parameters.Clear();
|
||||||
|
await ExecuteReaderAsync(readerHander, cmdType, cmdText, cmdParms);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//主库查询
|
||||||
|
if (cmd.Connection == null) cmd.Connection = (conn = await pool.GetAsync()).Value;
|
||||||
|
}
|
||||||
|
if (IsTracePerformance) {
|
||||||
|
logtxt += $"Open: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
logtxt_dt = DateTime.Now;
|
||||||
|
}
|
||||||
|
using (var dr = await cmd.ExecuteReaderAsync()) {
|
||||||
|
if (IsTracePerformance) logtxt += $"ExecuteReader: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
while (true) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
bool isread = await dr.ReadAsync();
|
||||||
|
if (IsTracePerformance) logtxt += $" dr.Read: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
if (isread == false) break;
|
||||||
|
|
||||||
|
if (readerHander != null) {
|
||||||
|
object[] values = null;
|
||||||
|
if (IsTracePerformance) {
|
||||||
|
logtxt_dt = DateTime.Now;
|
||||||
|
values = new object[dr.FieldCount];
|
||||||
|
for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync<object>(a);
|
||||||
|
logtxt += $" dr.GetValues: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
logtxt_dt = DateTime.Now;
|
||||||
|
}
|
||||||
|
await readerHander(dr);
|
||||||
|
if (IsTracePerformance) logtxt += $" readerHander: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms ({string.Join(",", values)})\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
dr.Close();
|
||||||
|
}
|
||||||
|
if (IsTracePerformance) logtxt += $"ExecuteReader_dispose: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
} catch (Exception ex2) {
|
||||||
|
ex = ex2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn != null) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
ReturnConnection(pool, conn, ex); //pool.Return(conn, ex);
|
||||||
|
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||||
|
}
|
||||||
|
LoggerException(pool, cmd, ex, dt, logtxt);
|
||||||
|
cmd.Parameters.Clear();
|
||||||
|
}
|
||||||
|
public Task ExecuteArrayAsync(string sql, object parms = null) => ExecuteArrayAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
async public Task<object[][]> ExecuteArrayAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
List<object[]> ret = new List<object[]>();
|
||||||
|
await ExecuteReaderAsync(async dr => {
|
||||||
|
object[] values = new object[dr.FieldCount];
|
||||||
|
for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync<object>(a);
|
||||||
|
ret.Add(values);
|
||||||
|
}, cmdType, cmdText, cmdParms);
|
||||||
|
return ret.ToArray();
|
||||||
|
}
|
||||||
|
public Task<DataTable> ExecuteDataTableAsync(string sql, object parms = null) => ExecuteDataTableAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
async public Task<DataTable> ExecuteDataTableAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
var ret = new DataTable();
|
||||||
|
await ExecuteReaderAsync(async dr => {
|
||||||
|
if (ret.Columns.Count == 0)
|
||||||
|
for (var a = 0; a < dr.FieldCount; a++) ret.Columns.Add(dr.GetName(a));
|
||||||
|
object[] values = new object[ret.Columns.Count];
|
||||||
|
for (int a = 0; a < values.Length; a++) if (!await dr.IsDBNullAsync(a)) values[a] = await dr.GetFieldValueAsync<object>(a);
|
||||||
|
ret.Rows.Add(values);
|
||||||
|
}, cmdType, cmdText, cmdParms);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public Task<int> ExecuteNonQueryAsync(string sql, object parms = null) => ExecuteNonQueryAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
async public Task<int> ExecuteNonQueryAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
DateTime dt = DateTime.Now;
|
||||||
|
string logtxt = "";
|
||||||
|
Object<DbConnection> conn = null;
|
||||||
|
var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt);
|
||||||
|
var logtxt_dt = DateTime.Now;
|
||||||
|
int val = 0;
|
||||||
|
Exception ex = null;
|
||||||
|
try {
|
||||||
|
if (cmd.Connection == null) cmd.Connection = (conn = await this.MasterPool.GetAsync()).Value;
|
||||||
|
val = await cmd.ExecuteNonQueryAsync();
|
||||||
|
} catch (Exception ex2) {
|
||||||
|
ex = ex2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn != null) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex);
|
||||||
|
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||||
|
}
|
||||||
|
LoggerException(this.MasterPool, cmd, ex, dt, logtxt);
|
||||||
|
cmd.Parameters.Clear();
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public Task<object> ExecuteScalarAsync(string sql, object parms = null) => ExecuteScalarAsync(CommandType.Text, sql, GetDbParamtersByObject(sql, parms));
|
||||||
|
async public Task<object> ExecuteScalarAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms) {
|
||||||
|
var dt = DateTime.Now;
|
||||||
|
var logtxt = "";
|
||||||
|
Object<DbConnection> conn = null;
|
||||||
|
var cmd = PrepareCommandAsync(cmdType, cmdText, cmdParms, ref logtxt);
|
||||||
|
var logtxt_dt = DateTime.Now;
|
||||||
|
object val = null;
|
||||||
|
Exception ex = null;
|
||||||
|
try {
|
||||||
|
if (cmd.Connection == null) cmd.Connection = (conn = await this.MasterPool.GetAsync()).Value;
|
||||||
|
val = await cmd.ExecuteScalarAsync();
|
||||||
|
} catch (Exception ex2) {
|
||||||
|
ex = ex2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn != null) {
|
||||||
|
if (IsTracePerformance) logtxt_dt = DateTime.Now;
|
||||||
|
ReturnConnection(MasterPool, conn, ex); //this.MasterPool.Return(conn, ex);
|
||||||
|
if (IsTracePerformance) logtxt += $"ReleaseConnection: {DateTime.Now.Subtract(logtxt_dt).TotalMilliseconds}ms Total: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms";
|
||||||
|
}
|
||||||
|
LoggerException(this.MasterPool, cmd, ex, dt, logtxt);
|
||||||
|
cmd.Parameters.Clear();
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DbCommand PrepareCommandAsync(CommandType cmdType, string cmdText, DbParameter[] cmdParms, ref string logtxt) {
|
||||||
|
DateTime dt = DateTime.Now;
|
||||||
|
DbCommand cmd = CreateCommand();
|
||||||
|
cmd.CommandType = cmdType;
|
||||||
|
cmd.CommandText = cmdText;
|
||||||
|
|
||||||
|
if (cmdParms != null) {
|
||||||
|
foreach (var parm in cmdParms) {
|
||||||
|
if (parm == null) continue;
|
||||||
|
if (parm.Value == null) parm.Value = DBNull.Value;
|
||||||
|
cmd.Parameters.Add(parm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsTracePerformance) logtxt += $" PrepareCommand_tran==null: {DateTime.Now.Subtract(dt).TotalMilliseconds}ms\r\n";
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SafeObjectPool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
partial class AdoProvider {
|
||||||
|
|
||||||
|
class Transaction2 {
|
||||||
|
internal Object<DbConnection> Conn;
|
||||||
|
internal DbTransaction Transaction;
|
||||||
|
internal DateTime RunTime;
|
||||||
|
internal TimeSpan Timeout;
|
||||||
|
|
||||||
|
public Transaction2(Object<DbConnection> conn, DbTransaction tran, TimeSpan timeout) {
|
||||||
|
Conn = conn;
|
||||||
|
Transaction = tran;
|
||||||
|
RunTime = DateTime.Now;
|
||||||
|
Timeout = timeout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<int, Transaction2> _trans = new Dictionary<int, Transaction2>();
|
||||||
|
private object _trans_lock = new object();
|
||||||
|
|
||||||
|
public DbTransaction TransactionCurrentThread => _trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var conn) && conn.Transaction?.Connection != null ? conn.Transaction : null;
|
||||||
|
|
||||||
|
private Dictionary<int, List<string>> _preRemoveKeys = new Dictionary<int, List<string>>();
|
||||||
|
private object _preRemoveKeys_lock = new object();
|
||||||
|
public string[] PreRemove(params string[] key) {
|
||||||
|
var tid = Thread.CurrentThread.ManagedThreadId;
|
||||||
|
List<string> keys = null;
|
||||||
|
if (key == null || key.Any() == false) return _preRemoveKeys.TryGetValue(tid, out keys) ? keys.ToArray() : new string[0];
|
||||||
|
_log.LogDebug($"线程{tid}事务预删除 {JsonConvert.SerializeObject(key)}");
|
||||||
|
if (_preRemoveKeys.TryGetValue(tid, out keys) == false)
|
||||||
|
lock (_preRemoveKeys_lock)
|
||||||
|
if (_preRemoveKeys.TryGetValue(tid, out keys) == false) {
|
||||||
|
_preRemoveKeys.Add(tid, keys = new List<string>(key));
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
keys.AddRange(key);
|
||||||
|
return keys.ToArray();
|
||||||
|
}
|
||||||
|
public void TransactionPreRemoveCache(params string[] key) => PreRemove(key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动事务
|
||||||
|
/// </summary>
|
||||||
|
public void BeginTransaction(TimeSpan timeout) {
|
||||||
|
int tid = Thread.CurrentThread.ManagedThreadId;
|
||||||
|
Transaction2 tran = null;
|
||||||
|
Object<DbConnection> conn = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
conn = MasterPool.Get();
|
||||||
|
tran = new Transaction2(conn, conn.Value.BeginTransaction(), timeout);
|
||||||
|
} catch(Exception ex) {
|
||||||
|
_log.LogError($"数据库出错(开启事务){ex.Message} \r\n{ex.StackTrace}");
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
if (_trans.ContainsKey(tid)) CommitTransaction();
|
||||||
|
|
||||||
|
lock (_trans_lock)
|
||||||
|
_trans.Add(tid, tran);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 自动提交事务
|
||||||
|
/// </summary>
|
||||||
|
private void AutoCommitTransaction() {
|
||||||
|
if (_trans.Count > 0) {
|
||||||
|
Transaction2[] trans = null;
|
||||||
|
lock (_trans_lock)
|
||||||
|
trans = _trans.Values.Where(st2 => DateTime.Now.Subtract(st2.RunTime) > st2.Timeout).ToArray();
|
||||||
|
foreach (Transaction2 tran in trans) CommitTransaction(true, tran);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void CommitTransaction(bool isCommit, Transaction2 tran) {
|
||||||
|
if (tran == null || tran.Transaction == null || tran.Transaction.Connection == null) return;
|
||||||
|
|
||||||
|
if (_trans.ContainsKey(tran.Conn.LastGetThreadId))
|
||||||
|
lock (_trans_lock)
|
||||||
|
if (_trans.ContainsKey(tran.Conn.LastGetThreadId))
|
||||||
|
_trans.Remove(tran.Conn.LastGetThreadId);
|
||||||
|
|
||||||
|
var removeKeys = PreRemove();
|
||||||
|
if (_preRemoveKeys.ContainsKey(tran.Conn.LastGetThreadId))
|
||||||
|
lock (_preRemoveKeys_lock)
|
||||||
|
if (_preRemoveKeys.ContainsKey(tran.Conn.LastGetThreadId))
|
||||||
|
_preRemoveKeys.Remove(tran.Conn.LastGetThreadId);
|
||||||
|
|
||||||
|
Exception ex = null;
|
||||||
|
var f001 = isCommit ? "提交" : "回滚";
|
||||||
|
try {
|
||||||
|
_log.LogDebug($"线程{tran.Conn.LastGetThreadId}事务{f001},批量删除缓存key {Newtonsoft.Json.JsonConvert.SerializeObject(removeKeys)}");
|
||||||
|
_cache.Remove(removeKeys);
|
||||||
|
if (isCommit) tran.Transaction.Commit();
|
||||||
|
else tran.Transaction.Rollback();
|
||||||
|
} catch (Exception ex2) {
|
||||||
|
ex = ex2;
|
||||||
|
_log.LogError($"数据库出错({f001}事务):{ex.Message} {ex.StackTrace}");
|
||||||
|
} finally {
|
||||||
|
ReturnConnection(MasterPool, tran.Conn, ex); //MasterPool.Return(tran.Conn, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void CommitTransaction(bool isCommit) {
|
||||||
|
if (_trans.TryGetValue(Thread.CurrentThread.ManagedThreadId, out var tran)) CommitTransaction(isCommit, tran);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 提交事务
|
||||||
|
/// </summary>
|
||||||
|
public void CommitTransaction() => CommitTransaction(true);
|
||||||
|
/// <summary>
|
||||||
|
/// 回滚事务
|
||||||
|
/// </summary>
|
||||||
|
public void RollbackTransaction() => CommitTransaction(false);
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
Transaction2[] trans = null;
|
||||||
|
lock (_trans_lock)
|
||||||
|
trans = _trans.Values.ToArray();
|
||||||
|
foreach (Transaction2 tran in trans) CommitTransaction(false, tran);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启事务(不支持异步),60秒未执行完将自动提交
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">事务体 () => {}</param>
|
||||||
|
public void Transaction(Action handler) {
|
||||||
|
Transaction(handler, TimeSpan.FromSeconds(60));
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 开启事务(不支持异步)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler">事务体 () => {}</param>
|
||||||
|
/// <param name="timeout">超时,未执行完将自动提交</param>
|
||||||
|
public void Transaction(Action handler, TimeSpan timeout) {
|
||||||
|
try {
|
||||||
|
BeginTransaction(timeout);
|
||||||
|
handler();
|
||||||
|
CommitTransaction();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
RollbackTransaction();
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
partial class AdoProvider {
|
||||||
|
|
||||||
|
public abstract object AddslashesProcessParam(object param);
|
||||||
|
public string Addslashes(string filter, params object[] parms) {
|
||||||
|
if (filter == null || parms == null) return string.Empty;
|
||||||
|
if (parms.Length == 0) return filter;
|
||||||
|
var nparms = new object[parms.Length];
|
||||||
|
for (int a = 0; a < parms.Length; a++) {
|
||||||
|
if (parms[a] == null)
|
||||||
|
filter = Regex.Replace(filter, @"\s*(=|IN)\s*\{" + a + @"\}", " IS {" + a + "}", RegexOptions.IgnoreCase);
|
||||||
|
nparms[a] = AddslashesProcessParam(parms[a]);
|
||||||
|
}
|
||||||
|
try { string ret = string.Format(filter, nparms); return ret; } catch { return filter; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
176
FreeSql/Internal/CommonProvider/CacheProvider.cs
Normal file
176
FreeSql/Internal/CommonProvider/CacheProvider.cs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
class CacheProvider : ICache {
|
||||||
|
|
||||||
|
public IDistributedCache Cache { get; private set; }
|
||||||
|
private bool CacheSupportMultiRemove = false;
|
||||||
|
private static DateTime dt1970 = new DateTime(1970, 1, 1);
|
||||||
|
|
||||||
|
public CacheProvider(IDistributedCache cache, ILogger log) {
|
||||||
|
if (cache == null) cache = new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions { }));
|
||||||
|
Cache = cache;
|
||||||
|
var key1 = $"testCacheSupportMultiRemoveFreeSql{Guid.NewGuid().ToString("N")}";
|
||||||
|
var key2 = $"testCacheSupportMultiRemoveFreeSql{Guid.NewGuid().ToString("N")}";
|
||||||
|
Cache.Set(key1, new byte[] { 65 });
|
||||||
|
Cache.Set(key2, new byte[] { 65 });
|
||||||
|
try { Cache.Remove($"{key1}|{key2}"); } catch { } // redis-cluster 不允许执行 multi keys 命令
|
||||||
|
CacheSupportMultiRemove = Cache.Get(key1) == null && cache.Get(key2) == null;
|
||||||
|
if (CacheSupportMultiRemove == false) {
|
||||||
|
log.LogWarning("FreeSql Warning: 低性能, IDistributedCache 没现实批量删除缓存 Cache.Remove(\"key1|key2\").");
|
||||||
|
Remove(key1, key2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Func<object, string> Serialize { get; set; }
|
||||||
|
public Func<string, Type, object> Deserialize { get; set; }
|
||||||
|
|
||||||
|
Func<JsonSerializerSettings> JsonSerializerSettings = () => {
|
||||||
|
var st = new JsonSerializerSettings();
|
||||||
|
st.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
|
||||||
|
st.DateFormatHandling = DateFormatHandling.IsoDateFormat;
|
||||||
|
st.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
|
||||||
|
return st;
|
||||||
|
};
|
||||||
|
string SerializeObject(object value) {
|
||||||
|
if (Serialize != null) return Serialize(value);
|
||||||
|
return JsonConvert.SerializeObject(value, this.JsonSerializerSettings());
|
||||||
|
}
|
||||||
|
T DeserializeObject<T>(string value) {
|
||||||
|
if (Deserialize != null) return (T) Deserialize(value, typeof(T));
|
||||||
|
return JsonConvert.DeserializeObject<T>(value, this.JsonSerializerSettings());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set<T>(string key, T data, int timeoutSeconds = 0) {
|
||||||
|
if (string.IsNullOrEmpty(key)) return;
|
||||||
|
Cache.Set(key, Encoding.UTF8.GetBytes(this.SerializeObject(data)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
||||||
|
}
|
||||||
|
public T Get<T>(string key) {
|
||||||
|
if (string.IsNullOrEmpty(key)) return default(T);
|
||||||
|
var value = Cache.Get(key);
|
||||||
|
if (value == null) return default(T);
|
||||||
|
return this.DeserializeObject<T>(Encoding.UTF8.GetString(value));
|
||||||
|
}
|
||||||
|
public string Get(string key) {
|
||||||
|
if (string.IsNullOrEmpty(key)) return null;
|
||||||
|
var value = Cache.Get(key);
|
||||||
|
if (value == null) return null;
|
||||||
|
return Encoding.UTF8.GetString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
async public Task SetAsync<T>(string key, T data, int timeoutSeconds = 0) {
|
||||||
|
if (string.IsNullOrEmpty(key)) return;
|
||||||
|
await Cache.SetAsync(key, Encoding.UTF8.GetBytes(this.SerializeObject(data)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
||||||
|
}
|
||||||
|
async public Task<T> GetAsync<T>(string key) {
|
||||||
|
if (string.IsNullOrEmpty(key)) return default(T);
|
||||||
|
var value = await Cache.GetAsync(key);
|
||||||
|
if (value == null) return default(T);
|
||||||
|
return this.DeserializeObject<T>(Encoding.UTF8.GetString(value));
|
||||||
|
}
|
||||||
|
async public Task<string> GetAsync(string key) {
|
||||||
|
if (string.IsNullOrEmpty(key)) return null;
|
||||||
|
var value = await Cache.GetAsync(key);
|
||||||
|
if (value == null) return null;
|
||||||
|
return Encoding.UTF8.GetString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(params string[] keys) {
|
||||||
|
if (keys == null || keys.Length == 0) return;
|
||||||
|
var keysDistinct = keys.Distinct();
|
||||||
|
if (CacheSupportMultiRemove) Cache.Remove(string.Join("|", keysDistinct));
|
||||||
|
else foreach (var key in keysDistinct) Cache.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
async public Task RemoveAsync(params string[] keys) {
|
||||||
|
if (keys == null || keys.Length == 0) return;
|
||||||
|
var keysDistinct = keys.Distinct();
|
||||||
|
if (CacheSupportMultiRemove) await Cache.RemoveAsync(string.Join("|", keysDistinct));
|
||||||
|
else foreach (var key in keysDistinct) await Cache.RemoveAsync(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Shell<T>(string key, int timeoutSeconds, Func<T> getData) {
|
||||||
|
if (timeoutSeconds <= 0) return getData();
|
||||||
|
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
||||||
|
var cacheValue = Cache.Get(key);
|
||||||
|
if (cacheValue != null) {
|
||||||
|
try {
|
||||||
|
var txt = Encoding.UTF8.GetString(cacheValue);
|
||||||
|
return DeserializeObject<T>(txt);
|
||||||
|
} catch {
|
||||||
|
Cache.Remove(key);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ret = getData();
|
||||||
|
Cache.Set(key, Encoding.UTF8.GetBytes(SerializeObject(ret)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Shell<T>(string key, string field, int timeoutSeconds, Func<T> getData) {
|
||||||
|
if (timeoutSeconds <= 0) return getData();
|
||||||
|
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
||||||
|
var hashkey = $"{key}:{field}";
|
||||||
|
var cacheValue = Cache.Get(hashkey);
|
||||||
|
if (cacheValue != null) {
|
||||||
|
try {
|
||||||
|
var txt = Encoding.UTF8.GetString(cacheValue);
|
||||||
|
var value = DeserializeObject<(T, long)>(txt);
|
||||||
|
if (DateTime.Now.Subtract(dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
|
||||||
|
} catch {
|
||||||
|
Cache.Remove(hashkey);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ret = (getData(), (long) DateTime.Now.Subtract(dt1970).TotalSeconds);
|
||||||
|
Cache.Set(hashkey, Encoding.UTF8.GetBytes(SerializeObject(ret)));
|
||||||
|
return ret.Item1;
|
||||||
|
}
|
||||||
|
|
||||||
|
async public Task<T> ShellAsync<T>(string key, int timeoutSeconds, Func<Task<T>> getDataAsync) {
|
||||||
|
if (timeoutSeconds <= 0) return await getDataAsync();
|
||||||
|
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
||||||
|
var cacheValue = await Cache.GetAsync(key);
|
||||||
|
if (cacheValue != null) {
|
||||||
|
try {
|
||||||
|
var txt = Encoding.UTF8.GetString(cacheValue);
|
||||||
|
return DeserializeObject<T>(txt);
|
||||||
|
} catch {
|
||||||
|
await Cache.RemoveAsync(key);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ret = await getDataAsync();
|
||||||
|
await Cache.SetAsync(key, Encoding.UTF8.GetBytes(SerializeObject(ret)), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(timeoutSeconds) });
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
async public Task<T> ShellAsync<T>(string key, string field, int timeoutSeconds, Func<Task<T>> getDataAsync) {
|
||||||
|
if (timeoutSeconds <= 0) return await getDataAsync();
|
||||||
|
if (Cache == null) throw new Exception("缓存现实 IDistributedCache 为 null");
|
||||||
|
var hashkey = $"{key}:{field}";
|
||||||
|
var cacheValue = await Cache.GetAsync(hashkey);
|
||||||
|
if (cacheValue != null) {
|
||||||
|
try {
|
||||||
|
var txt = Encoding.UTF8.GetString(cacheValue);
|
||||||
|
var value = DeserializeObject<(T, long)>(txt);
|
||||||
|
if (DateTime.Now.Subtract(dt1970.AddSeconds(value.Item2)).TotalSeconds <= timeoutSeconds) return value.Item1;
|
||||||
|
} catch {
|
||||||
|
await Cache.RemoveAsync(hashkey);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ret = (await getDataAsync(), (long) DateTime.Now.Subtract(dt1970).TotalSeconds);
|
||||||
|
await Cache.SetAsync(hashkey, Encoding.UTF8.GetBytes(SerializeObject(ret)));
|
||||||
|
return ret.Item1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
FreeSql/Internal/CommonProvider/DeleteProvider.cs
Normal file
52
FreeSql/Internal/CommonProvider/DeleteProvider.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract partial class DeleteProvider<T1> : IDelete<T1> where T1 : class {
|
||||||
|
protected IFreeSql _orm;
|
||||||
|
protected CommonUtils _commonUtils;
|
||||||
|
protected CommonExpression _commonExpression;
|
||||||
|
protected List<T1> _source = new List<T1>();
|
||||||
|
protected TableInfo _table;
|
||||||
|
protected StringBuilder _where = new StringBuilder();
|
||||||
|
protected int _whereTimes = 0;
|
||||||
|
protected List<DbParameter> _params = new List<DbParameter>();
|
||||||
|
|
||||||
|
public DeleteProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) {
|
||||||
|
_orm = orm;
|
||||||
|
_commonUtils = commonUtils;
|
||||||
|
_commonExpression = commonExpression;
|
||||||
|
_table = _commonUtils.GetTableByEntity(typeof(T1));
|
||||||
|
_where.Append("DELETE FROM ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append(" WHERE ");
|
||||||
|
this.Where(_commonUtils.WhereObject(_table, "", dywhere));
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ExecuteAffrows() {
|
||||||
|
var sql = this.ToSql();
|
||||||
|
if (string.IsNullOrEmpty(sql)) return 0;
|
||||||
|
return _orm.Ado.ExecuteNonQuery(CommandType.Text, sql, _params.ToArray());
|
||||||
|
}
|
||||||
|
public abstract List<T1> ExecuteDeleted();
|
||||||
|
|
||||||
|
public IDelete<T1> Where(Expression<Func<T1, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambdaNoneForeignObject(null, null, exp?.Body));
|
||||||
|
public IDelete<T1> Where(string sql, object parms = null) {
|
||||||
|
if (string.IsNullOrEmpty(sql)) return this;
|
||||||
|
if (++_whereTimes > 1) _where.Append(" AND ");
|
||||||
|
_where.Append("(").Append(sql).Append(")");
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public IDelete<T1> Where(T1 item) => this.Where(new[] { item });
|
||||||
|
public IDelete<T1> Where(IEnumerable<T1> items) => this.Where(_commonUtils.WhereItems(_table, "", items));
|
||||||
|
public IDelete<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class => this.Where($"{(notExists ? "NOT " : "")}EXISTS({select.ToSql("1")})");
|
||||||
|
|
||||||
|
public string ToSql() => _whereTimes <= 0 ? null : _where.ToString();
|
||||||
|
}
|
||||||
|
}
|
90
FreeSql/Internal/CommonProvider/InsertProvider.cs
Normal file
90
FreeSql/Internal/CommonProvider/InsertProvider.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract partial class InsertProvider<T1> : IInsert<T1> where T1 : class {
|
||||||
|
protected IFreeSql _orm;
|
||||||
|
protected CommonUtils _commonUtils;
|
||||||
|
protected CommonExpression _commonExpression;
|
||||||
|
protected List<T1> _source = new List<T1>();
|
||||||
|
protected Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
protected TableInfo _table;
|
||||||
|
protected DbParameter[] _params;
|
||||||
|
|
||||||
|
public InsertProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) {
|
||||||
|
_orm = orm;
|
||||||
|
_commonUtils = commonUtils;
|
||||||
|
_commonExpression = commonExpression;
|
||||||
|
_table = _commonUtils.GetTableByEntity(typeof(T1));
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInsert<T1> AppendData(T1 source) {
|
||||||
|
if (source != null) _source.Add(source);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public IInsert<T1> AppendData(IEnumerable<T1> source) {
|
||||||
|
if (source != null) _source.AddRange(source.Where(a => a != null));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ExecuteAffrows() => _orm.Ado.ExecuteNonQuery(CommandType.Text, this.ToSql(), _params);
|
||||||
|
public abstract long ExecuteIdentity();
|
||||||
|
public abstract List<T1> ExecuteInserted();
|
||||||
|
|
||||||
|
public IInsert<T1> IgnoreColumns(Expression<Func<T1, object>> columns) {
|
||||||
|
var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).Distinct();
|
||||||
|
_ignore.Clear();
|
||||||
|
foreach (var col in cols) _ignore.Add(col, true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public IInsert<T1> InsertColumns(Expression<Func<T1, object>> columns) {
|
||||||
|
var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).ToDictionary(a => a, a => true);
|
||||||
|
_ignore.Clear();
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
if (cols.ContainsKey(col.Attribute.Name) == false)
|
||||||
|
_ignore.Add(col.Attribute.Name, true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToSql() {
|
||||||
|
if (_source == null || _source.Any() == false) return null;
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append("INSERT INTO ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append("(");
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name) == false) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
if (colidx == 0) return null;
|
||||||
|
sb.Append(") VALUES");
|
||||||
|
_params = new DbParameter[colidx * _source.Count];
|
||||||
|
var didx = 0;
|
||||||
|
foreach (var d in _source) {
|
||||||
|
if (didx > 0) sb.Append(", ");
|
||||||
|
sb.Append("(");
|
||||||
|
var colidx2 = 0;
|
||||||
|
foreach (var col in _table.Columns.Values)
|
||||||
|
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name) == false) {
|
||||||
|
if (colidx2 > 0) sb.Append(", ");
|
||||||
|
sb.Append("?").Append(col.CsName).Append(didx);
|
||||||
|
_params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : DBNull.Value);
|
||||||
|
++colidx2;
|
||||||
|
}
|
||||||
|
sb.Append(")");
|
||||||
|
++didx;
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,263 @@
|
|||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select0Provider<TSelect, T1> : ISelect0<TSelect, T1> where TSelect : class where T1 : class {
|
||||||
|
|
||||||
|
protected int _limit, _skip;
|
||||||
|
protected string _select = "SELECT ", _orderby, _groupby, _having;
|
||||||
|
protected StringBuilder _where = new StringBuilder();
|
||||||
|
protected List<DbParameter> _params = new List<DbParameter>();
|
||||||
|
protected List<SelectTableInfo> _tables = new List<SelectTableInfo>();
|
||||||
|
protected StringBuilder _join = new StringBuilder();
|
||||||
|
protected (int seconds, string key) _cache = (0, null);
|
||||||
|
protected IFreeSql _orm;
|
||||||
|
protected CommonUtils _commonUtils;
|
||||||
|
protected CommonExpression _commonExpression;
|
||||||
|
|
||||||
|
internal static void CopyData(Select0Provider<TSelect, T1> from, object to) {
|
||||||
|
var toType = to?.GetType();
|
||||||
|
if (toType == null) return;
|
||||||
|
toType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._limit);
|
||||||
|
toType.GetField("_skip", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._skip);
|
||||||
|
toType.GetField("_select", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._select);
|
||||||
|
toType.GetField("_where", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._where.ToString()));
|
||||||
|
toType.GetField("_params", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<DbParameter>(from._params.ToArray()));
|
||||||
|
toType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new List<SelectTableInfo>(from._tables.ToArray()));
|
||||||
|
toType.GetField("_join", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, new StringBuilder().Append(from._join.ToString()));
|
||||||
|
toType.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._cache);
|
||||||
|
//toType.GetField("_orm", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._orm);
|
||||||
|
//toType.GetField("_commonUtils", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonUtils);
|
||||||
|
//toType.GetField("_commonExpression", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(to, from._commonExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Select0Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) {
|
||||||
|
_orm = orm;
|
||||||
|
_commonUtils = commonUtils;
|
||||||
|
_commonExpression = commonExpression;
|
||||||
|
_tables.Add(new SelectTableInfo { Table = _commonUtils.GetTableByEntity(typeof(T1)), Alias = "a", On = null, Type = SelectTableInfoType.From });
|
||||||
|
this.Where(_commonUtils.WhereObject(_tables.First().Table, "a.", dywhere));
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Any() {
|
||||||
|
this.Limit(1);
|
||||||
|
return this.ToList<int>("1").FirstOrDefault() == 1;
|
||||||
|
}
|
||||||
|
public TSelect Caching(int seconds, string key = null) {
|
||||||
|
_cache = (seconds, key);
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
public long Count() => this.ToList<int>("count(1)").FirstOrDefault();
|
||||||
|
public TSelect Count(out long count) {
|
||||||
|
count = this.Count();
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TSelect GroupBy(string sql, object parms = null) {
|
||||||
|
_groupby = sql;
|
||||||
|
if (string.IsNullOrEmpty(_groupby)) return this as TSelect;
|
||||||
|
_groupby = string.Concat(" \r\nGROUP BY ", _groupby);
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(_groupby, parms));
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
public TSelect Having(string sql, object parms = null) {
|
||||||
|
if (string.IsNullOrEmpty(_groupby) || string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||||
|
_having = string.Concat(_having, " AND (", sql, ")");
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TSelect LeftJoin(Expression<Func<T1, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.LeftJoin);
|
||||||
|
public TSelect InnerJoin(Expression<Func<T1, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.InnerJoin);
|
||||||
|
public TSelect RightJoin(Expression<Func<T1, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.RightJoin);
|
||||||
|
public TSelect LeftJoin<T2>(Expression<Func<T1, T2, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.LeftJoin);
|
||||||
|
public TSelect InnerJoin<T2>(Expression<Func<T1, T2, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.InnerJoin);
|
||||||
|
public TSelect RightJoin<T2>(Expression<Func<T1, T2, bool>> exp) => this.InternalJoin(exp?.Body, SelectTableInfoType.RightJoin);
|
||||||
|
|
||||||
|
public TSelect InnerJoin(string sql, object parms = null) {
|
||||||
|
if (string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||||
|
_join.Append(" \r\nINNER JOIN ").Append(sql);
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
public TSelect LeftJoin(string sql, object parms = null) {
|
||||||
|
if (string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||||
|
_join.Append(" \r\nLEFT JOIN ").Append(sql);
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TSelect Limit(int limit) {
|
||||||
|
_limit = limit;
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
public TSelect Master() {
|
||||||
|
_select = " SELECT ";
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
public TSelect Offset(int offset) => this.Skip(offset) as TSelect;
|
||||||
|
|
||||||
|
public TSelect OrderBy(string sql, object parms = null) {
|
||||||
|
if (string.IsNullOrEmpty(sql)) _orderby = null;
|
||||||
|
_orderby = string.Concat(string.IsNullOrEmpty(_orderby) ? " \r\nORDER BY " : "", _orderby, sql);
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
public TSelect Page(int pageIndex, int pageSize) {
|
||||||
|
this.Skip(Math.Max(0, pageIndex - 1) * pageSize);
|
||||||
|
return this.Limit(pageSize) as TSelect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TSelect RightJoin(string sql, object parms = null) {
|
||||||
|
if (string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||||
|
_join.Append(" \r\nRIGHT JOIN ").Append(sql);
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TSelect Skip(int offset) {
|
||||||
|
_skip = offset;
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
public TSelect Take(int limit) => this.Limit(limit) as TSelect;
|
||||||
|
|
||||||
|
public List<TTuple> ToList<TTuple>(string field) {
|
||||||
|
var sql = this.ToSql(field);
|
||||||
|
if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = sql;
|
||||||
|
|
||||||
|
return _orm.Cache.Shell(_cache.key, _cache.seconds, () => {
|
||||||
|
List<TTuple> ret = new List<TTuple>();
|
||||||
|
Type type = typeof(TTuple);
|
||||||
|
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql, _params.ToArray());
|
||||||
|
foreach (var dr in ds) {
|
||||||
|
var read = Utils.ExecuteArrayRowReadClassOrTuple(type, null, dr);
|
||||||
|
ret.Add(read.value == null ? default(TTuple) : (TTuple)read.value);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public List<T1> ToList() {
|
||||||
|
return this.ToList<T1>(this.GetAllField());
|
||||||
|
}
|
||||||
|
public T1 ToOne() {
|
||||||
|
this.Limit(1);
|
||||||
|
return ToList().FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<TReturn> ToList<TReturn>((ReadAnonymousTypeInfo map, string field) af) {
|
||||||
|
var sql = this.ToSql(af.field);
|
||||||
|
if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}";
|
||||||
|
|
||||||
|
var drarr = _orm.Cache.Shell(_cache.key, _cache.seconds, () => _orm.Ado.ExecuteArray(CommandType.Text, sql, _params.ToArray()));
|
||||||
|
var ret = new List<TReturn>();
|
||||||
|
for (var a = 0; a < drarr.Length; a++) {
|
||||||
|
var dr = drarr[a];
|
||||||
|
var index = -1;
|
||||||
|
ret.Add((TReturn)_commonExpression.ReadAnonymous(af.map, dr, ref index));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
protected (ReadAnonymousTypeInfo map, string field) GetNewExpressionField(NewExpression newexp) {
|
||||||
|
var map = new ReadAnonymousTypeInfo();
|
||||||
|
var field = new StringBuilder();
|
||||||
|
var index = 0;
|
||||||
|
|
||||||
|
_commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp);
|
||||||
|
return (map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null);
|
||||||
|
}
|
||||||
|
protected (ReadAnonymousTypeInfo map, string field) GetAllField() {
|
||||||
|
var type = typeof(T1);
|
||||||
|
var map = new ReadAnonymousTypeInfo { Consturctor = type.GetConstructor(new Type[0]), ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties };
|
||||||
|
var field = new StringBuilder();
|
||||||
|
var tb = _tables.First();
|
||||||
|
var index = 0;
|
||||||
|
var ps = typeof(T1).GetProperties();
|
||||||
|
foreach (var p in ps) {
|
||||||
|
var child = new ReadAnonymousTypeInfo { CsName = p.Name };
|
||||||
|
if (tb.Table.ColumnsByCs.TryGetValue(p.Name, out var col)) { //普通字段
|
||||||
|
if (index > 0) field.Append(", ");
|
||||||
|
field.Append(tb.Alias).Append(".").Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as").Append(++index);
|
||||||
|
} else {
|
||||||
|
var tb2 = _tables.Where(a => a.Table.Type == p.PropertyType && a.Alias.Contains(p.Name)).FirstOrDefault();
|
||||||
|
if (tb2 == null && ps.Where(pw => pw.PropertyType == p.PropertyType).Count() == 1) tb2 = _tables.Where(a => a.Table.Type == p.PropertyType).FirstOrDefault();
|
||||||
|
if (tb2 == null) continue;
|
||||||
|
child.Consturctor = tb2.Table.Type.GetConstructor(new Type[0]);
|
||||||
|
child.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties;
|
||||||
|
foreach (var col2 in tb2.Table.Columns.Values) {
|
||||||
|
if (index > 0) field.Append(", ");
|
||||||
|
field.Append(tb2.Alias).Append(".").Append(_commonUtils.QuoteSqlName(col2.Attribute.Name)).Append(" as").Append(++index);
|
||||||
|
child.Childs.Add(new ReadAnonymousTypeInfo { CsName = col2.CsName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map.Childs.Add(child);
|
||||||
|
}
|
||||||
|
return (map, field.ToString());
|
||||||
|
}
|
||||||
|
public abstract string ToSql(string field = null);
|
||||||
|
|
||||||
|
public TSelect Where(string sql, object parms = null) => this.WhereIf(true, sql, parms);
|
||||||
|
public TSelect WhereIf(bool condition, string sql, object parms = null) {
|
||||||
|
if (condition == false || string.IsNullOrEmpty(sql)) return this as TSelect;
|
||||||
|
_where.Append(" AND (").Append(sql).Append(")");
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
#region common
|
||||||
|
|
||||||
|
protected TMember InternalAvg<TMember>(Expression exp) => this.ToList<TMember>($"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault();
|
||||||
|
protected TMember InternalMax<TMember>(Expression exp) => this.ToList<TMember>($"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault();
|
||||||
|
protected TMember InternalMin<TMember>(Expression exp) => this.ToList<TMember>($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault();
|
||||||
|
protected TMember InternalSum<TMember>(Expression exp) => this.ToList<TMember>($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault();
|
||||||
|
|
||||||
|
protected TSelect InternalGroupBy(Expression columns) => this.GroupBy(string.Join(", ", _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, columns, true)));
|
||||||
|
protected TSelect InternalJoin(Expression exp, SelectTableInfoType joinType) {
|
||||||
|
_commonExpression.ExpressionJoinLambda(_tables, joinType, exp);
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
protected TSelect InternalJoin<T2>(Expression exp, SelectTableInfoType joinType) {
|
||||||
|
var tb = _commonUtils.GetTableByEntity(typeof(T2));
|
||||||
|
if (tb == null) throw new ArgumentException("T2 类型错误");
|
||||||
|
_tables.Add(new SelectTableInfo { Table = tb, Alias = $"IJ{_tables.Count}", On = null, Type = joinType });
|
||||||
|
_commonExpression.ExpressionJoinLambda(_tables, joinType, exp);
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true));
|
||||||
|
protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true)} DESC");
|
||||||
|
|
||||||
|
protected List<TReturn> InternalToList<TReturn>(Expression select) => this.ToList<TReturn>(this.GetNewExpressionField(select as NewExpression));
|
||||||
|
|
||||||
|
protected TSelect InternalWhere(Expression exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp));
|
||||||
|
protected TSelect InternalWhereLikeOr(Expression columns, string pattern, bool notLike) {
|
||||||
|
if (string.IsNullOrEmpty(pattern)) return this as TSelect;
|
||||||
|
var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, columns, true);
|
||||||
|
if (cols.Any() == false) return this as TSelect;
|
||||||
|
var filter = "";
|
||||||
|
foreach (var col in cols) {
|
||||||
|
if (string.IsNullOrEmpty(col)) continue;
|
||||||
|
filter += string.Concat(" OR ", _commonUtils.FormatSql($"{col} {(notLike ? "NOT LIKE" : "LIKE")} {{0}}", pattern));
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(filter)) return this as TSelect;
|
||||||
|
return this.Where(filter.Substring(4));
|
||||||
|
}
|
||||||
|
protected TSelect InternalWhereLike(Expression column, string pattern, bool notLike) {
|
||||||
|
if (string.IsNullOrEmpty(pattern)) return this as TSelect;
|
||||||
|
string col = _commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true);
|
||||||
|
if (string.IsNullOrEmpty(col)) return this as TSelect;
|
||||||
|
return this.Where(_commonUtils.FormatSql($"{col} {(notLike ? "NOT LIKE" : "LIKE")} {{0}}", pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TSelect InternalJoin(Expression exp) {
|
||||||
|
return this as TSelect;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class
|
||||||
|
where T3 : class
|
||||||
|
where T4 : class
|
||||||
|
where T5 : class
|
||||||
|
where T6 : class
|
||||||
|
where T7 : class
|
||||||
|
where T8 : class
|
||||||
|
where T9 : class
|
||||||
|
where T10 : class {
|
||||||
|
|
||||||
|
public Select10Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9), typeof(T10));
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select1Provider<T1> : Select0Provider<ISelect<T1>, T1>, ISelect<T1>
|
||||||
|
where T1 : class {
|
||||||
|
public Select1Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ISelect<T1> InternalFrom(Expression exp) {
|
||||||
|
if (exp.NodeType == ExpressionType.Call) {
|
||||||
|
var expCall = exp as MethodCallExpression;
|
||||||
|
var stockCall = new Stack<MethodCallExpression>();
|
||||||
|
while (expCall != null) {
|
||||||
|
stockCall.Push(expCall);
|
||||||
|
expCall = expCall.Object as MethodCallExpression;
|
||||||
|
}
|
||||||
|
while (stockCall.Any()) {
|
||||||
|
expCall = stockCall.Pop();
|
||||||
|
|
||||||
|
switch (expCall.Method.Name) {
|
||||||
|
case "Where": this.InternalWhere(expCall.Arguments[0]); break;
|
||||||
|
case "WhereIf":
|
||||||
|
if (_commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[0], false) == "1")
|
||||||
|
this.InternalWhere(expCall.Arguments[1]);
|
||||||
|
break;
|
||||||
|
case "WhereLike":
|
||||||
|
var whereLikeArg0 = (expCall.Arguments[0] as UnaryExpression).Operand as LambdaExpression;
|
||||||
|
var whereLikeArg1 = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[1], false);
|
||||||
|
var whereLikeArg2 = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[2], false) == "1";
|
||||||
|
if (whereLikeArg0.ReturnType == typeof(string)) this.InternalWhereLike(whereLikeArg0, whereLikeArg1, whereLikeArg2);
|
||||||
|
else this.InternalWhereLikeOr(whereLikeArg0, whereLikeArg1, whereLikeArg2);
|
||||||
|
break;
|
||||||
|
case "GroupBy": this.InternalGroupBy(expCall.Arguments[0]); break;
|
||||||
|
case "OrderBy": this.InternalOrderBy(expCall.Arguments[0]); break;
|
||||||
|
case "OrderByDescending": this.InternalOrderByDescending(expCall.Arguments[0]); break;
|
||||||
|
|
||||||
|
case "LeftJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.LeftJoin); break;
|
||||||
|
case "InnerJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.InnerJoin); break;
|
||||||
|
case "RightJoin": this.InternalJoin(expCall.Arguments[0], SelectTableInfoType.RightJoin); break;
|
||||||
|
|
||||||
|
default: throw new NotImplementedException($"未现实 {expCall.Method.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
throw new NotImplementedException($"未现实 {exp}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISelect<T1> As(string alias) {
|
||||||
|
var oldAs = _tables.First().Alias;
|
||||||
|
var newAs = string.IsNullOrEmpty(alias) ? "a" : alias;
|
||||||
|
if (oldAs != newAs) {
|
||||||
|
_tables.First().Alias = newAs;
|
||||||
|
var wh = _where.ToString();
|
||||||
|
_where.Replace($" {oldAs}.", $" {newAs}.");
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TMember Avg<TMember>(Expression<Func<T1, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
public abstract ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class;// { this.InternalFrom(exp?.Body); var ret = new Select3Provider<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||||
|
|
||||||
|
public abstract ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class;// { this.InternalFrom(exp?.Body); var ret = new Select4Provider<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||||
|
|
||||||
|
public abstract ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class;// { this.InternalFrom(exp?.Body); var ret = new Select5Provider<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||||
|
|
||||||
|
public abstract ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class;// { this.InternalFrom(exp?.Body); var ret = new Select6Provider<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||||
|
|
||||||
|
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class;// { this.InternalFrom(exp?.Body); var ret = new Select7Provider<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||||
|
|
||||||
|
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class;// { this.InternalFrom(exp?.Body); var ret = new Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||||
|
|
||||||
|
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class;// { this.InternalFrom(exp?.Body); var ret = new Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||||
|
|
||||||
|
public abstract ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;// { this.InternalFrom(exp?.Body); var ret = new Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); Select0Provider<ISelect<T1>, T1>.CopyData(this, ret); return ret; }
|
||||||
|
|
||||||
|
public ISelect<T1> GroupBy(Expression<Func<T1, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
public TMember Max<TMember>(Expression<Func<T1, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
public TMember Min<TMember>(Expression<Func<T1, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
public ISelect<T1> OrderBy<TMember>(Expression<Func<T1, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
public ISelect<T1> OrderByDescending<TMember>(Expression<Func<T1, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
public TMember Sum<TMember>(Expression<Func<T1, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
public List<TReturn> ToList<TReturn>(Expression<Func<T1, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
public ISelect<T1> Where(Expression<Func<T1, bool>> exp) => this.InternalWhere(exp?.Body);
|
||||||
|
|
||||||
|
public ISelect<T1> Where<T2>(Expression<Func<T1, T2, bool>> exp) where T2 : class => this.InternalWhere(exp?.Body);
|
||||||
|
|
||||||
|
public ISelect<T1> Where<T2, T3>(Expression<Func<T1, T2, T3, bool>> exp) where T2 : class where T3 : class => this.InternalWhere(exp?.Body);
|
||||||
|
|
||||||
|
public ISelect<T1> Where<T2, T3, T4>(Expression<Func<T1, T2, T3, T4, bool>> exp) where T2 : class where T3 : class where T4 : class => this.InternalWhere(exp?.Body);
|
||||||
|
|
||||||
|
public ISelect<T1> Where<T2, T3, T4, T5>(Expression<Func<T1, T2, T3, T4, T5, bool>> exp) where T2 : class where T3 : class where T4 : class where T5 : class => this.InternalWhere(exp?.Body);
|
||||||
|
|
||||||
|
public ISelect<T1> WhereIf(bool condition, Expression<Func<T1, bool>> exp) => condition ? this.InternalWhere(exp?.Body) : this;
|
||||||
|
|
||||||
|
public ISelect<T1> WhereLike(Expression<Func<T1, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
public ISelect<T1> WhereLike(Expression<Func<T1, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select2Provider<T1, T2> : Select0Provider<ISelect<T1, T2>, T1>, ISelect<T1, T2>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class {
|
||||||
|
|
||||||
|
public Select2Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T2>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2>.Avg<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2> ISelect<T1, T2>.GroupBy(Expression<Func<T1, T2, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2>.Max<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2>.Min<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2> ISelect<T1, T2>.OrderBy<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2> ISelect<T1, T2>.OrderByDescending<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2>.Sum<TMember>(Expression<Func<T1, T2, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2>.ToList<TReturn>(Expression<Func<T1, T2, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2> ISelect<T1, T2>.Where(Expression<Func<T1, T2, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2> ISelect<T1, T2>.WhereIf(bool condition, Expression<Func<T1, T2, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2> ISelect<T1, T2>.WhereLike(Expression<Func<T1, T2, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2> ISelect<T1, T2>.WhereLike(Expression<Func<T1, T2, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select3Provider<T1, T2, T3> : Select0Provider<ISelect<T1, T2, T3>, T1>, ISelect<T1, T2, T3>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class
|
||||||
|
where T3 : class {
|
||||||
|
|
||||||
|
public Select3Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3>.Avg<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.GroupBy(Expression<Func<T1, T2, T3, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3>.Max<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3>.Min<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.OrderBy<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3>.Sum<TMember>(Expression<Func<T1, T2, T3, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2, T3>.ToList<TReturn>(Expression<Func<T1, T2, T3, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.Where(Expression<Func<T1, T2, T3, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.WhereIf(bool condition, Expression<Func<T1, T2, T3, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.WhereLike(Expression<Func<T1, T2, T3, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3> ISelect<T1, T2, T3>.WhereLike(Expression<Func<T1, T2, T3, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select4Provider<T1, T2, T3, T4> : Select0Provider<ISelect<T1, T2, T3, T4>, T1>, ISelect<T1, T2, T3, T4>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class
|
||||||
|
where T3 : class
|
||||||
|
where T4 : class {
|
||||||
|
|
||||||
|
public Select4Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.GroupBy(Expression<Func<T1, T2, T3, T4, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4>.Max<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4>.Min<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2, T3, T4>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.Where(Expression<Func<T1, T2, T3, T4, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.WhereLike(Expression<Func<T1, T2, T3, T4, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4> ISelect<T1, T2, T3, T4>.WhereLike(Expression<Func<T1, T2, T3, T4, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select5Provider<T1, T2, T3, T4, T5> : Select0Provider<ISelect<T1, T2, T3, T4, T5>, T1>, ISelect<T1, T2, T3, T4, T5>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class
|
||||||
|
where T3 : class
|
||||||
|
where T4 : class
|
||||||
|
where T5 : class {
|
||||||
|
|
||||||
|
public Select5Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5));
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2, T3, T4, T5>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.Where(Expression<Func<T1, T2, T3, T4, T5, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5> ISelect<T1, T2, T3, T4, T5>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select6Provider<T1, T2, T3, T4, T5, T6> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6>, T1>, ISelect<T1, T2, T3, T4, T5, T6>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class
|
||||||
|
where T3 : class
|
||||||
|
where T4 : class
|
||||||
|
where T5 : class
|
||||||
|
where T6 : class {
|
||||||
|
|
||||||
|
public Select6Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6));
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6> ISelect<T1, T2, T3, T4, T5, T6>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select7Provider<T1, T2, T3, T4, T5, T6, T7> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class
|
||||||
|
where T3 : class
|
||||||
|
where T4 : class
|
||||||
|
where T5 : class
|
||||||
|
where T6 : class
|
||||||
|
where T7 : class {
|
||||||
|
|
||||||
|
public Select7Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7));
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6, T7>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7> ISelect<T1, T2, T3, T4, T5, T6, T7>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract partial class Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class
|
||||||
|
where T3 : class
|
||||||
|
where T4 : class
|
||||||
|
where T5 : class
|
||||||
|
where T6 : class
|
||||||
|
where T7 : class
|
||||||
|
where T8 : class {
|
||||||
|
|
||||||
|
public Select8Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8> ISelect<T1, T2, T3, T4, T5, T6, T7, T8>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract class Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> : Select0Provider<ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>, T1>, ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>
|
||||||
|
where T1 : class
|
||||||
|
where T2 : class
|
||||||
|
where T3 : class
|
||||||
|
where T4 : class
|
||||||
|
where T5 : class
|
||||||
|
where T6 : class
|
||||||
|
where T7 : class
|
||||||
|
where T8 : class
|
||||||
|
where T9 : class {
|
||||||
|
|
||||||
|
public Select9Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(typeof(T2), typeof(T3), typeof(T4), typeof(T5), typeof(T6), typeof(T7), typeof(T8), typeof(T9));
|
||||||
|
}
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Avg<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalAvg<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.GroupBy(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, object>> columns) => this.InternalGroupBy(columns?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Max<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalMax<TMember>(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Min<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalMin<TMember>(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.OrderBy<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalOrderBy(column?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.OrderByDescending<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalOrderByDescending(column?.Body);
|
||||||
|
|
||||||
|
TMember ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Sum<TMember>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TMember>> column) => this.InternalSum<TMember>(column?.Body);
|
||||||
|
|
||||||
|
List<TReturn> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.ToList<TReturn>(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, TReturn>> select) => this.InternalToList<TReturn>(select?.Body);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.Where(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body));
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.WhereIf(bool condition, Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, bool>> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this;
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, string[]>> columns, string pattern, bool notLike) => this.InternalWhereLikeOr(columns?.Body, pattern, notLike);
|
||||||
|
|
||||||
|
ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>.WhereLike(Expression<Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, string>> column, string pattern, bool notLike) => this.InternalWhereLike(column?.Body, pattern, notLike);
|
||||||
|
}
|
||||||
|
}
|
172
FreeSql/Internal/CommonProvider/UpdateProvider.cs
Normal file
172
FreeSql/Internal/CommonProvider/UpdateProvider.cs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.CommonProvider {
|
||||||
|
|
||||||
|
abstract partial class UpdateProvider<T1> : IUpdate<T1> where T1 : class {
|
||||||
|
protected IFreeSql _orm;
|
||||||
|
protected CommonUtils _commonUtils;
|
||||||
|
protected CommonExpression _commonExpression;
|
||||||
|
protected List<T1> _source = new List<T1>();
|
||||||
|
protected Dictionary<string, bool> _ignore = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
protected TableInfo _table;
|
||||||
|
protected StringBuilder _where = new StringBuilder();
|
||||||
|
protected StringBuilder _set = new StringBuilder();
|
||||||
|
protected List<DbParameter> _params = new List<DbParameter>();
|
||||||
|
protected List<DbParameter> _paramsSource = new List<DbParameter>();
|
||||||
|
|
||||||
|
public UpdateProvider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) {
|
||||||
|
_orm = orm;
|
||||||
|
_commonUtils = commonUtils;
|
||||||
|
_commonExpression = commonExpression;
|
||||||
|
_table = _commonUtils.GetTableByEntity(typeof(T1));
|
||||||
|
this.Where(_commonUtils.WhereObject(_table, "", dywhere));
|
||||||
|
if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure<T1>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long ExecuteAffrows() {
|
||||||
|
var sql = this.ToSql();
|
||||||
|
if (string.IsNullOrEmpty(sql)) return 0;
|
||||||
|
return _orm.Ado.ExecuteNonQuery(CommandType.Text, sql, _params.Concat(_paramsSource).ToArray());
|
||||||
|
}
|
||||||
|
public abstract List<T1> ExecuteUpdated();
|
||||||
|
|
||||||
|
public IUpdate<T1> IgnoreColumns(Expression<Func<T1, object>> columns) {
|
||||||
|
var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).Distinct();
|
||||||
|
_ignore.Clear();
|
||||||
|
foreach (var col in cols) _ignore.Add(col, true);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUpdate<T1> SetSource(T1 source) => this.SetSource(new[] { source });
|
||||||
|
public IUpdate<T1> SetSource(IEnumerable<T1> source) {
|
||||||
|
if (source == null || source.Any() == false) return this;
|
||||||
|
_source.AddRange(source.Where(a => a != null));
|
||||||
|
return this.Where(_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> column, TMember value) {
|
||||||
|
var col = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, column?.Body, true);
|
||||||
|
if (string.IsNullOrEmpty(col)) return this;
|
||||||
|
_set.Append(", ").Append(col).Append(" = ?p_").Append(_params.Count);
|
||||||
|
_commonUtils.AppendParamter(_params, null, value);
|
||||||
|
//foreach (var t in _source) Utils.FillPropertyValue(t, tryf.CsName, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public IUpdate<T1> Set<TMember>(Expression<Func<T1, TMember>> binaryExpression) {
|
||||||
|
if (binaryExpression?.Body is BinaryExpression == false) return this;
|
||||||
|
var cols = new List<SelectColumnInfo>();
|
||||||
|
var expt = _commonExpression.ExpressionWhereLambdaNoneForeignObject(null, cols, binaryExpression);
|
||||||
|
if (cols.Any() == false) return this;
|
||||||
|
foreach (var col in cols) {
|
||||||
|
if (col.Column.Attribute.IsNullable) {
|
||||||
|
var repltype = col.Column.CsType;
|
||||||
|
if (repltype.FullName.StartsWith("System.Nullable`1[[System.")) repltype = repltype.GenericTypeArguments[0];
|
||||||
|
var replval = Activator.CreateInstance(repltype);
|
||||||
|
if (replval == null) continue;
|
||||||
|
var replname = _commonUtils.QuoteSqlName(col.Column.Attribute.Name);
|
||||||
|
replval = _commonUtils.FormatSql("{0}", replval);
|
||||||
|
expt = expt.Replace(replname, _commonUtils.IsNull(replname, replval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_set.Append(", ").Append(_commonUtils.QuoteSqlName(cols.First().Column.Attribute.Name)).Append(" = ").Append(expt);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public IUpdate<T1> SetRaw(string sql, object parms = null) {
|
||||||
|
if (string.IsNullOrEmpty(sql)) return this;
|
||||||
|
_set.Append(", ").Append(sql);
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUpdate<T1> Where(Expression<Func<T1, bool>> expression) => this.Where(_commonExpression.ExpressionWhereLambdaNoneForeignObject(null, null, expression?.Body));
|
||||||
|
public IUpdate<T1> Where(string sql, object parms = null) {
|
||||||
|
if (string.IsNullOrEmpty(sql)) return this;
|
||||||
|
_where.Append(" AND (").Append(sql).Append(")");
|
||||||
|
if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public IUpdate<T1> Where(T1 item) => this.Where(new[] { item });
|
||||||
|
public IUpdate<T1> Where(IEnumerable<T1> items) => this.Where(_commonUtils.WhereItems(_table, "", items));
|
||||||
|
public IUpdate<T1> WhereExists<TEntity2>(ISelect<TEntity2> select, bool notExists = false) where TEntity2 : class => this.Where($"{(notExists ? "NOT " : "")}EXISTS({select.ToSql("1")})");
|
||||||
|
|
||||||
|
protected abstract void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys);
|
||||||
|
protected abstract void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d);
|
||||||
|
|
||||||
|
public string ToSql() {
|
||||||
|
if (_where.Length == 0) return null;
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append("UPDATE ").Append(_commonUtils.QuoteSqlName(_table.DbName)).Append(" SET ");
|
||||||
|
|
||||||
|
if (_set.Length > 0) { //指定 set 更新
|
||||||
|
sb.Append(_set.ToString().Substring(2));
|
||||||
|
|
||||||
|
} else if (_source.Count == 1) { //保存 Source
|
||||||
|
_paramsSource.Clear();
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values) {
|
||||||
|
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.CsName) == false) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(_commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"));
|
||||||
|
_commonUtils.AppendParamter(_paramsSource, null, _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(_source.First()) : DBNull.Value);
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (colidx == 0) return null;
|
||||||
|
|
||||||
|
} else if (_source.Count > 1) { //批量保存 Source
|
||||||
|
if (_table.Primarys.Any() == false) return null;
|
||||||
|
|
||||||
|
var caseWhen = new StringBuilder();
|
||||||
|
caseWhen.Append("CASE ");
|
||||||
|
ToSqlCase(caseWhen, _table.Primarys);
|
||||||
|
//if (_table.Primarys.Length > 1) caseWhen.Append("CONCAT(");
|
||||||
|
//var pkidx = 0;
|
||||||
|
//foreach (var pk in _table.Primarys) {
|
||||||
|
// if (pkidx > 0) caseWhen.Append(", ");
|
||||||
|
// caseWhen.Append(_commonUtils.QuoteSqlName(pk.Attribute.Name));
|
||||||
|
// ++pkidx;
|
||||||
|
//}
|
||||||
|
//if (_table.Primarys.Length > 1) caseWhen.Append(")");
|
||||||
|
var cw = caseWhen.Append(" ").ToString();
|
||||||
|
|
||||||
|
_paramsSource.Clear();
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values) {
|
||||||
|
if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.CsName) == false) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" = ").Append(cw);
|
||||||
|
foreach (var d in _source) {
|
||||||
|
sb.Append(" \r\nWHEN ");
|
||||||
|
ToSqlWhen(sb, _table.Primarys, d);
|
||||||
|
//if (_table.Primarys.Length > 1) sb.Append("CONCAT(");
|
||||||
|
//pkidx = 0;
|
||||||
|
//foreach (var pk in _table.Primarys) {
|
||||||
|
// if (pkidx > 0) sb.Append(", ");
|
||||||
|
// sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(pk.CsName, out var tryp2) ? tryp2.GetValue(d) : null));
|
||||||
|
// ++pkidx;
|
||||||
|
//}
|
||||||
|
//if (_table.Primarys.Length > 1) sb.Append(")");
|
||||||
|
sb.Append(" THEN ").Append(_commonUtils.QuoteParamterName($"p_{_paramsSource.Count}"));
|
||||||
|
_commonUtils.AppendParamter(_paramsSource, null, _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : DBNull.Value);
|
||||||
|
}
|
||||||
|
sb.Append(" END");
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (colidx == 0) return null;
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
|
|
||||||
|
sb.Append(" \r\nWHERE ").Append(_where.ToString().Substring(5));
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
FreeSql/Internal/CommonUtils.cs
Normal file
119
FreeSql/Internal/CommonUtils.cs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal {
|
||||||
|
internal abstract class CommonUtils {
|
||||||
|
|
||||||
|
internal abstract DbParameter[] GetDbParamtersByObject(string sql, object obj);
|
||||||
|
internal abstract DbParameter AppendParamter(List<DbParameter> _params, string parameterName, object value);
|
||||||
|
internal abstract string FormatSql(string sql, params object[] args);
|
||||||
|
internal abstract string QuoteSqlName(string name);
|
||||||
|
internal abstract string QuoteParamterName(string name);
|
||||||
|
internal abstract string IsNull(string sql, object value);
|
||||||
|
|
||||||
|
internal ICodeFirst CodeFirst { get; set; }
|
||||||
|
internal TableInfo GetTableByEntity(Type entity) => Utils.GetTableByEntity(entity, this);
|
||||||
|
|
||||||
|
internal string WhereObject(TableInfo table, string aliasAndDot, object dywhere) {
|
||||||
|
if (dywhere == null) return "";
|
||||||
|
var type = dywhere.GetType();
|
||||||
|
var primarys = table.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
|
||||||
|
if (primarys.Length == 1 && type == primarys.First().CsType) {
|
||||||
|
return $"{aliasAndDot}{this.QuoteSqlName(primarys.First().Attribute.Name)} = {this.FormatSql("{0}", dywhere)}";
|
||||||
|
} else if (primarys.Length > 0 && type.FullName == table.Type.FullName) {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var pkidx = 0;
|
||||||
|
foreach (var pk in primarys) {
|
||||||
|
var prop = type.GetProperty(pk.CsName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
|
||||||
|
if (pkidx > 0) sb.Append(" AND ");
|
||||||
|
sb.Append(aliasAndDot).Append(this.QuoteSqlName(pk.Attribute.Name));
|
||||||
|
sb.Append(this.FormatSql(" = {0}", prop.GetValue(dywhere)));
|
||||||
|
++pkidx;
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
} else if (dywhere is IEnumerable) {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var ie = dywhere as IEnumerable;
|
||||||
|
var ieidx = 0;
|
||||||
|
foreach (var i in ie) {
|
||||||
|
var fw = WhereObject(table, aliasAndDot, i);
|
||||||
|
if (string.IsNullOrEmpty(fw)) continue;
|
||||||
|
if (ieidx > 0) sb.Append(" OR ");
|
||||||
|
sb.Append(fw);
|
||||||
|
++ieidx;
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
} else {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var ps = type.GetProperties();
|
||||||
|
var psidx = 0;
|
||||||
|
foreach (var p in ps) {
|
||||||
|
if (table.Columns.TryGetValue(p.Name, out var trycol) == false) continue;
|
||||||
|
if (psidx > 0) sb.Append(" AND ");
|
||||||
|
sb.Append(aliasAndDot).Append(this.QuoteSqlName(trycol.Attribute.Name));
|
||||||
|
sb.Append(this.FormatSql(" = {0}", p.GetValue(dywhere)));
|
||||||
|
++psidx;
|
||||||
|
}
|
||||||
|
if (psidx == 0) return "";
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string WhereItems<TEntity>(TableInfo table, string aliasAndDot, IEnumerable<TEntity> items) {
|
||||||
|
if (items == null || items.Any() == false) return null;
|
||||||
|
if (table.Primarys.Any() == false) return null;
|
||||||
|
var its = items.Where(a => a != null).ToArray();
|
||||||
|
|
||||||
|
if (table.Primarys.Length == 1) {
|
||||||
|
var sbin = new StringBuilder();
|
||||||
|
sbin.Append(aliasAndDot).Append(this.QuoteSqlName(table.Primarys.First().Attribute.Name));
|
||||||
|
var indt = its.Select(a => table.Properties.TryGetValue(table.Primarys.First().CsName, out var trycol) ? this.FormatSql("{0}", trycol.GetValue(a)) : null).Where(a => a != null).ToArray();
|
||||||
|
if (indt.Any() == false) return null;
|
||||||
|
if (indt.Length == 1) sbin.Append(" = ").Append(indt.First());
|
||||||
|
else sbin.Append(" IN (").Append(string.Join(",", indt)).Append(")");
|
||||||
|
return sbin.ToString();
|
||||||
|
}
|
||||||
|
var dicpk = its.Length > 5 ? new Dictionary<string, bool>() : null;
|
||||||
|
var sb = its.Length > 5 ? null : new StringBuilder();
|
||||||
|
var iidx = 0;
|
||||||
|
foreach (var item in its) {
|
||||||
|
var filter = "";
|
||||||
|
for (var a = 0; a < table.Primarys.Length; a++) {
|
||||||
|
if (table.Properties.TryGetValue(table.Primarys[a].CsName, out var trycol) == false) continue;
|
||||||
|
filter += $" AND {aliasAndDot}{this.QuoteSqlName(table.Primarys[a].Attribute.Name)} = {this.FormatSql("{0}", trycol.GetValue(item))}";
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(filter)) continue;
|
||||||
|
if (sb != null) {
|
||||||
|
sb.Append(" OR (");
|
||||||
|
sb.Append(filter.Substring(5));
|
||||||
|
sb.Append(")");
|
||||||
|
++iidx;
|
||||||
|
}
|
||||||
|
if (dicpk != null) {
|
||||||
|
filter = filter.Substring(5);
|
||||||
|
if (dicpk.ContainsKey(filter) == false) {
|
||||||
|
dicpk.Add(filter, true);
|
||||||
|
++iidx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//++iidx;
|
||||||
|
}
|
||||||
|
if (iidx == 0) return null;
|
||||||
|
if (sb == null) {
|
||||||
|
sb = new StringBuilder();
|
||||||
|
foreach (var fil in dicpk) {
|
||||||
|
sb.Append(" OR (");
|
||||||
|
sb.Append(fil.Key);
|
||||||
|
sb.Append(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iidx == 1 ? sb.Remove(0, 5).Remove(sb.Length - 1, 1).ToString() : sb.Remove(0, 4).ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
FreeSql/Internal/Model/ColumnInfo.cs
Normal file
11
FreeSql/Internal/Model/ColumnInfo.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.Model {
|
||||||
|
class ColumnInfo {
|
||||||
|
public TableInfo Table { get; set; }
|
||||||
|
public string CsName { get; set; }
|
||||||
|
public Type CsType { get; set; }
|
||||||
|
public ColumnAttribute Attribute { get; set; }
|
||||||
|
}
|
||||||
|
}
|
14
FreeSql/Internal/Model/ReadAnonymousTypeInfo.cs
Normal file
14
FreeSql/Internal/Model/ReadAnonymousTypeInfo.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.Model {
|
||||||
|
class ReadAnonymousTypeInfo {
|
||||||
|
public string CsName { get; set; }
|
||||||
|
public ConstructorInfo Consturctor { get; set; }
|
||||||
|
public ReadAnonymousTypeInfoConsturctorType ConsturctorType { get; set; }
|
||||||
|
public List<ReadAnonymousTypeInfo> Childs = new List<ReadAnonymousTypeInfo>();
|
||||||
|
}
|
||||||
|
enum ReadAnonymousTypeInfoConsturctorType { Arguments, Properties }
|
||||||
|
}
|
10
FreeSql/Internal/Model/SelectColumnInfo.cs
Normal file
10
FreeSql/Internal/Model/SelectColumnInfo.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.Model {
|
||||||
|
class SelectColumnInfo {
|
||||||
|
public ColumnInfo Column { get; set; }
|
||||||
|
public SelectTableInfo Table { get; set; }
|
||||||
|
}
|
||||||
|
}
|
9
FreeSql/Internal/Model/SelectTableInfo.cs
Normal file
9
FreeSql/Internal/Model/SelectTableInfo.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace FreeSql.Internal.Model {
|
||||||
|
class SelectTableInfo {
|
||||||
|
public TableInfo Table { get; set; }
|
||||||
|
public string Alias { get; set; }
|
||||||
|
public string On { get; set; }
|
||||||
|
public SelectTableInfoType Type { get; set; }
|
||||||
|
}
|
||||||
|
enum SelectTableInfoType { From, LeftJoin, InnerJoin, RightJoin }
|
||||||
|
}
|
18
FreeSql/Internal/Model/TableInfo.cs
Normal file
18
FreeSql/Internal/Model/TableInfo.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal.Model {
|
||||||
|
class TableInfo {
|
||||||
|
public Type Type { get; set; }
|
||||||
|
public Dictionary<string, PropertyInfo> Properties { get; set; } = new Dictionary<string, PropertyInfo>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
public Dictionary<string, ColumnInfo> Columns { get; set; } = new Dictionary<string, ColumnInfo>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
public Dictionary<string, ColumnInfo> ColumnsByCs { get; set; } = new Dictionary<string, ColumnInfo>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
public ColumnInfo[] Primarys { get; set; }
|
||||||
|
public string CsName { get; set; }
|
||||||
|
public string DbName { get; set; }
|
||||||
|
public string DbOldName { get; set; }
|
||||||
|
public string SelectFilter { get; set; }
|
||||||
|
public List<List<ColumnInfo>> Uniques { get; set; } = new List<List<ColumnInfo>>();
|
||||||
|
}
|
||||||
|
}
|
144
FreeSql/Internal/Utils.cs
Normal file
144
FreeSql/Internal/Utils.cs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace FreeSql.Internal {
|
||||||
|
class Utils {
|
||||||
|
|
||||||
|
static ConcurrentDictionary<string, TableInfo> _cacheGetTableByEntity = new ConcurrentDictionary<string, TableInfo>();
|
||||||
|
internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) {
|
||||||
|
if (_cacheGetTableByEntity.TryGetValue(entity.FullName, out var trytb)) return trytb;
|
||||||
|
if (common.CodeFirst.GetDbInfo(entity) != null) return null;
|
||||||
|
|
||||||
|
var tbattr = entity.GetCustomAttributes(typeof(TableAttribute), false).LastOrDefault() as TableAttribute;
|
||||||
|
trytb = new TableInfo();
|
||||||
|
trytb.Type = entity;
|
||||||
|
trytb.Properties = entity.GetProperties().ToDictionary(a => a.Name, a => a, StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
trytb.CsName = entity.Name;
|
||||||
|
trytb.DbName = tbattr?.Name ?? entity.Name;
|
||||||
|
trytb.DbOldName = tbattr?.OldName;
|
||||||
|
trytb.SelectFilter = tbattr?.SelectFilter;
|
||||||
|
foreach (var p in trytb.Properties.Values) {
|
||||||
|
var tp = common.CodeFirst.GetDbInfo(p.PropertyType);
|
||||||
|
if (tp == null) continue;
|
||||||
|
var colattr = p.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute ?? new ColumnAttribute {
|
||||||
|
Name = p.Name,
|
||||||
|
DbType = tp.Value.dbtypeFull,
|
||||||
|
IsIdentity = false,
|
||||||
|
IsNullable = tp.Value.isnullable ?? false,
|
||||||
|
IsPrimary = false,
|
||||||
|
};
|
||||||
|
if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name;
|
||||||
|
if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp.Value.dbtypeFull;
|
||||||
|
if (colattr.DbType.IndexOf("NOT NULL") == -1 && tp.Value.isnullable == false) colattr.DbType += " NOT NULL";
|
||||||
|
|
||||||
|
var col = new ColumnInfo {
|
||||||
|
Table = trytb,
|
||||||
|
CsName = p.Name,
|
||||||
|
CsType = p.PropertyType,
|
||||||
|
Attribute = colattr
|
||||||
|
};
|
||||||
|
trytb.Columns.Add(colattr.Name, col);
|
||||||
|
trytb.ColumnsByCs.Add(p.Name, col);
|
||||||
|
}
|
||||||
|
trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary).ToArray();
|
||||||
|
_cacheGetTableByEntity.TryAdd(entity.FullName, trytb);
|
||||||
|
return trytb;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static T[] GetDbParamtersByObject<T>(string sql, object obj, string paramPrefix, Func<string, Type, object, T> constructorParamter) {
|
||||||
|
if (string.IsNullOrEmpty(sql) || obj == null) return new T[0];
|
||||||
|
var ttype = typeof(T);
|
||||||
|
var type = obj.GetType();
|
||||||
|
if (type == ttype) return new[] { (T)Convert.ChangeType(obj, type) };
|
||||||
|
var ret = new List<T>();
|
||||||
|
var ps = type.GetProperties();
|
||||||
|
foreach (var p in ps) {
|
||||||
|
if (sql.IndexOf($"{paramPrefix}{p.Name}", StringComparison.CurrentCultureIgnoreCase) == -1) continue;
|
||||||
|
var pvalue = p.GetValue(obj);
|
||||||
|
if (p.PropertyType == ttype) ret.Add((T)Convert.ChangeType(pvalue, ttype));
|
||||||
|
else ret.Add(constructorParamter(p.Name, p.PropertyType, pvalue));
|
||||||
|
}
|
||||||
|
return ret.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static (object value, int dataIndex) ExecuteArrayRowReadClassOrTuple(Type type, Dictionary<string, int> names, object[] row, int dataIndex = 0) {
|
||||||
|
if (type.Namespace == "System" && (type.FullName == "System.String" || type.IsValueType)) { //值类型,或者元组
|
||||||
|
bool isTuple = type.Name.StartsWith("ValueTuple`");
|
||||||
|
if (isTuple) {
|
||||||
|
var fs = type.GetFields();
|
||||||
|
var types = new Type[fs.Length];
|
||||||
|
var parms = new object[fs.Length];
|
||||||
|
for (int a = 0; a < fs.Length; a++) {
|
||||||
|
types[a] = fs[a].FieldType;
|
||||||
|
var read = ExecuteArrayRowReadClassOrTuple(types[a], names, row, dataIndex);
|
||||||
|
if (read.dataIndex > dataIndex) dataIndex = read.dataIndex;
|
||||||
|
parms[a] = read.value;
|
||||||
|
}
|
||||||
|
var constructor = type.GetConstructor(types);
|
||||||
|
return (constructor?.Invoke(parms), dataIndex);
|
||||||
|
}
|
||||||
|
return (dataIndex >= row.Length || row[dataIndex] == DBNull.Value ? null : Convert.ChangeType(row[dataIndex], type), dataIndex + 1);
|
||||||
|
}
|
||||||
|
if (type == typeof(object) && names != null) {
|
||||||
|
dynamic expando = new System.Dynamic.ExpandoObject(); //动态类型字段 可读可写
|
||||||
|
var expandodic = (IDictionary<string, object>)expando;
|
||||||
|
foreach (var name in names)
|
||||||
|
expandodic[Utils.GetCsName(name.Key)] = row[name.Value];
|
||||||
|
return (expando, names.Count);
|
||||||
|
}
|
||||||
|
//类注入属性
|
||||||
|
var consturct = type.GetConstructor(new Type[0]);
|
||||||
|
var value = consturct.Invoke(new object[0]);
|
||||||
|
var ps = type.GetProperties();
|
||||||
|
foreach(var p in ps) {
|
||||||
|
var tryidx = dataIndex;
|
||||||
|
if (names != null && names.TryGetValue(p.Name, out tryidx) == false) continue;
|
||||||
|
var read = ExecuteArrayRowReadClassOrTuple(p.PropertyType, names, row, tryidx);
|
||||||
|
if (read.dataIndex > dataIndex) dataIndex = read.dataIndex;
|
||||||
|
FillPropertyValue(value, p.Name, read.value);
|
||||||
|
//p.SetValue(value, read.value);
|
||||||
|
}
|
||||||
|
return (value, dataIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void FillPropertyValue(object info, string memberAccessPath, object value) {
|
||||||
|
var current = info;
|
||||||
|
PropertyInfo prop = null;
|
||||||
|
var members = memberAccessPath.Split('.');
|
||||||
|
for (var a = 0; a < members.Length; a++) {
|
||||||
|
var type = current.GetType();
|
||||||
|
prop = type.GetProperty(members[a], BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
|
||||||
|
if (prop == null) throw new Exception(string.Concat(type.FullName, " 没有定义属性 ", members[a]));
|
||||||
|
if (a < members.Length - 1) current = prop.GetValue(current);
|
||||||
|
}
|
||||||
|
if (value == null || value == DBNull.Value) {
|
||||||
|
prop.SetValue(current, null, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var propType = prop.PropertyType;
|
||||||
|
if (propType.FullName.StartsWith("System.Nullable`1[")) propType = propType.GenericTypeArguments.First();
|
||||||
|
if (propType.IsEnum) {
|
||||||
|
var valueStr = string.Concat(value);
|
||||||
|
if (string.IsNullOrEmpty(valueStr) == false) prop.SetValue(current, Enum.Parse(propType, valueStr), null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (propType != value.GetType()) {
|
||||||
|
prop.SetValue(current, Convert.ChangeType(value, propType), null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prop.SetValue(current, value, null);
|
||||||
|
}
|
||||||
|
internal static string GetCsName(string name) {
|
||||||
|
name = Regex.Replace(name.TrimStart('@'), @"[^\w]", "_");
|
||||||
|
return char.IsLetter(name, 0) ? name : string.Concat("_", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
FreeSql/MySql/Curd/MySqlDelete.cs
Normal file
25
FreeSql/MySql/Curd/MySqlDelete.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql.Curd {
|
||||||
|
|
||||||
|
class MySqlDelete<T1> : Internal.CommonProvider.DeleteProvider<T1> where T1 : class {
|
||||||
|
public MySqlDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||||
|
: base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<T1> ExecuteDeleted() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(this.ToSql()).Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
return _orm.Ado.Query<T1>(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
FreeSql/MySql/Curd/MySqlInsert.cs
Normal file
28
FreeSql/MySql/Curd/MySqlInsert.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql.Curd {
|
||||||
|
|
||||||
|
class MySqlInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class {
|
||||||
|
public MySqlInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||||
|
: base(orm, commonUtils, commonExpression) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long ExecuteIdentity() => int.TryParse(string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, string.Concat(this.ToSql(), "; SELECT LAST_INSERT_ID();"), _params)), out var trylng) ? trylng : 0;
|
||||||
|
|
||||||
|
public override List<T1> ExecuteInserted() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(this.ToSql()).Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
return _orm.Ado.Query<T1>(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
FreeSql/MySql/Curd/MySqlSelect.cs
Normal file
114
FreeSql/MySql/Curd/MySqlSelect.cs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql.Curd {
|
||||||
|
|
||||||
|
class MySqlSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1> where T1 : class {
|
||||||
|
|
||||||
|
internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List<SelectTableInfo> _tables) {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(_select).Append(field).Append(" \r\nFROM ");
|
||||||
|
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
|
||||||
|
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
|
||||||
|
for (var a = 0; a < tbsfrom.Length; a++) {
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tbsfrom[a].Table.DbName)).Append(" ").Append(tbsfrom[a].Alias);
|
||||||
|
if (tbsjoin.Length > 0) {
|
||||||
|
//如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
|
||||||
|
for (var b = 1; b < tbsfrom.Length; b++)
|
||||||
|
sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbsfrom[b].Table.DbName)).Append(" ").Append(tbsfrom[b].Alias).Append(" ON 1 = 1");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (a < tbsfrom.Length - 1) sb.Append(", ");
|
||||||
|
}
|
||||||
|
foreach (var tb in tbsjoin) {
|
||||||
|
switch (tb.Type) {
|
||||||
|
case SelectTableInfoType.LeftJoin:
|
||||||
|
sb.Append(" \r\nLEFT JOIN ");
|
||||||
|
break;
|
||||||
|
case SelectTableInfoType.InnerJoin:
|
||||||
|
sb.Append(" \r\nINNER JOIN ");
|
||||||
|
break;
|
||||||
|
case SelectTableInfoType.RightJoin:
|
||||||
|
sb.Append(" \r\nRIGHT JOIN ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tb.Table.DbName)).Append(" ").Append(tb.Alias).Append(" ON ").Append(tb.On);
|
||||||
|
}
|
||||||
|
if (_join.Length > 0) sb.Append(_join);
|
||||||
|
|
||||||
|
var sbqf = new StringBuilder();
|
||||||
|
foreach (var tb in _tables) {
|
||||||
|
if (string.IsNullOrEmpty(tb.Table.SelectFilter) == false)
|
||||||
|
sbqf.Append(" AND (").Append(tb.Table.SelectFilter.Replace("a.", $"{tb.Alias}.")).Append(")");
|
||||||
|
}
|
||||||
|
if (_where.Length > 0) {
|
||||||
|
sb.Append(" \r\nWHERE ").Append(_where.ToString().Substring(5));
|
||||||
|
if (sbqf.Length > 0) sb.Append(sbqf.ToString());
|
||||||
|
} else {
|
||||||
|
if (sbqf.Length > 0) sb.Append(" \r\nWHERE ").Append(sbqf.Remove(0, 5));
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(_groupby) == false) {
|
||||||
|
sb.Append(_groupby);
|
||||||
|
if (string.IsNullOrEmpty(_having) == false)
|
||||||
|
sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
|
||||||
|
}
|
||||||
|
sb.Append(_orderby);
|
||||||
|
if (_skip > 0 || _limit > 0)
|
||||||
|
sb.Append(" \r\nlimit ").Append(Math.Max(0, _skip)).Append(",").Append(_limit > 0 ? _limit : -1);
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); MySqlSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); MySqlSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); MySqlSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); MySqlSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); MySqlSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); MySqlSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); MySqlSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); MySqlSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T1 : class where T2 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T1 : class where T2 : class where T3 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T1 : class where T2 : class where T3 : class where T4 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2, T3, T4, T5> : FreeSql.Internal.CommonProvider.Select5Provider<T1, T2, T3, T4, T5> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2, T3, T4, T5, T6> : FreeSql.Internal.CommonProvider.Select6Provider<T1, T2, T3, T4, T5, T6> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2, T3, T4, T5, T6, T7> : FreeSql.Internal.CommonProvider.Select7Provider<T1, T2, T3, T4, T5, T6, T7> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8> : FreeSql.Internal.CommonProvider.Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class MySqlSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : FreeSql.Internal.CommonProvider.Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class {
|
||||||
|
public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => MySqlSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
}
|
49
FreeSql/MySql/Curd/MySqlUpdate.cs
Normal file
49
FreeSql/MySql/Curd/MySqlUpdate.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql.Curd {
|
||||||
|
|
||||||
|
class MySqlUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1> where T1 : class {
|
||||||
|
|
||||||
|
public MySqlUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||||
|
: base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<T1> ExecuteUpdated() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(this.ToSql()).Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
return _orm.Ado.Query<T1>(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) {
|
||||||
|
if (_table.Primarys.Length > 1) caseWhen.Append("CONCAT(");
|
||||||
|
var pkidx = 0;
|
||||||
|
foreach (var pk in _table.Primarys) {
|
||||||
|
if (pkidx > 0) caseWhen.Append(", ");
|
||||||
|
caseWhen.Append(_commonUtils.QuoteSqlName(pk.Attribute.Name));
|
||||||
|
++pkidx;
|
||||||
|
}
|
||||||
|
if (_table.Primarys.Length > 1) caseWhen.Append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d) {
|
||||||
|
if (_table.Primarys.Length > 1) sb.Append("CONCAT(");
|
||||||
|
var pkidx = 0;
|
||||||
|
foreach (var pk in _table.Primarys) {
|
||||||
|
if (pkidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(pk.CsName, out var tryp2) ? tryp2.GetValue(d) : null));
|
||||||
|
++pkidx;
|
||||||
|
}
|
||||||
|
if (_table.Primarys.Length > 1) sb.Append(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
FreeSql/MySql/MySqlAdo/MySqlAdo.cs
Normal file
63
FreeSql/MySql/MySqlAdo/MySqlAdo.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
using SafeObjectPool;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql {
|
||||||
|
class MySqlAdo : FreeSql.Internal.CommonProvider.AdoProvider {
|
||||||
|
CommonUtils _util;
|
||||||
|
|
||||||
|
public MySqlAdo() : base(null, null) { }
|
||||||
|
public MySqlAdo(CommonUtils util, ICache cache, ILogger log, string masterConnectionString, string[] slaveConnectionStrings) : base(cache, log) {
|
||||||
|
this._util = util;
|
||||||
|
MasterPool = new MySqlConnectionPool("主库", masterConnectionString, null, null);
|
||||||
|
if (slaveConnectionStrings != null) {
|
||||||
|
foreach (var slaveConnectionString in slaveConnectionStrings) {
|
||||||
|
var slavePool = new MySqlConnectionPool($"从库{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
|
||||||
|
SlavePools.Add(slavePool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public override object AddslashesProcessParam(object param) {
|
||||||
|
if (param == null) return "NULL";
|
||||||
|
if (param is bool || param is bool?)
|
||||||
|
return (bool)param ? 1 : 0;
|
||||||
|
else if (param is string)
|
||||||
|
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
|
||||||
|
else if (param is Enum)
|
||||||
|
return ((Enum)param).ToInt64();
|
||||||
|
else if (decimal.TryParse(string.Concat(param), out var trydec))
|
||||||
|
return param;
|
||||||
|
else if (param is DateTime) {
|
||||||
|
DateTime dt = (DateTime)param;
|
||||||
|
return string.Concat("'", dt.ToString("yyyy-MM-dd HH:mm:ss"), "'");
|
||||||
|
} else if (param is DateTime?) {
|
||||||
|
DateTime? dt = param as DateTime?;
|
||||||
|
return string.Concat("'", dt.Value.ToString("yyyy-MM-dd HH:mm:ss"), "'");
|
||||||
|
} else if (param is IEnumerable) {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var ie = param as IEnumerable;
|
||||||
|
foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z));
|
||||||
|
return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString();
|
||||||
|
} else {
|
||||||
|
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
|
||||||
|
//if (param is string) return string.Concat('N', nparms[a]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DbCommand CreateCommand() {
|
||||||
|
return new MySqlCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex) {
|
||||||
|
(pool as MySqlConnectionPool).Return(conn, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
|
||||||
|
}
|
||||||
|
}
|
36
FreeSql/MySql/MySqlAdo/MySqlAdoExtensions.cs
Normal file
36
FreeSql/MySql/MySqlAdo/MySqlAdoExtensions.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
public static class MySqlAdoExtensions {
|
||||||
|
public static object GetEnum<T>(this IDataReader dr, int index) {
|
||||||
|
string value = dr.GetString(index);
|
||||||
|
Type t = typeof(T);
|
||||||
|
foreach (var f in t.GetFields())
|
||||||
|
if (f.GetCustomAttribute<DescriptionAttribute>()?.Description == value || f.Name == value) return Enum.Parse(t, f.Name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToDescriptionOrString(this Enum item) {
|
||||||
|
string name = item.ToString();
|
||||||
|
DescriptionAttribute desc = item.GetType().GetField(name)?.GetCustomAttribute<DescriptionAttribute>();
|
||||||
|
return desc?.Description ?? name;
|
||||||
|
}
|
||||||
|
public static long ToInt64(this Enum item) {
|
||||||
|
return Convert.ToInt64(item);
|
||||||
|
}
|
||||||
|
public static IEnumerable<T> ToSet<T>(this long value) {
|
||||||
|
List<T> ret = new List<T>();
|
||||||
|
if (value == 0) return ret;
|
||||||
|
Type t = typeof(T);
|
||||||
|
foreach (FieldInfo f in t.GetFields()) {
|
||||||
|
if (f.FieldType != t) continue;
|
||||||
|
object o = Enum.Parse(t, f.Name);
|
||||||
|
long v = (long) o;
|
||||||
|
if ((value & v) == v) ret.Add((T) o);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
125
FreeSql/MySql/MySqlAdo/MySqlConnectionPool.cs
Normal file
125
FreeSql/MySql/MySqlAdo/MySqlConnectionPool.cs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
using SafeObjectPool;
|
||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql {
|
||||||
|
|
||||||
|
class MySqlConnectionPool : ObjectPool<DbConnection> {
|
||||||
|
|
||||||
|
internal Action availableHandler;
|
||||||
|
internal Action unavailableHandler;
|
||||||
|
|
||||||
|
public MySqlConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null) {
|
||||||
|
var policy = new MySqlConnectionPoolPolicy {
|
||||||
|
_pool = this,
|
||||||
|
Name = name
|
||||||
|
};
|
||||||
|
this.Policy = policy;
|
||||||
|
policy.ConnectionString = connectionString;
|
||||||
|
|
||||||
|
this.availableHandler = availableHandler;
|
||||||
|
this.unavailableHandler = unavailableHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false) {
|
||||||
|
if (exception != null && exception is MySqlException) {
|
||||||
|
try { if ((obj.Value as MySqlConnection).Ping() == false) obj.Value.Open(); } catch { base.SetUnavailable(exception); }
|
||||||
|
}
|
||||||
|
base.Return(obj, isRecreate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MySqlConnectionPoolPolicy : IPolicy<DbConnection> {
|
||||||
|
|
||||||
|
internal MySqlConnectionPool _pool;
|
||||||
|
public string Name { get; set; } = "MySql MySqlConnection 对象池";
|
||||||
|
public int PoolSize { get; set; } = 100;
|
||||||
|
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
||||||
|
public int AsyncGetCapacity { get; set; } = 10000;
|
||||||
|
public bool IsThrowGetTimeoutException { get; set; } = true;
|
||||||
|
public int CheckAvailableInterval { get; set; } = 5;
|
||||||
|
|
||||||
|
private string _connectionString;
|
||||||
|
public string ConnectionString {
|
||||||
|
get => _connectionString;
|
||||||
|
set {
|
||||||
|
_connectionString = value ?? "";
|
||||||
|
Match m = Regex.Match(_connectionString, @"Max\s*pool\s*size\s*=\s*(\d+)", RegexOptions.IgnoreCase);
|
||||||
|
if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100;
|
||||||
|
PoolSize = poolsize;
|
||||||
|
|
||||||
|
var initConns = new Object<DbConnection>[poolsize];
|
||||||
|
for (var a = 0; a < poolsize; a++) try { initConns[a] = _pool.Get(); } catch { }
|
||||||
|
foreach (var conn in initConns) _pool.Return(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool OnCheckAvailable(Object<DbConnection> obj) {
|
||||||
|
if ((obj.Value as MySqlConnection).Ping() == false) obj.Value.Open();
|
||||||
|
return (obj.Value as MySqlConnection).Ping();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbConnection OnCreate() {
|
||||||
|
var conn = new MySqlConnection(_connectionString);
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDestroy(DbConnection obj) {
|
||||||
|
if (obj.State != ConnectionState.Closed) obj.Close();
|
||||||
|
obj.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGet(Object<DbConnection> obj) {
|
||||||
|
|
||||||
|
if (_pool.IsAvailable) {
|
||||||
|
|
||||||
|
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (obj.Value as MySqlConnection).Ping() == false) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
obj.Value.Open();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (_pool.SetUnavailable(ex) == true)
|
||||||
|
throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async public Task OnGetAsync(Object<DbConnection> obj) {
|
||||||
|
|
||||||
|
if (_pool.IsAvailable) {
|
||||||
|
|
||||||
|
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (obj.Value as MySqlConnection).Ping() == false) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
await obj.Value.OpenAsync();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (_pool.SetUnavailable(ex) == true)
|
||||||
|
throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnGetTimeout() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReturn(Object<DbConnection> obj) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAvailable() {
|
||||||
|
_pool.availableHandler?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUnavailable() {
|
||||||
|
_pool.unavailableHandler?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
308
FreeSql/MySql/MySqlAdo/MygisTypes.cs
Normal file
308
FreeSql/MySql/MySqlAdo/MygisTypes.cs
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
public struct MygisCoordinate2D : IEquatable<MygisCoordinate2D> {
|
||||||
|
public double X { get; }
|
||||||
|
public double Y { get; }
|
||||||
|
public MygisCoordinate2D(double x, double y) { X = x; Y = y; }
|
||||||
|
|
||||||
|
public bool Equals(MygisCoordinate2D c) => X == c.X && Y == c.Y;
|
||||||
|
public override int GetHashCode() => X.GetHashCode() ^ MygisGeometry.RotateShift(Y.GetHashCode(), sizeof(int) / 2);
|
||||||
|
public override bool Equals(object obj) => obj is MygisCoordinate2D && Equals((MygisCoordinate2D) obj);
|
||||||
|
public static bool operator ==(MygisCoordinate2D left, MygisCoordinate2D right) => Equals(left, right);
|
||||||
|
public static bool operator !=(MygisCoordinate2D left, MygisCoordinate2D right) => !Equals(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class MygisGeometry {
|
||||||
|
protected abstract int GetLenHelper();
|
||||||
|
internal int GetLen(bool includeSRID) => 5 + (SRID == 0 || !includeSRID ? 0 : 4) + GetLenHelper();
|
||||||
|
public uint SRID { get; set; } = 0;
|
||||||
|
internal static int RotateShift(int val, int shift) => (val << shift) | (val >> (sizeof(int) - shift));
|
||||||
|
public override string ToString() => this.AsText();
|
||||||
|
public string AsText() {
|
||||||
|
if (this is MygisPoint) {
|
||||||
|
var obj = this as MygisPoint;
|
||||||
|
return $"POINT({obj.X} {obj.Y})";
|
||||||
|
}
|
||||||
|
if (this is MygisLineString) {
|
||||||
|
var obj = this as MygisLineString;
|
||||||
|
return obj?.PointCount > 0 ? $"LINESTRING({string.Join(",", obj.Select(a => $"{a.X} {a.Y}"))})" : null;
|
||||||
|
}
|
||||||
|
if (this is MygisPolygon) {
|
||||||
|
var obj = (this as MygisPolygon).Where(z => z.Count() > 1 && z.First().Equals(z.Last()));
|
||||||
|
return obj.Any() ? $"POLYGON(({string.Join("),(", obj.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))}))" : null;
|
||||||
|
}
|
||||||
|
if (this is MygisMultiPoint) {
|
||||||
|
var obj = this as MygisMultiPoint;
|
||||||
|
return obj?.PointCount > 0 ? $"MULTIPOINT({string.Join(",", obj.Select(a => $"{a.X} {a.Y}"))})" : null;
|
||||||
|
}
|
||||||
|
if (this is MygisMultiLineString) {
|
||||||
|
var obj = this as MygisMultiLineString;
|
||||||
|
return obj.LineCount > 0 ? $"MULTILINESTRING(({string.Join("),(", obj.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))}))" : null;
|
||||||
|
}
|
||||||
|
if (this is MygisMultiPolygon) {
|
||||||
|
var obj = (this as MygisMultiPolygon)?.Where(z => z.Where(y => y.Count() > 1 && y.First().Equals(y.Last())).Any());
|
||||||
|
return obj.Any() ? $"MULTIPOLYGON((({string.Join(")),((", obj.Select(d => string.Join("),(", d.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))))})))" : null;
|
||||||
|
}
|
||||||
|
return base.ToString();
|
||||||
|
}
|
||||||
|
static readonly Regex regexMygisPoint = new Regex(@"\s*(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s*");
|
||||||
|
static readonly Regex regexSplit1 = new Regex(@"\)\s*,\s*\(");
|
||||||
|
static readonly Regex regexSplit2 = new Regex(@"\)\s*\)\s*,\s*\(\s*\(");
|
||||||
|
public static MygisGeometry Parse(string wkt) {
|
||||||
|
if (string.IsNullOrEmpty(wkt)) return null;
|
||||||
|
wkt = wkt.Trim();
|
||||||
|
if (wkt.StartsWith("point", StringComparison.CurrentCultureIgnoreCase)) return ParsePoint(wkt.Substring(5).Trim('(', ')'));
|
||||||
|
else if (wkt.StartsWith("linestring", StringComparison.CurrentCultureIgnoreCase)) return new MygisLineString(ParseLineString(wkt.Substring(10).Trim('(', ')')));
|
||||||
|
else if (wkt.StartsWith("polygon", StringComparison.CurrentCultureIgnoreCase)) return new MygisPolygon(ParsePolygon(wkt.Substring(7).Trim('(', ')')));
|
||||||
|
else if (wkt.StartsWith("multipoint", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiPoint(ParseLineString(wkt.Substring(10).Trim('(', ')')));
|
||||||
|
else if (wkt.StartsWith("multilinestring", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiLineString(ParseMultiLineString(wkt.Substring(15).Trim('(', ')')));
|
||||||
|
else if (wkt.StartsWith("multipolygon", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiPolygon(ParseMultiPolygon(wkt.Substring(12).Trim('(', ')')));
|
||||||
|
throw new NotImplementedException($"MygisGeometry.Parse 未现实 \"{wkt}\"");
|
||||||
|
}
|
||||||
|
static MygisPoint ParsePoint(string str) {
|
||||||
|
var m = regexMygisPoint.Match(str);
|
||||||
|
if (m.Success == false) return null;
|
||||||
|
return new MygisPoint(double.TryParse(m.Groups[1].Value, out var tryd) ? tryd : 0, double.TryParse(m.Groups[2].Value, out tryd) ? tryd : 0);
|
||||||
|
}
|
||||||
|
static MygisCoordinate2D[] ParseLineString(string str) {
|
||||||
|
var ms = regexMygisPoint.Matches(str);
|
||||||
|
var points = new MygisCoordinate2D[ms.Count];
|
||||||
|
for (var a = 0; a < ms.Count; a++) points[a] = new MygisCoordinate2D(double.TryParse(ms[a].Groups[1].Value, out var tryd) ? tryd : 0, double.TryParse(ms[a].Groups[2].Value, out tryd) ? tryd : 0);
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
static MygisCoordinate2D[][] ParsePolygon(string str) {
|
||||||
|
return regexSplit1.Split(str).Select(s => ParseLineString(s)).Where(a => a.Length > 1 && a.First().Equals(a.Last())).ToArray();
|
||||||
|
}
|
||||||
|
static MygisLineString[] ParseMultiLineString(string str) {
|
||||||
|
return regexSplit1.Split(str).Select(s => new MygisLineString(ParseLineString(s))).ToArray();
|
||||||
|
}
|
||||||
|
static MygisPolygon[] ParseMultiPolygon(string str) {
|
||||||
|
return regexSplit2.Split(str).Select(s => new MygisPolygon(ParsePolygon(s))).ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MygisPoint : MygisGeometry, IEquatable<MygisPoint> {
|
||||||
|
MygisCoordinate2D _coord;
|
||||||
|
protected override int GetLenHelper() => 16;
|
||||||
|
public double X => _coord.X;
|
||||||
|
public double Y => _coord.Y;
|
||||||
|
|
||||||
|
public MygisPoint(double x, double y) {
|
||||||
|
_coord = new MygisCoordinate2D(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(MygisPoint other) => !ReferenceEquals(other, null) && _coord.Equals(other._coord);
|
||||||
|
public override bool Equals(object obj) => Equals(obj as MygisPoint);
|
||||||
|
public static bool operator ==(MygisPoint x, MygisPoint y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
|
||||||
|
public static bool operator !=(MygisPoint x, MygisPoint y) => !(x == y);
|
||||||
|
public override int GetHashCode() => X.GetHashCode() ^ RotateShift(Y.GetHashCode(), sizeof(int) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MygisLineString : MygisGeometry, IEquatable<MygisLineString>, IEnumerable<MygisCoordinate2D> {
|
||||||
|
readonly MygisCoordinate2D[] _points;
|
||||||
|
protected override int GetLenHelper() => 4 + _points.Length * 16;
|
||||||
|
public IEnumerator<MygisCoordinate2D> GetEnumerator() => ((IEnumerable<MygisCoordinate2D>) _points).GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public MygisCoordinate2D this[int index] => _points[index];
|
||||||
|
public int PointCount => _points.Length;
|
||||||
|
|
||||||
|
public MygisLineString(IEnumerable<MygisCoordinate2D> points) {
|
||||||
|
_points = points.ToArray();
|
||||||
|
}
|
||||||
|
public MygisLineString(MygisCoordinate2D[] points) {
|
||||||
|
_points = points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(MygisLineString other) {
|
||||||
|
if (ReferenceEquals(other, null)) return false;
|
||||||
|
if (_points.Length != other._points.Length) return false;
|
||||||
|
for (var i = 0; i < _points.Length; i++)
|
||||||
|
if (!_points[i].Equals(other._points[i])) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj) => Equals(obj as MygisLineString);
|
||||||
|
public static bool operator ==(MygisLineString x, MygisLineString y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
|
||||||
|
public static bool operator !=(MygisLineString x, MygisLineString y) => !(x == y);
|
||||||
|
public override int GetHashCode() {
|
||||||
|
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
|
||||||
|
foreach (var t in _points) ret ^= RotateShift(t.GetHashCode(), ret % sizeof(int));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MygisPolygon : MygisGeometry, IEquatable<MygisPolygon>, IEnumerable<IEnumerable<MygisCoordinate2D>> {
|
||||||
|
readonly MygisCoordinate2D[][] _rings;
|
||||||
|
protected override int GetLenHelper() => 4 + _rings.Length * 4 + TotalPointCount * 16;
|
||||||
|
public MygisCoordinate2D this[int ringIndex, int pointIndex] => _rings[ringIndex][pointIndex];
|
||||||
|
public MygisCoordinate2D[] this[int ringIndex] => _rings[ringIndex];
|
||||||
|
public IEnumerator<IEnumerable<MygisCoordinate2D>> GetEnumerator() => ((IEnumerable<IEnumerable<MygisCoordinate2D>>) _rings).GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public int RingCount => _rings.Length;
|
||||||
|
public int TotalPointCount => _rings.Sum(r => r.Length);
|
||||||
|
|
||||||
|
public MygisPolygon(MygisCoordinate2D[][] rings) {
|
||||||
|
_rings = rings;
|
||||||
|
}
|
||||||
|
public MygisPolygon(IEnumerable<IEnumerable<MygisCoordinate2D>> rings) {
|
||||||
|
_rings = rings.Select(x => x.ToArray()).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(MygisPolygon other) {
|
||||||
|
if (ReferenceEquals(other, null)) return false;
|
||||||
|
if (_rings.Length != other._rings.Length) return false;
|
||||||
|
for (var i = 0; i < _rings.Length; i++) {
|
||||||
|
if (_rings[i].Length != other._rings[i].Length) return false;
|
||||||
|
for (var j = 0; j < _rings[i].Length; j++)
|
||||||
|
if (!_rings[i][j].Equals(other._rings[i][j])) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj) => Equals(obj as MygisPolygon);
|
||||||
|
public static bool operator ==(MygisPolygon x, MygisPolygon y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
|
||||||
|
public static bool operator !=(MygisPolygon x, MygisPolygon y) => !(x == y);
|
||||||
|
public override int GetHashCode() {
|
||||||
|
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
|
||||||
|
for (var i = 0; i < _rings.Length; i++)
|
||||||
|
for (var j = 0; j < _rings[i].Length; j++)
|
||||||
|
ret ^= RotateShift(_rings[i][j].GetHashCode(), ret % sizeof(int));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MygisMultiPoint : MygisGeometry, IEquatable<MygisMultiPoint>, IEnumerable<MygisCoordinate2D> {
|
||||||
|
readonly MygisCoordinate2D[] _points;
|
||||||
|
protected override int GetLenHelper() => 4 + _points.Length * 21;
|
||||||
|
public IEnumerator<MygisCoordinate2D> GetEnumerator() => ((IEnumerable<MygisCoordinate2D>) _points).GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public MygisCoordinate2D this[int indexer] => _points[indexer];
|
||||||
|
public int PointCount => _points.Length;
|
||||||
|
|
||||||
|
public MygisMultiPoint(MygisCoordinate2D[] points) {
|
||||||
|
_points = points;
|
||||||
|
}
|
||||||
|
public MygisMultiPoint(IEnumerable<MygisPoint> points) {
|
||||||
|
_points = points.Select(x => new MygisCoordinate2D(x.X, x.Y)).ToArray();
|
||||||
|
}
|
||||||
|
public MygisMultiPoint(IEnumerable<MygisCoordinate2D> points) {
|
||||||
|
_points = points.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(MygisMultiPoint other) {
|
||||||
|
if (ReferenceEquals(other, null)) return false;
|
||||||
|
if (_points.Length != other._points.Length) return false;
|
||||||
|
for (var i = 0; i < _points.Length; i++)
|
||||||
|
if (!_points[i].Equals(other._points[i])) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj) => Equals(obj as MygisMultiPoint);
|
||||||
|
public static bool operator ==(MygisMultiPoint x, MygisMultiPoint y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
|
||||||
|
public static bool operator !=(MygisMultiPoint x, MygisMultiPoint y) => !(x == y);
|
||||||
|
public override int GetHashCode() {
|
||||||
|
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
|
||||||
|
for (var i = 0; i < _points.Length; i++) ret ^= RotateShift(_points[i].GetHashCode(), ret % sizeof(int));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class MygisMultiLineString : MygisGeometry,
|
||||||
|
IEquatable<MygisMultiLineString>, IEnumerable<MygisLineString> {
|
||||||
|
readonly MygisLineString[] _lineStrings;
|
||||||
|
protected override int GetLenHelper() {
|
||||||
|
var n = 4;
|
||||||
|
for (var i = 0; i < _lineStrings.Length; i++) n += _lineStrings[i].GetLen(false);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
public IEnumerator<MygisLineString> GetEnumerator() => ((IEnumerable<MygisLineString>) _lineStrings).GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public MygisLineString this[int index] => _lineStrings[index];
|
||||||
|
public int LineCount => _lineStrings.Length;
|
||||||
|
|
||||||
|
internal MygisMultiLineString(MygisCoordinate2D[][] pointArray) {
|
||||||
|
_lineStrings = new MygisLineString[pointArray.Length];
|
||||||
|
for (var i = 0; i < pointArray.Length; i++)
|
||||||
|
_lineStrings[i] = new MygisLineString(pointArray[i]);
|
||||||
|
}
|
||||||
|
public MygisMultiLineString(MygisLineString[] linestrings) {
|
||||||
|
_lineStrings = linestrings;
|
||||||
|
}
|
||||||
|
public MygisMultiLineString(IEnumerable<MygisLineString> linestrings) {
|
||||||
|
_lineStrings = linestrings.ToArray();
|
||||||
|
}
|
||||||
|
public MygisMultiLineString(IEnumerable<IEnumerable<MygisCoordinate2D>> pointList) {
|
||||||
|
_lineStrings = pointList.Select(x => new MygisLineString(x)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(MygisMultiLineString other) {
|
||||||
|
if (ReferenceEquals(other, null)) return false;
|
||||||
|
if (_lineStrings.Length != other._lineStrings.Length) return false;
|
||||||
|
for (var i = 0; i < _lineStrings.Length; i++)
|
||||||
|
if (_lineStrings[i] != other._lineStrings[i]) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj) => Equals(obj as MygisMultiLineString);
|
||||||
|
public static bool operator ==(MygisMultiLineString x, MygisMultiLineString y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
|
||||||
|
public static bool operator !=(MygisMultiLineString x, MygisMultiLineString y) => !(x == y);
|
||||||
|
public override int GetHashCode() {
|
||||||
|
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
|
||||||
|
for (var i = 0; i < _lineStrings.Length; i++) ret ^= RotateShift(_lineStrings[i].GetHashCode(), ret % sizeof(int));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MygisMultiPolygon : MygisGeometry, IEquatable<MygisMultiPolygon>, IEnumerable<MygisPolygon> {
|
||||||
|
readonly MygisPolygon[] _polygons;
|
||||||
|
protected override int GetLenHelper() {
|
||||||
|
var n = 4;
|
||||||
|
for (var i = 0; i < _polygons.Length; i++) n += _polygons[i].GetLen(false);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
public IEnumerator<MygisPolygon> GetEnumerator() => ((IEnumerable<MygisPolygon>) _polygons).GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public MygisPolygon this[int index] => _polygons[index];
|
||||||
|
public int PolygonCount => _polygons.Length;
|
||||||
|
|
||||||
|
public MygisMultiPolygon(MygisPolygon[] polygons) {
|
||||||
|
_polygons = polygons;
|
||||||
|
}
|
||||||
|
public MygisMultiPolygon(IEnumerable<MygisPolygon> polygons) {
|
||||||
|
_polygons = polygons.ToArray();
|
||||||
|
}
|
||||||
|
public MygisMultiPolygon(IEnumerable<IEnumerable<IEnumerable<MygisCoordinate2D>>> ringList) {
|
||||||
|
_polygons = ringList.Select(x => new MygisPolygon(x)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(MygisMultiPolygon other) {
|
||||||
|
if (ReferenceEquals(other, null)) return false;
|
||||||
|
if (_polygons.Length != other._polygons.Length) return false;
|
||||||
|
for (var i = 0; i < _polygons.Length; i++) if (_polygons[i] != other._polygons[i]) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj) => obj is MygisMultiPolygon && Equals((MygisMultiPolygon) obj);
|
||||||
|
public static bool operator ==(MygisMultiPolygon x, MygisMultiPolygon y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
|
||||||
|
public static bool operator !=(MygisMultiPolygon x, MygisMultiPolygon y) => !(x == y);
|
||||||
|
public override int GetHashCode() {
|
||||||
|
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
|
||||||
|
for (var i = 0; i < _polygons.Length; i++) ret ^= RotateShift(_polygons[i].GetHashCode(), ret % sizeof(int));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class MygisTypesExtensions {
|
||||||
|
/// <summary>
|
||||||
|
/// 测量两个经纬度的距离,返回单位:米
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="that">经纬坐标1</param>
|
||||||
|
/// <param name="point">经纬坐标2</param>
|
||||||
|
/// <returns>返回距离(单位:米)</returns>
|
||||||
|
public static double Distance(this MygisPoint that, MygisPoint point) {
|
||||||
|
double radLat1 = (double)(that.Y) * Math.PI / 180d;
|
||||||
|
double radLng1 = (double)(that.X) * Math.PI / 180d;
|
||||||
|
double radLat2 = (double)(point.Y) * Math.PI / 180d;
|
||||||
|
double radLng2 = (double)(point.X) * Math.PI / 180d;
|
||||||
|
return 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin((radLat1 - radLat2) / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin((radLng1 - radLng2) / 2), 2))) * 6378137;
|
||||||
|
}
|
||||||
|
}
|
184
FreeSql/MySql/MySqlCodeFirst.cs
Normal file
184
FreeSql/MySql/MySqlCodeFirst.cs
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
using FreeSql.DatabaseModel;
|
||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql {
|
||||||
|
|
||||||
|
class MySqlCodeFirst : ICodeFirst {
|
||||||
|
IFreeSql _orm;
|
||||||
|
protected CommonUtils _commonUtils;
|
||||||
|
protected CommonExpression _commonExpression;
|
||||||
|
public MySqlCodeFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) {
|
||||||
|
_orm = orm;
|
||||||
|
_commonUtils = commonUtils;
|
||||||
|
_commonExpression = commonExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAutoSyncStructure { get; set; } = true;
|
||||||
|
|
||||||
|
static object _dicCsToDbLock = new object();
|
||||||
|
static Dictionary<string, (MySqlDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable)> _dicCsToDb = new Dictionary<string, (MySqlDbType type, string dbtype, string dbtypeFull, bool? isUnsigned, bool? isnullable)>() {
|
||||||
|
{ typeof(bool).FullName, (MySqlDbType.Bit, "bit","bit(1) NOT NULL", null, false) },{ typeof(bool?).FullName, (MySqlDbType.Bit, "bit","bit(1)", null, true) },
|
||||||
|
|
||||||
|
{ typeof(sbyte).FullName, (MySqlDbType.Byte, "tinyint", "tinyint(3) NOT NULL", false, false) },{ typeof(sbyte?).FullName, (MySqlDbType.Byte, "tinyint", "tinyint(3)", false, true) },
|
||||||
|
{ typeof(short).FullName, (MySqlDbType.Int16, "smallint","smallint(6) NOT NULL", false, false) },{ typeof(short?).FullName, (MySqlDbType.Int16, "smallint", "smallint(6)", false, true) },
|
||||||
|
{ typeof(int).FullName, (MySqlDbType.Int32, "int", "int(11) NOT NULL", false, false) },{ typeof(int?).FullName, (MySqlDbType.Int32, "int", "int(11)", false, true) },
|
||||||
|
{ typeof(long).FullName, (MySqlDbType.Int64, "bigint","bigint(20) NOT NULL", false, false) },{ typeof(long?).FullName, (MySqlDbType.Int64, "bigint","bigint(20)", false, true) },
|
||||||
|
|
||||||
|
{ typeof(byte).FullName, (MySqlDbType.UByte, "tinyint","tinyint(3) unsigned NOT NULL", true, false) },{ typeof(byte?).FullName, (MySqlDbType.UByte, "tinyint","tinyint(3) unsigned", true, true) },
|
||||||
|
{ typeof(ushort).FullName, (MySqlDbType.UInt16, "smallint","smallint(5) unsigned NOT NULL", true, false) },{ typeof(ushort?).FullName, (MySqlDbType.UInt16, "smallint", "smallint(5) unsigned", true, true) },
|
||||||
|
{ typeof(uint).FullName, (MySqlDbType.UInt32, "int", "int(10) unsigned NOT NULL", true, false) },{ typeof(uint?).FullName, (MySqlDbType.UInt32, "int", "int(10) unsigned", true, true) },
|
||||||
|
{ typeof(ulong).FullName, (MySqlDbType.UInt64, "bigint", "bigint(20) unsigned NOT NULL", true, false) },{ typeof(ulong?).FullName, (MySqlDbType.UInt64, "bigint", "bigint(20) unsigned", true, true) },
|
||||||
|
|
||||||
|
{ typeof(double).FullName, (MySqlDbType.Double, "double", "double NOT NULL", false, false) },{ typeof(double?).FullName, (MySqlDbType.Double, "double", "double", false, true) },
|
||||||
|
{ typeof(float).FullName, (MySqlDbType.Float, "float","float NOT NULL", false, false) },{ typeof(float?).FullName, (MySqlDbType.Float, "float","float", false, true) },
|
||||||
|
{ typeof(decimal).FullName, (MySqlDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false) },{ typeof(decimal?).FullName, (MySqlDbType.Decimal, "decimal", "decimal(10,2)", false, true) },
|
||||||
|
|
||||||
|
{ typeof(TimeSpan).FullName, (MySqlDbType.Time, "time","time NOT NULL", false, false) },{ typeof(TimeSpan?).FullName, (MySqlDbType.Time, "time", "time",false, true) },
|
||||||
|
{ typeof(DateTime).FullName, (MySqlDbType.DateTime, "datetime", "datetime NOT NULL", false, false) },{ typeof(DateTime?).FullName, (MySqlDbType.DateTime, "datetime", "datetime", false, true) },
|
||||||
|
|
||||||
|
{ typeof(byte[]).FullName, (MySqlDbType.VarBinary, "varbinary", "varbinary(255)", false, null) },
|
||||||
|
{ typeof(string).FullName, (MySqlDbType.VarChar, "varchar", "varchar(255)", false, null) },
|
||||||
|
|
||||||
|
{ typeof(Guid).FullName, (MySqlDbType.VarChar, "char", "char(36)", false, false) },{ typeof(Guid?).FullName, (MySqlDbType.VarChar, "char", "char(36)", false, true) },
|
||||||
|
|
||||||
|
{ typeof(MygisPoint).FullName, (MySqlDbType.Geometry, "point", "point", false, null) },
|
||||||
|
{ typeof(MygisLineString).FullName, (MySqlDbType.Geometry, "linestring", "linestring", false, null) },
|
||||||
|
{ typeof(MygisPolygon).FullName, (MySqlDbType.Geometry, "polygon", "polygon", false, null) },
|
||||||
|
{ typeof(MygisMultiPoint).FullName, (MySqlDbType.Geometry, "multipoint","multipoint", false, null) },
|
||||||
|
{ typeof(MygisMultiLineString).FullName, (MySqlDbType.Geometry, "multilinestring","multilinestring", false, null) },
|
||||||
|
{ typeof(MygisMultiPolygon).FullName, (MySqlDbType.Geometry, "multipolygon", "multipolygon", false, null) },
|
||||||
|
};
|
||||||
|
|
||||||
|
public (int type, string dbtype, string dbtypeFull, bool? isnullable)? GetDbInfo(Type type) {
|
||||||
|
if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new (int, string, string, bool?)?(((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable));
|
||||||
|
var enumType = type.IsEnum ? type : null;
|
||||||
|
if (enumType == null && type.FullName.StartsWith("System.Nullable`1[") && type.GenericTypeArguments.Length == 1 && type.GenericTypeArguments.First().IsEnum) enumType = type.GenericTypeArguments.First();
|
||||||
|
if (enumType != null) {
|
||||||
|
var names = string.Join(",", Enum.GetNames(enumType).Select(a => _commonUtils.FormatSql("{0}", a)));
|
||||||
|
var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ?
|
||||||
|
(MySqlDbType.Set, "set", $"set({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true) :
|
||||||
|
(MySqlDbType.Enum, "enum", $"enum({names}){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true);
|
||||||
|
if (_dicCsToDb.ContainsKey(type.FullName) == false) {
|
||||||
|
lock (_dicCsToDbLock) {
|
||||||
|
if (_dicCsToDb.ContainsKey(type.FullName) == false)
|
||||||
|
_dicCsToDb.Add(type.FullName, newItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetComparisonDDLStatements<TEntity>() => this.GetComparisonDDLStatements(typeof(TEntity));
|
||||||
|
public string GetComparisonDDLStatements(params Type[] entityTypes) {
|
||||||
|
string database = "";
|
||||||
|
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) {
|
||||||
|
database = conn.Value.Database;
|
||||||
|
}
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var entityType in entityTypes) {
|
||||||
|
if (sb.Length > 0) sb.Append("\r\n");
|
||||||
|
var tb = _commonUtils.GetTableByEntity(entityType);
|
||||||
|
var tboldname = tb.DbOldName?.Split(new[] { '.' }, 2); //旧表名
|
||||||
|
if (tboldname?.Length == 1) tboldname = new[] { database, tboldname[0] };
|
||||||
|
|
||||||
|
var isRenameTable = false;
|
||||||
|
var tbname = tb.DbName.Split(new[] { '.' }, 2);
|
||||||
|
if (tbname.Length == 1) tbname = new[] { database, tbname[0] };
|
||||||
|
if (_orm.Ado.ExecuteScalar(CommandType.Text, "SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}".FormatMySql(tbname)) == null) { //表不存在
|
||||||
|
|
||||||
|
if (tboldname != null && _orm.Ado.ExecuteScalar(CommandType.Text, "SELECT 1 FROM information_schema.TABLES WHERE table_schema={0} and table_name={1}".FormatMySql(tboldname)) != null) { //旧表存在
|
||||||
|
//修改表名
|
||||||
|
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(";\r\n");
|
||||||
|
isRenameTable = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//创建表
|
||||||
|
sb.Append("CREATE TABLE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" (");
|
||||||
|
foreach (var tbcol in tb.Columns.Values) {
|
||||||
|
sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ");
|
||||||
|
sb.Append(tbcol.Attribute.DbType.ToUpper());
|
||||||
|
if (tbcol.Attribute.IsIdentity && tbcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" AUTO_INCREMENT");
|
||||||
|
sb.Append(",");
|
||||||
|
}
|
||||||
|
if (tb.Primarys.Any() == false)
|
||||||
|
sb.Remove(sb.Length - 1, 1);
|
||||||
|
else {
|
||||||
|
sb.Append(" \r\n PRIMARY KEY (");
|
||||||
|
foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", ");
|
||||||
|
sb.Remove(sb.Length - 2, 2).Append(")");
|
||||||
|
}
|
||||||
|
sb.Append("\r\n) Engine=InnoDB CHARACTER SET utf8;\r\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//对比字段,只可以修改类型、增加字段、有限的修改字段名;保证安全不删除字段
|
||||||
|
var addcols = new Dictionary<string, ColumnInfo>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
foreach (var tbcol in tb.Columns) addcols.Add(tbcol.Value.Attribute.Name, tbcol.Value);
|
||||||
|
var surplus = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
|
||||||
|
var dbcols = new List<DbColumnInfo>();
|
||||||
|
var sql = @"select
|
||||||
|
a.column_name,
|
||||||
|
a.column_type,
|
||||||
|
case when a.is_nullable = 'YES' then 1 else 0 end 'is_nullable',
|
||||||
|
case when locate('auto_increment', a.extra) > 0 then 1 else 0 end 'is_identity'
|
||||||
|
from information_schema.columns a
|
||||||
|
where a.table_schema in ({0}) and a.table_name in ({1})".FormatMySql(isRenameTable ? tboldname : tbname);
|
||||||
|
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
foreach (var row in ds) {
|
||||||
|
string column = string.Concat(row[0]);
|
||||||
|
string sqlType = string.Concat(row[1]);
|
||||||
|
bool is_nullable = string.Concat(row[2]) == "1";
|
||||||
|
bool is_identity = string.Concat(row[3]) == "1";
|
||||||
|
bool is_unsigned = sqlType.EndsWith(" unsigned");
|
||||||
|
|
||||||
|
if (addcols.TryGetValue(column, out var trycol)) {
|
||||||
|
if ((trycol.Attribute.DbType.IndexOf(" unsigned", StringComparison.CurrentCultureIgnoreCase) != -1) != is_unsigned ||
|
||||||
|
Regex.Replace(trycol.Attribute.DbType, @"\([^\)]+\)", m => Regex.Replace(m.Groups[0].Value, @"\s", "")).StartsWith(sqlType, StringComparison.CurrentCultureIgnoreCase) == false ||
|
||||||
|
(trycol.Attribute.DbType.IndexOf("NOT NULL", StringComparison.CurrentCultureIgnoreCase) == -1) != is_nullable ||
|
||||||
|
trycol.Attribute.IsIdentity != is_identity) {
|
||||||
|
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" MODIFY ").Append(_commonUtils.QuoteSqlName(column)).Append(" ").Append(trycol.Attribute.DbType.ToUpper());
|
||||||
|
if (trycol.Attribute.IsIdentity && trycol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" AUTO_INCREMENT");
|
||||||
|
sb.Append(";\r\n");
|
||||||
|
}
|
||||||
|
addcols.Remove(column);
|
||||||
|
} else
|
||||||
|
surplus.Add(column, true); //记录剩余字段
|
||||||
|
}
|
||||||
|
foreach (var addcol in addcols.Values) {
|
||||||
|
if (string.IsNullOrEmpty(addcol.Attribute.OldName) == false && surplus.ContainsKey(addcol.Attribute.OldName)) { //修改列名
|
||||||
|
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" CHANGE COLUMN ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.OldName)).Append(" ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(" ").Append(addcol.Attribute.DbType.ToUpper());
|
||||||
|
if (addcol.Attribute.IsIdentity && addcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" AUTO_INCREMENT");
|
||||||
|
sb.Append(";\r\n");
|
||||||
|
|
||||||
|
} else { //添加列
|
||||||
|
sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(" ").Append(addcol.Attribute.DbType.ToUpper());
|
||||||
|
if (addcol.Attribute.IsIdentity && addcol.Attribute.DbType.IndexOf("AUTO_INCREMENT", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" AUTO_INCREMENT");
|
||||||
|
sb.Append(";\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.Length == 0 ? null : sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SyncStructure<TEntity>() => this.SyncStructure(typeof(TEntity));
|
||||||
|
public bool SyncStructure(params Type[] entityTypes) {
|
||||||
|
var ddl = this.GetComparisonDDLStatements(entityTypes);
|
||||||
|
if (string.IsNullOrEmpty(ddl)) return true;
|
||||||
|
try {
|
||||||
|
return _orm.Ado.ExecuteNonQuery(CommandType.Text, ddl) > 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
367
FreeSql/MySql/MySqlDbFirst.cs
Normal file
367
FreeSql/MySql/MySqlDbFirst.cs
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
using FreeSql.DatabaseModel;
|
||||||
|
using FreeSql.Internal;
|
||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql {
|
||||||
|
class MySqlDbFirst : IDbFirst {
|
||||||
|
IFreeSql _orm;
|
||||||
|
protected CommonUtils _commonUtils;
|
||||||
|
protected CommonExpression _commonExpression;
|
||||||
|
public MySqlDbFirst(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression) {
|
||||||
|
_orm = orm;
|
||||||
|
_commonUtils = commonUtils;
|
||||||
|
_commonExpression = commonExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetDbType(DbColumnInfo column) => (int)GetMySqlDbType(column);
|
||||||
|
MySqlDbType GetMySqlDbType(DbColumnInfo column) {
|
||||||
|
var is_unsigned = column.DbTypeTextFull.ToLower().EndsWith(" unsigned");
|
||||||
|
switch (column.DbTypeText.ToLower()) {
|
||||||
|
case "bit": return MySqlDbType.Bit;
|
||||||
|
|
||||||
|
case "tinyint": return is_unsigned ? MySqlDbType.UByte : MySqlDbType.Byte;
|
||||||
|
case "smallint": return is_unsigned ? MySqlDbType.UInt16 : MySqlDbType.Int16;
|
||||||
|
case "mediumint": return is_unsigned ? MySqlDbType.UInt24 : MySqlDbType.Int24;
|
||||||
|
case "int": return is_unsigned ? MySqlDbType.UInt32 : MySqlDbType.Int32;
|
||||||
|
case "bigint": return is_unsigned ? MySqlDbType.UInt64 : MySqlDbType.Int64;
|
||||||
|
|
||||||
|
case "real":
|
||||||
|
case "double": return MySqlDbType.Double;
|
||||||
|
case "float": return MySqlDbType.Float;
|
||||||
|
case "numeric":
|
||||||
|
case "decimal": return MySqlDbType.Decimal;
|
||||||
|
|
||||||
|
case "year": return MySqlDbType.Year;
|
||||||
|
case "time": return MySqlDbType.Time;
|
||||||
|
case "date": return MySqlDbType.Date;
|
||||||
|
case "timestamp": return MySqlDbType.Timestamp;
|
||||||
|
case "datetime": return MySqlDbType.DateTime;
|
||||||
|
|
||||||
|
case "tinyblob": return MySqlDbType.TinyBlob;
|
||||||
|
case "blob": return MySqlDbType.Blob;
|
||||||
|
case "mediumblob": return MySqlDbType.MediumBlob;
|
||||||
|
case "longblob": return MySqlDbType.LongBlob;
|
||||||
|
|
||||||
|
case "binary": return MySqlDbType.Binary;
|
||||||
|
case "varbinary": return MySqlDbType.VarBinary;
|
||||||
|
|
||||||
|
case "tinytext": return MySqlDbType.TinyText;
|
||||||
|
case "text": return MySqlDbType.Text;
|
||||||
|
case "mediumtext": return MySqlDbType.MediumText;
|
||||||
|
case "longtext": return MySqlDbType.LongText;
|
||||||
|
|
||||||
|
case "char": return column.MaxLength == 36 ? MySqlDbType.Guid : MySqlDbType.String;
|
||||||
|
case "varchar": return MySqlDbType.VarChar;
|
||||||
|
|
||||||
|
case "set": return MySqlDbType.Set;
|
||||||
|
case "enum": return MySqlDbType.Enum;
|
||||||
|
|
||||||
|
case "point": return MySqlDbType.Geometry;
|
||||||
|
case "linestring": return MySqlDbType.Geometry;
|
||||||
|
case "polygon": return MySqlDbType.Geometry;
|
||||||
|
case "geometry": return MySqlDbType.Geometry;
|
||||||
|
case "multipoint": return MySqlDbType.Geometry;
|
||||||
|
case "multilinestring": return MySqlDbType.Geometry;
|
||||||
|
case "multipolygon": return MySqlDbType.Geometry;
|
||||||
|
case "geometrycollection": return MySqlDbType.Geometry;
|
||||||
|
default: return MySqlDbType.String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)> _dicDbToCs = new Dictionary<int, (string csConvert, string csParse, string csStringify, string csType, Type csTypeInfo, Type csNullableTypeInfo, string csTypeValue, string dataReaderMethod)>() {
|
||||||
|
{ (int)MySqlDbType.Bit, ("(bool?)", "{0} == \"1\"", "{0} == true ? \"1\" : \"0\"", "bool?", typeof(bool), typeof(bool?), "{0}.Value", "GetBoolean") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.Byte, ("(sbyte?)", "sbyte.Parse({0})", "{0}.ToString()", "sbyte?", typeof(sbyte), typeof(sbyte?), "{0}.Value", "GetByte") },
|
||||||
|
{ (int)MySqlDbType.Int16, ("(short?)", "short.Parse({0})", "{0}.ToString()", "short?", typeof(short), typeof(short?), "{0}.Value", "GetInt16") },
|
||||||
|
{ (int)MySqlDbType.Int24, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
|
||||||
|
{ (int)MySqlDbType.Int32, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
|
||||||
|
{ (int)MySqlDbType.Int64, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.UByte, ("(byte?)", "byte.Parse({0})", "{0}.ToString()", "byte?", typeof(byte), typeof(byte?), "{0}.Value", "GetByte") },
|
||||||
|
{ (int)MySqlDbType.UInt16, ("(ushort?)", "ushort.Parse({0})", "{0}.ToString()", "ushort?", typeof(ushort), typeof(ushort?), "{0}.Value", "GetInt16") },
|
||||||
|
{ (int)MySqlDbType.UInt24, ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") },
|
||||||
|
{ (int)MySqlDbType.UInt32, ("(uint?)", "uint.Parse({0})", "{0}.ToString()", "uint?", typeof(uint), typeof(uint?), "{0}.Value", "GetInt32") },
|
||||||
|
{ (int)MySqlDbType.UInt64, ("(ulong?)", "ulong.Parse({0})", "{0}.ToString()", "ulong?", typeof(ulong), typeof(ulong?), "{0}.Value", "GetInt64") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.Double, ("(double?)", "double.Parse({0})", "{0}.ToString()", "double?", typeof(double), typeof(double?), "{0}.Value", "GetDouble") },
|
||||||
|
{ (int)MySqlDbType.Float, ("(float?)", "float.Parse({0})", "{0}.ToString()", "float?", typeof(float), typeof(float?), "{0}.Value", "GetFloat") },
|
||||||
|
{ (int)MySqlDbType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.Year, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") },
|
||||||
|
{ (int)MySqlDbType.Time, ("(TimeSpan?)", "TimeSpan.Parse(double.Parse({0}))", "{0}.Ticks.ToString()", "TimeSpan?", typeof(TimeSpan), typeof(TimeSpan?), "{0}.Value", "GetValue") },
|
||||||
|
{ (int)MySqlDbType.Date, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
|
||||||
|
{ (int)MySqlDbType.Timestamp, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
|
||||||
|
{ (int)MySqlDbType.DateTime, ("(DateTime?)", "new DateTime(long.Parse({0}))", "{0}.Ticks.ToString()", "DateTime?", typeof(DateTime), typeof(DateTime?), "{0}.Value", "GetDateTime") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.TinyBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
|
||||||
|
{ (int)MySqlDbType.Blob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
|
||||||
|
{ (int)MySqlDbType.MediumBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
|
||||||
|
{ (int)MySqlDbType.LongBlob, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.Binary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
|
||||||
|
{ (int)MySqlDbType.VarBinary, ("(byte[])", "Convert.FromBase64String({0})", "Convert.ToBase64String({0})", "byte[]", typeof(byte[]), typeof(byte[]), "{0}", "GetValue") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.TinyText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
{ (int)MySqlDbType.Text, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
{ (int)MySqlDbType.MediumText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
{ (int)MySqlDbType.LongText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.Guid, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}", "GetString") },
|
||||||
|
{ (int)MySqlDbType.String, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
{ (int)MySqlDbType.VarString, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
{ (int)MySqlDbType.VarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.Set, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Set", typeof(bool), typeof(Enum), "{0}", "GetInt64") },
|
||||||
|
{ (int)MySqlDbType.Enum, ("(long?)", "long.Parse({0})", "{0}.ToInt64().ToString()", "Enum", typeof(bool), typeof(Enum), "{0}", "GetInt64") },
|
||||||
|
|
||||||
|
{ (int)MySqlDbType.Geometry, ("(MygisGeometry)", "MygisGeometry.Parse({0}.Replace(StringifySplit, \"|\"))", "{0}.AsText().Replace(\"|\", StringifySplit)", "MygisGeometry", typeof(MygisGeometry), typeof(MygisGeometry), "{0}", "GetString") },
|
||||||
|
};
|
||||||
|
|
||||||
|
public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null;
|
||||||
|
public string GetCsParse(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csParse : null;
|
||||||
|
public string GetCsStringify(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csStringify : null;
|
||||||
|
public string GetCsType(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csType : trydc.csType.Replace("?", "")) : null;
|
||||||
|
public Type GetCsTypeInfo(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeInfo : null;
|
||||||
|
public string GetCsTypeValue(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.csTypeValue : null;
|
||||||
|
public string GetDataReaderMethod(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? trydc.dataReaderMethod : null;
|
||||||
|
|
||||||
|
public List<string> GetDatabases() {
|
||||||
|
var sql = @"select schema_name from information_schema.schemata where schema_name not in ('information_schema', 'mysql', 'performance_schema')";
|
||||||
|
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
return ds.Select(a => a.FirstOrDefault()?.ToString()).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DbTableInfo> GetTablesByDatabase(params string[] database) {
|
||||||
|
var loc1 = new List<DbTableInfo>();
|
||||||
|
var loc2 = new Dictionary<string, DbTableInfo>();
|
||||||
|
var loc3 = new Dictionary<string, Dictionary<string, DbColumnInfo>>();
|
||||||
|
|
||||||
|
if (database == null || database.Any() == false) return loc1;
|
||||||
|
var databaseIn = string.Join(",", database.Select(a => "{0}".FormatMySql(a)));
|
||||||
|
var sql = string.Format(@"select
|
||||||
|
concat(a.table_schema, '.', a.table_name) 'id',
|
||||||
|
a.table_schema 'schema',
|
||||||
|
a.table_name 'table',
|
||||||
|
a.table_type 'type'
|
||||||
|
from information_schema.tables a
|
||||||
|
where a.table_schema in ({0})", databaseIn);
|
||||||
|
var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
if (ds == null) return loc1;
|
||||||
|
|
||||||
|
var loc6 = new List<string>();
|
||||||
|
var loc66 = new List<string>();
|
||||||
|
foreach (var row in ds) {
|
||||||
|
var table_id = string.Concat(row[0]);
|
||||||
|
var schema = string.Concat(row[1]);
|
||||||
|
var table = string.Concat(row[2]);
|
||||||
|
var type = string.Concat(row[3]) == "VIEW" ? DbTableType.VIEW : DbTableType.TABLE;
|
||||||
|
if (database.Length == 1) {
|
||||||
|
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
|
||||||
|
schema = "";
|
||||||
|
}
|
||||||
|
loc2.Add(table_id, new DbTableInfo { Id = table_id, Schema = schema, Name = table, Type = type });
|
||||||
|
loc3.Add(table_id, new Dictionary<string, DbColumnInfo>());
|
||||||
|
switch (type) {
|
||||||
|
case DbTableType.TABLE:
|
||||||
|
case DbTableType.VIEW:
|
||||||
|
loc6.Add(table.Replace("'", "''"));
|
||||||
|
break;
|
||||||
|
case DbTableType.StoreProcedure:
|
||||||
|
loc66.Add(table.Replace("'", "''"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (loc6.Count == 0) return loc1;
|
||||||
|
var loc8 = "'" + string.Join("','", loc6.ToArray()) + "'";
|
||||||
|
var loc88 = "'" + string.Join("','", loc66.ToArray()) + "'";
|
||||||
|
|
||||||
|
sql = string.Format(@"select
|
||||||
|
concat(a.table_schema, '.', a.table_name),
|
||||||
|
a.column_name,
|
||||||
|
a.data_type,
|
||||||
|
ifnull(a.character_maximum_length, 0) 'len',
|
||||||
|
a.column_type,
|
||||||
|
case when a.is_nullable = 'YES' then 1 else 0 end 'is_nullable',
|
||||||
|
case when locate('auto_increment', a.extra) > 0 then 1 else 0 end 'is_identity',
|
||||||
|
a.column_comment 'comment'
|
||||||
|
from information_schema.columns a
|
||||||
|
where a.table_schema in ({1}) and a.table_name in ({0})
|
||||||
|
", loc8, databaseIn);
|
||||||
|
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
if (ds == null) return loc1;
|
||||||
|
|
||||||
|
foreach (var row in ds) {
|
||||||
|
string table_id = string.Concat(row[0]);
|
||||||
|
string column = string.Concat(row[1]);
|
||||||
|
string type = string.Concat(row[2]);
|
||||||
|
//long max_length = long.Parse(string.Concat(row[3]));
|
||||||
|
string sqlType = string.Concat(row[4]);
|
||||||
|
var m_len = Regex.Match(sqlType, @"\w+\((\d+)");
|
||||||
|
int max_length = m_len.Success ? int.Parse(m_len.Groups[1].Value) : -1;
|
||||||
|
bool is_nullable = string.Concat(row[5]) == "1";
|
||||||
|
bool is_identity = string.Concat(row[6]) == "1";
|
||||||
|
string comment = string.Concat(row[7]);
|
||||||
|
if (max_length == 0) max_length = -1;
|
||||||
|
if (database.Length == 1) {
|
||||||
|
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
|
||||||
|
}
|
||||||
|
loc3[table_id].Add(column, new DbColumnInfo {
|
||||||
|
Name = column,
|
||||||
|
MaxLength = max_length,
|
||||||
|
IsIdentity = is_identity,
|
||||||
|
IsNullable = is_nullable,
|
||||||
|
IsPrimary = false,
|
||||||
|
DbTypeText = type,
|
||||||
|
DbTypeTextFull = sqlType,
|
||||||
|
Table = loc2[table_id],
|
||||||
|
Coment = comment
|
||||||
|
});
|
||||||
|
loc3[table_id][column].DbType = this.GetDbType(loc3[table_id][column]);
|
||||||
|
loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sql = string.Format(@"select
|
||||||
|
concat(a.constraint_schema, '.', a.table_name) 'table_id',
|
||||||
|
a.column_name,
|
||||||
|
concat(a.constraint_schema, '/', a.table_name, '/', a.constraint_name) 'index_id',
|
||||||
|
1 'IsUnique',
|
||||||
|
case when constraint_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey',
|
||||||
|
0 'IsClustered',
|
||||||
|
0 'IsDesc'
|
||||||
|
from information_schema.key_column_usage a
|
||||||
|
where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position_in_unique_constraint)
|
||||||
|
", loc8, databaseIn);
|
||||||
|
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
if (ds == null) return loc1;
|
||||||
|
|
||||||
|
var indexColumns = new Dictionary<string, Dictionary<string, List<DbColumnInfo>>>();
|
||||||
|
var uniqueColumns = new Dictionary<string, Dictionary<string, List<DbColumnInfo>>>();
|
||||||
|
foreach (var row in ds) {
|
||||||
|
string table_id = string.Concat(row[0]);
|
||||||
|
string column = string.Concat(row[1]);
|
||||||
|
string index_id = string.Concat(row[2]);
|
||||||
|
bool is_unique = string.Concat(row[3]) == "1";
|
||||||
|
bool is_primary_key = string.Concat(row[4]) == "1";
|
||||||
|
bool is_clustered = string.Concat(row[5]) == "1";
|
||||||
|
int is_desc = int.Parse(string.Concat(row[6]));
|
||||||
|
if (database.Length == 1) {
|
||||||
|
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
|
||||||
|
}
|
||||||
|
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
|
||||||
|
var loc9 = loc3[table_id][column];
|
||||||
|
if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key;
|
||||||
|
|
||||||
|
Dictionary<string, List<DbColumnInfo>> loc10 = null;
|
||||||
|
List<DbColumnInfo> loc11 = null;
|
||||||
|
if (!indexColumns.TryGetValue(table_id, out loc10))
|
||||||
|
indexColumns.Add(table_id, loc10 = new Dictionary<string, List<DbColumnInfo>>());
|
||||||
|
if (!loc10.TryGetValue(index_id, out loc11))
|
||||||
|
loc10.Add(index_id, loc11 = new List<DbColumnInfo>());
|
||||||
|
loc11.Add(loc9);
|
||||||
|
if (is_unique) {
|
||||||
|
if (!uniqueColumns.TryGetValue(table_id, out loc10))
|
||||||
|
uniqueColumns.Add(table_id, loc10 = new Dictionary<string, List<DbColumnInfo>>());
|
||||||
|
if (!loc10.TryGetValue(index_id, out loc11))
|
||||||
|
loc10.Add(index_id, loc11 = new List<DbColumnInfo>());
|
||||||
|
loc11.Add(loc9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (string table_id in indexColumns.Keys) {
|
||||||
|
foreach (var columns in indexColumns[table_id].Values)
|
||||||
|
loc2[table_id].Indexes.Add(columns);
|
||||||
|
}
|
||||||
|
foreach (string table_id in uniqueColumns.Keys) {
|
||||||
|
foreach (var columns in uniqueColumns[table_id].Values) {
|
||||||
|
columns.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
|
||||||
|
loc2[table_id].Uniques.Add(columns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sql = string.Format(@"select
|
||||||
|
concat(a.constraint_schema, '.', a.table_name) 'table_id',
|
||||||
|
a.column_name,
|
||||||
|
concat(a.constraint_schema, '/', a.constraint_name) 'FKId',
|
||||||
|
concat(a.referenced_table_schema, '.', a.referenced_table_name) 'ref_table_id',
|
||||||
|
1 'IsForeignKey',
|
||||||
|
a.referenced_column_name 'ref_column'
|
||||||
|
from information_schema.key_column_usage a
|
||||||
|
where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(position_in_unique_constraint)
|
||||||
|
", loc8, databaseIn);
|
||||||
|
ds = _orm.Ado.ExecuteArray(CommandType.Text, sql);
|
||||||
|
if (ds == null) return loc1;
|
||||||
|
|
||||||
|
var fkColumns = new Dictionary<string, Dictionary<string, DbForeignInfo>>();
|
||||||
|
foreach (var row in ds) {
|
||||||
|
string table_id = string.Concat(row[0]);
|
||||||
|
string column = string.Concat(row[1]);
|
||||||
|
string fk_id = string.Concat(row[2]);
|
||||||
|
string ref_table_id = string.Concat(row[3]);
|
||||||
|
bool is_foreign_key = string.Concat(row[4]) == "1";
|
||||||
|
string referenced_column = string.Concat(row[5]);
|
||||||
|
if (database.Length == 1) {
|
||||||
|
table_id = table_id.Substring(table_id.IndexOf('.') + 1);
|
||||||
|
ref_table_id = ref_table_id.Substring(ref_table_id.IndexOf('.') + 1);
|
||||||
|
}
|
||||||
|
if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue;
|
||||||
|
var loc9 = loc3[table_id][column];
|
||||||
|
if (loc2.ContainsKey(ref_table_id) == false) continue;
|
||||||
|
var loc10 = loc2[ref_table_id];
|
||||||
|
var loc11 = loc3[ref_table_id][referenced_column];
|
||||||
|
|
||||||
|
Dictionary<string, DbForeignInfo> loc12 = null;
|
||||||
|
DbForeignInfo loc13 = null;
|
||||||
|
if (!fkColumns.TryGetValue(table_id, out loc12))
|
||||||
|
fkColumns.Add(table_id, loc12 = new Dictionary<string, DbForeignInfo>());
|
||||||
|
if (!loc12.TryGetValue(fk_id, out loc13))
|
||||||
|
loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[table_id], ReferencedTable = loc10 });
|
||||||
|
loc13.Columns.Add(loc9);
|
||||||
|
loc13.ReferencedColumns.Add(loc11);
|
||||||
|
}
|
||||||
|
foreach (var table_id in fkColumns.Keys)
|
||||||
|
foreach (var fk in fkColumns[table_id].Values)
|
||||||
|
loc2[table_id].Foreigns.Add(fk);
|
||||||
|
|
||||||
|
foreach (var table_id in loc3.Keys) {
|
||||||
|
foreach (var loc5 in loc3[table_id].Values) {
|
||||||
|
loc2[table_id].Columns.Add(loc5);
|
||||||
|
if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5);
|
||||||
|
if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var loc4 in loc2.Values) {
|
||||||
|
if (loc4.Primarys.Count == 0 && loc4.Uniques.Count > 0) {
|
||||||
|
foreach (var loc5 in loc4.Uniques[0]) {
|
||||||
|
loc5.IsPrimary = true;
|
||||||
|
loc4.Primarys.Add(loc5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
|
||||||
|
loc4.Columns.Sort((c1, c2) => {
|
||||||
|
int compare = c2.IsPrimary.CompareTo(c1.IsPrimary);
|
||||||
|
if (compare == 0) {
|
||||||
|
bool b1 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c1.Name) != null) != null;
|
||||||
|
bool b2 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c2.Name) != null) != null;
|
||||||
|
compare = b2.CompareTo(b1);
|
||||||
|
}
|
||||||
|
if (compare == 0) compare = c1.Name.CompareTo(c2.Name);
|
||||||
|
return compare;
|
||||||
|
});
|
||||||
|
loc1.Add(loc4);
|
||||||
|
}
|
||||||
|
loc1.Sort((t1, t2) => {
|
||||||
|
var ret = t1.Schema.CompareTo(t2.Schema);
|
||||||
|
if (ret == 0) ret = t1.Name.CompareTo(t2.Name);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
loc2.Clear();
|
||||||
|
loc3.Clear();
|
||||||
|
return loc1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
159
FreeSql/MySql/MySqlExpression.cs
Normal file
159
FreeSql/MySql/MySqlExpression.cs
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql {
|
||||||
|
class MySqlExpression : CommonExpression {
|
||||||
|
|
||||||
|
public MySqlExpression(CommonUtils common) : base(common) { }
|
||||||
|
|
||||||
|
internal override string ExpressionLambdaToSqlCall(MethodCallExpression exp, List<SelectTableInfo> _tables, List<SelectColumnInfo> _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) {
|
||||||
|
if (exp.Object.Type.FullName == "System.String") {
|
||||||
|
var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
switch (exp.Method.Name) {
|
||||||
|
case "StartsWith":
|
||||||
|
case "EndsWith":
|
||||||
|
case "Contains":
|
||||||
|
var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
if (args0Value == "NULL") return $"({left}) IS NULL";
|
||||||
|
if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}";
|
||||||
|
if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}";
|
||||||
|
if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}";
|
||||||
|
return $"({left}) like concat('%', {args0Value}, '%')";
|
||||||
|
case "ToLower": return $"lower({left})";
|
||||||
|
case "ToUpper": return $"upper({left})";
|
||||||
|
case "Substring": return $"substr({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} + 1, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Length": return $"char_length({left})";
|
||||||
|
case "IndexOf":
|
||||||
|
var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName);
|
||||||
|
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"(locate({left}, {indexOfFindStr}, ParseLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName) + 1) - 1)";
|
||||||
|
return $"(locate({left}, {indexOfFindStr}) - 1)";
|
||||||
|
case "PadLeft": return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "PadRight": return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Trim":
|
||||||
|
case "TrimStart":
|
||||||
|
case "TrimEnd":
|
||||||
|
if (exp.Arguments.Count == 0) {
|
||||||
|
if (exp.Method.Name == "Trim") return $"trim({left})";
|
||||||
|
if (exp.Method.Name == "TrimStart") return $"ltrim({left})";
|
||||||
|
if (exp.Method.Name == "TrimStart") return $"rtrim({left})";
|
||||||
|
}
|
||||||
|
foreach (var argsTrim01 in exp.Arguments) {
|
||||||
|
if (exp.Method.Name == "Trim") left = $"trim({ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName)} from {left})";
|
||||||
|
if (exp.Method.Name == "TrimStart") left = $"trim(leading {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName)} from {left})";
|
||||||
|
if (exp.Method.Name == "TrimStart") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName)} from {left})";
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "CompareTo": return $"strcmp({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp.Object.Type.FullName == "System.Math") {
|
||||||
|
switch (exp.Method.Name) {
|
||||||
|
case "Abs": return $"abs({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Sign": return $"sign({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Floor": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Round":
|
||||||
|
if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Exp": return $"exp({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Log": return $"log({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Log10": return $"log10({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Pow": return $"pow({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "PI": return $"pi()";
|
||||||
|
case "Cos": return $"cos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Sin": return $"sin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Tan": return $"tan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Acos": return $"acos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Asin": return $"asin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Atan": return $"atan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Atan2": return $"atan2({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})";
|
||||||
|
case "Truncate": return $"truncate({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, 0)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//dayofweek = DayOfWeek
|
||||||
|
//dayofmonth = Day
|
||||||
|
//dayofyear = DayOfYear
|
||||||
|
//month = Month
|
||||||
|
//year = Year
|
||||||
|
//hour = Hour
|
||||||
|
//minute = Minute
|
||||||
|
//second = Second
|
||||||
|
/*
|
||||||
|
* date_add(date,interval expr type)
|
||||||
|
date_sub(date,interval expr type)
|
||||||
|
adddate(date,interval expr type)
|
||||||
|
subdate(date,interval expr type)
|
||||||
|
对日期时间进行加减法运算
|
||||||
|
(adddate()和subdate()是date_add()和date_sub()的同义词,也
|
||||||
|
可以用运算符+和-而不是函数
|
||||||
|
date是一个datetime或date值,expr对date进行加减法的一个表
|
||||||
|
达式字符串type指明表达式expr应该如何被解释
|
||||||
|
[type值 含义 期望的expr格式]:
|
||||||
|
second 秒 seconds
|
||||||
|
minute 分钟 minutes
|
||||||
|
hour 时间 hours
|
||||||
|
day 天 days
|
||||||
|
month 月 months
|
||||||
|
year 年 years
|
||||||
|
minute_second 分钟和秒 "minutes:seconds"
|
||||||
|
hour_minute 小时和分钟 "hours:minutes"
|
||||||
|
day_hour 天和小时 "days hours"
|
||||||
|
year_month 年和月 "years-months"
|
||||||
|
hour_second 小时, 分钟, "hours:minutes:seconds"
|
||||||
|
day_minute 天, 小时, 分钟 "days hours:minutes"
|
||||||
|
day_second 天, 小时, 分钟, 秒 "days
|
||||||
|
hours:minutes:seconds"
|
||||||
|
expr中允许任何标点做分隔符,如果所有是date值时结果是一个
|
||||||
|
date值,否则结果是一个datetime值)
|
||||||
|
如果type关键词不完整,则mysql从右端取值,day_second因为缺
|
||||||
|
少小时分钟等于minute_second)
|
||||||
|
如果增加month、year_month或year,天数大于结果月份的最大天
|
||||||
|
数则使用最大天数)
|
||||||
|
mysql> select "1997-12-31 23:59:59" + interval 1 second;
|
||||||
|
|
||||||
|
-> 1998-01-01 00:00:00
|
||||||
|
mysql> select interval 1 day + "1997-12-31";
|
||||||
|
-> 1998-01-01
|
||||||
|
mysql> select "1998-01-01" - interval 1 second;
|
||||||
|
-> 1997-12-31 23:59:59
|
||||||
|
mysql> select date_add("1997-12-31 23:59:59",interval 1
|
||||||
|
second);
|
||||||
|
-> 1998-01-01 00:00:00
|
||||||
|
mysql> select date_add("1997-12-31 23:59:59",interval 1
|
||||||
|
day);
|
||||||
|
-> 1998-01-01 23:59:59
|
||||||
|
mysql> select date_add("1997-12-31 23:59:59",interval
|
||||||
|
"1:1" minute_second);
|
||||||
|
-> 1998-01-01 00:01:00
|
||||||
|
mysql> select date_sub("1998-01-01 00:00:00",interval "1
|
||||||
|
1:1:1" day_second);
|
||||||
|
-> 1997-12-30 22:58:59
|
||||||
|
mysql> select date_add("1998-01-01 00:00:00", interval "-1
|
||||||
|
10" day_hour);
|
||||||
|
-> 1997-12-30 14:00:00
|
||||||
|
mysql> select date_sub("1998-01-02", interval 31 day);
|
||||||
|
-> 1997-12-02
|
||||||
|
mysql> select extract(year from "1999-07-02");
|
||||||
|
-> 1999
|
||||||
|
mysql> select extract(year_month from "1999-07-02
|
||||||
|
01:02:03");
|
||||||
|
-> 199907
|
||||||
|
mysql> select extract(day_minute from "1999-07-02
|
||||||
|
01:02:03");
|
||||||
|
-> 20102
|
||||||
|
*/
|
||||||
|
|
||||||
|
//convert
|
||||||
|
var xxx = DateTime.Now.ToString("");
|
||||||
|
|
||||||
|
|
||||||
|
throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
FreeSql/MySql/MySqlProvider.cs
Normal file
50
FreeSql/MySql/MySqlProvider.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.CommonProvider;
|
||||||
|
using FreeSql.MySql.Curd;
|
||||||
|
using Microsoft.Extensions.Caching.Distributed;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql {
|
||||||
|
|
||||||
|
class MySqlProvider : IFreeSql {
|
||||||
|
|
||||||
|
public ISelect<T1> Select<T1>() where T1 : class => new MySqlSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||||
|
public ISelect<T1> Select<T1>(object dywhere) where T1 : class => new MySqlSelect<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||||
|
public IInsert<T1> Insert<T1>() where T1 : class => new MySqlInsert<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||||
|
public IInsert<T1> Insert<T1>(T1 source) where T1 : class => this.Insert<T1>().AppendData(source);
|
||||||
|
public IInsert<T1> Insert<T1>(IEnumerable<T1> source) where T1 : class => this.Insert<T1>().AppendData(source);
|
||||||
|
public IUpdate<T1> Update<T1>() where T1 : class => new MySqlUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||||
|
public IUpdate<T1> Update<T1>(object dywhere) where T1 : class => new MySqlUpdate<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||||
|
public IDelete<T1> Delete<T1>() where T1 : class => new MySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, null);
|
||||||
|
public IDelete<T1> Delete<T1>(object dywhere) where T1 : class => new MySqlDelete<T1>(this, this.InternalCommonUtils, this.InternalCommonExpression, dywhere);
|
||||||
|
|
||||||
|
public IAdo Ado { get; }
|
||||||
|
public ICache Cache { get; }
|
||||||
|
public ICodeFirst CodeFirst { get; }
|
||||||
|
public IDbFirst DbFirst { get; }
|
||||||
|
public MySqlProvider(IDistributedCache cache, IConfiguration cacheStrategy, string masterConnectionString, string[] slaveConnectionString, ILogger log) {
|
||||||
|
CacheStrategy = cacheStrategy;
|
||||||
|
if (log == null) log = new LoggerFactory(new[] { new Microsoft.Extensions.Logging.Debug.DebugLoggerProvider() }).CreateLogger("FreeSql.MySql");
|
||||||
|
|
||||||
|
this.InternalCommonUtils = new MySqlUtils(this);
|
||||||
|
this.InternalCommonExpression = new MySqlExpression(this.InternalCommonUtils);
|
||||||
|
|
||||||
|
this.Cache = new CacheProvider(cache, log);
|
||||||
|
this.Ado = new MySqlAdo(this.InternalCommonUtils, this.Cache, log, masterConnectionString, slaveConnectionString);
|
||||||
|
|
||||||
|
this.DbFirst = new MySqlDbFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||||
|
this.InternalCommonUtils.CodeFirst = this.CodeFirst = new MySqlCodeFirst(this, this.InternalCommonUtils, this.InternalCommonExpression);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal CommonUtils InternalCommonUtils { get; }
|
||||||
|
internal CommonExpression InternalCommonExpression { get; }
|
||||||
|
internal IConfiguration CacheStrategy { get; private set; }
|
||||||
|
|
||||||
|
public void Transaction(Action handler) => Ado.Transaction(handler);
|
||||||
|
|
||||||
|
public void Transaction(Action handler, TimeSpan timeout) => Ado.Transaction(handler, timeout);
|
||||||
|
}
|
||||||
|
}
|
48
FreeSql/MySql/MySqlUtils.cs
Normal file
48
FreeSql/MySql/MySqlUtils.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using MySql.Data.MySqlClient;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
|
||||||
|
namespace FreeSql.MySql {
|
||||||
|
|
||||||
|
class MySqlUtils : CommonUtils {
|
||||||
|
IFreeSql _orm;
|
||||||
|
public MySqlUtils(IFreeSql mysql) {
|
||||||
|
_orm = mysql;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override DbParameter AppendParamter(List<DbParameter> _params, string parameterName, object value) {
|
||||||
|
if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}";
|
||||||
|
MySqlParameter ret = null;
|
||||||
|
if (value == null) ret = new MySqlParameter { ParameterName = $"{parameterName}", Value = DBNull.Value };
|
||||||
|
else {
|
||||||
|
var type = value.GetType();
|
||||||
|
ret = new MySqlParameter {
|
||||||
|
ParameterName = parameterName,
|
||||||
|
Value = value
|
||||||
|
};
|
||||||
|
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
|
||||||
|
if (tp != null) ret.MySqlDbType = (MySqlDbType)tp.Value;
|
||||||
|
}
|
||||||
|
_params?.Add(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override DbParameter[] GetDbParamtersByObject(string sql, object obj) =>
|
||||||
|
Utils.GetDbParamtersByObject<MySqlParameter>(sql, obj, "?", (name, type, value) => {
|
||||||
|
var cp = new MySqlParameter {
|
||||||
|
ParameterName = name,
|
||||||
|
Value = value ?? DBNull.Value
|
||||||
|
};
|
||||||
|
var tp = _orm.CodeFirst.GetDbInfo(type)?.type;
|
||||||
|
if (tp != null) cp.MySqlDbType = (MySqlDbType)tp.Value;
|
||||||
|
return cp;
|
||||||
|
});
|
||||||
|
|
||||||
|
internal override string FormatSql(string sql, params object[] args) => sql?.FormatMySql(args);
|
||||||
|
internal override string QuoteSqlName(string name) => $"`{name.Trim('`').Replace(".", "`.`")}`";
|
||||||
|
internal override string QuoteParamterName(string name) => $"?{name}";
|
||||||
|
internal override string IsNull(string sql, object value) => $"ifnull({sql}, {value})";
|
||||||
|
}
|
||||||
|
}
|
25
FreeSql/PostgreSQL/Curd/PostgreSQLDelete.cs
Normal file
25
FreeSql/PostgreSQL/Curd/PostgreSQLDelete.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.PostgreSQL.Curd {
|
||||||
|
|
||||||
|
class PostgreSQLDelete<T1> : Internal.CommonProvider.DeleteProvider<T1> where T1 : class {
|
||||||
|
public PostgreSQLDelete(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||||
|
: base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<T1> ExecuteDeleted() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(this.ToSql()).Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
return _orm.Ado.Query<T1>(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs
Normal file
30
FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.PostgreSQL.Curd {
|
||||||
|
|
||||||
|
class PostgreSQLInsert<T1> : Internal.CommonProvider.InsertProvider<T1> where T1 : class {
|
||||||
|
public PostgreSQLInsert(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression)
|
||||||
|
: base(orm, commonUtils, commonExpression) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long ExecuteIdentity() =>
|
||||||
|
int.TryParse(string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, string.Concat(this.ToSql(), " RETURNING ", _commonUtils.QuoteSqlName(_table.Columns.Where(a => a.Value.Attribute.IsIdentity).FirstOrDefault().Value.Attribute.Name)), _params)), out var trylng) ? trylng : 0;
|
||||||
|
|
||||||
|
public override List<T1> ExecuteInserted() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(this.ToSql()).Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
return _orm.Ado.Query<T1>(sb.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
116
FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs
Normal file
116
FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.PostgreSQL.Curd {
|
||||||
|
|
||||||
|
class PostgreSQLSelect<T1> : FreeSql.Internal.CommonProvider.Select1Provider<T1> where T1 : class {
|
||||||
|
|
||||||
|
internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List<SelectTableInfo> _tables) {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(_select).Append(field).Append(" \r\nFROM ");
|
||||||
|
var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray();
|
||||||
|
var tbsfrom = _tables.Where(a => a.Type == SelectTableInfoType.From).ToArray();
|
||||||
|
for (var a = 0; a < tbsfrom.Length; a++) {
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tbsfrom[a].Table.DbName)).Append(" ").Append(tbsfrom[a].Alias);
|
||||||
|
if (tbsjoin.Length > 0) {
|
||||||
|
//如果存在 join 查询,则处理 from t1, t2 改为 from t1 inner join t2 on 1 = 1
|
||||||
|
for (var b = 1; b < tbsfrom.Length; b++)
|
||||||
|
sb.Append(" \r\nLEFT JOIN ").Append(_commonUtils.QuoteSqlName(tbsfrom[b].Table.DbName)).Append(" ").Append(tbsfrom[b].Alias).Append(" ON 1 = 1");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (a < tbsfrom.Length - 1) sb.Append(", ");
|
||||||
|
}
|
||||||
|
foreach (var tb in tbsjoin) {
|
||||||
|
switch (tb.Type) {
|
||||||
|
case SelectTableInfoType.LeftJoin:
|
||||||
|
sb.Append(" \r\nLEFT JOIN ");
|
||||||
|
break;
|
||||||
|
case SelectTableInfoType.InnerJoin:
|
||||||
|
sb.Append(" \r\nINNER JOIN ");
|
||||||
|
break;
|
||||||
|
case SelectTableInfoType.RightJoin:
|
||||||
|
sb.Append(" \r\nRIGHT JOIN ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(tb.Table.DbName)).Append(" ").Append(tb.Alias).Append(" ON ").Append(tb.On);
|
||||||
|
}
|
||||||
|
if (_join.Length > 0) sb.Append(_join);
|
||||||
|
|
||||||
|
var sbqf = new StringBuilder();
|
||||||
|
foreach (var tb in _tables) {
|
||||||
|
if (string.IsNullOrEmpty(tb.Table.SelectFilter) == false)
|
||||||
|
sbqf.Append(" AND (").Append(tb.Table.SelectFilter.Replace("a.", $"{tb.Alias}.")).Append(")");
|
||||||
|
}
|
||||||
|
if (_where.Length > 0) {
|
||||||
|
sb.Append(" \r\nWHERE ").Append(_where.ToString().Substring(5));
|
||||||
|
if (sbqf.Length > 0) sb.Append(sbqf.ToString());
|
||||||
|
} else {
|
||||||
|
if (sbqf.Length > 0) sb.Append(" \r\nWHERE ").Append(sbqf.Remove(0, 5));
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(_groupby) == false) {
|
||||||
|
sb.Append(_groupby);
|
||||||
|
if (string.IsNullOrEmpty(_having) == false)
|
||||||
|
sb.Append(" \r\nHAVING ").Append(_having.Substring(5));
|
||||||
|
}
|
||||||
|
sb.Append(_orderby);
|
||||||
|
if (_limit > 0)
|
||||||
|
sb.Append(" \r\nlimit ").Append(_limit);
|
||||||
|
if (_skip > 0)
|
||||||
|
sb.Append(" \r\noffset ").Append(_skip);
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override ISelect<T1, T2, T3> From<T2, T3>(Expression<Func<ISelectFromExpression<T1>, T2, T3, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect<T1, T2, T3>(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4> From<T2, T3, T4>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect<T1, T2, T3, T4>(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5> From<T2, T3, T4, T5>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5>(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6> From<T2, T3, T4, T5, T6>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6>(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7> From<T2, T3, T4, T5, T6, T7>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7>(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8> From<T2, T3, T4, T5, T6, T7, T8>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8>(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> From<T2, T3, T4, T5, T6, T7, T8, T9>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9>(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override ISelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> From<T2, T3, T4, T5, T6, T7, T8, T9, T10>(Expression<Func<ISelectFromExpression<T1>, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression<T1>>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect<T1>.CopyData(this, ret); return ret; }
|
||||||
|
public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2> : FreeSql.Internal.CommonProvider.Select2Provider<T1, T2> where T1 : class where T2 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3> : FreeSql.Internal.CommonProvider.Select3Provider<T1, T2, T3> where T1 : class where T2 : class where T3 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4> : FreeSql.Internal.CommonProvider.Select4Provider<T1, T2, T3, T4> where T1 : class where T2 : class where T3 : class where T4 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5> : FreeSql.Internal.CommonProvider.Select5Provider<T1, T2, T3, T4, T5> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6> : FreeSql.Internal.CommonProvider.Select6Provider<T1, T2, T3, T4, T5, T6> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7> : FreeSql.Internal.CommonProvider.Select7Provider<T1, T2, T3, T4, T5, T6, T7> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8> : FreeSql.Internal.CommonProvider.Select8Provider<T1, T2, T3, T4, T5, T6, T7, T8> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9> : FreeSql.Internal.CommonProvider.Select9Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
class PostgreSQLSelect<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : FreeSql.Internal.CommonProvider.Select10Provider<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class {
|
||||||
|
public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { }
|
||||||
|
public override string ToSql(string field = null) => PostgreSQLSelect<T1>.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables);
|
||||||
|
}
|
||||||
|
}
|
49
FreeSql/PostgreSQL/Curd/PostgreSQLUpdate.cs
Normal file
49
FreeSql/PostgreSQL/Curd/PostgreSQLUpdate.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using FreeSql.Internal;
|
||||||
|
using FreeSql.Internal.Model;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FreeSql.PostgreSQL.Curd {
|
||||||
|
|
||||||
|
class PostgreSQLUpdate<T1> : Internal.CommonProvider.UpdateProvider<T1> where T1 : class {
|
||||||
|
|
||||||
|
public PostgreSQLUpdate(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere)
|
||||||
|
: base(orm, commonUtils, commonExpression, dywhere) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<T1> ExecuteUpdated() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append(this.ToSql()).Append(" RETURNING ");
|
||||||
|
|
||||||
|
var colidx = 0;
|
||||||
|
foreach (var col in _table.Columns.Values) {
|
||||||
|
if (colidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName));
|
||||||
|
++colidx;
|
||||||
|
}
|
||||||
|
return _orm.Ado.Query<T1>(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) {
|
||||||
|
if (_table.Primarys.Length > 1) caseWhen.Append("(");
|
||||||
|
var pkidx = 0;
|
||||||
|
foreach (var pk in _table.Primarys) {
|
||||||
|
if (pkidx > 0) caseWhen.Append(", ");
|
||||||
|
caseWhen.Append(_commonUtils.QuoteSqlName(pk.Attribute.Name)).Append("::varchar");
|
||||||
|
++pkidx;
|
||||||
|
}
|
||||||
|
if (_table.Primarys.Length > 1) caseWhen.Append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d) {
|
||||||
|
if (_table.Primarys.Length > 1) sb.Append("(");
|
||||||
|
var pkidx = 0;
|
||||||
|
foreach (var pk in _table.Primarys) {
|
||||||
|
if (pkidx > 0) sb.Append(", ");
|
||||||
|
sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(pk.CsName, out var tryp2) ? tryp2.GetValue(d) : null)).Append("::varchar");
|
||||||
|
++pkidx;
|
||||||
|
}
|
||||||
|
if (_table.Primarys.Length > 1) sb.Append(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user