Merge branch 'master' of https://github.com/dotnetcore/FreeSql
7
.editorconfig
Normal file
@ -0,0 +1,7 @@
|
||||
[*.cs]
|
||||
|
||||
# Default severity for analyzer diagnostics with category 'Style'
|
||||
dotnet_analyzer_diagnostic.category-Style.severity = none
|
||||
|
||||
# CS0649: 从未对字段“TransactionalAttribute._uowManager”赋值,字段将一直保持其默认值 null
|
||||
dotnet_diagnostic.CS0649.severity = none
|
17
.github/workflows/gitee-mirror.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: Publish
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Sync to Gitee 💕
|
||||
uses: wearerequired/git-mirror-action@master
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
with:
|
||||
source-repo: "git@github.com:dotnetcore/freesql.git"
|
||||
destination-repo: "git@gitee.com:FreeSql/FreeSql-ORM.git"
|
4
.gitignore
vendored
@ -1,6 +1,9 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
FreeSql.xml
|
||||
FreeSql.DbContext.xml
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
@ -186,7 +189,6 @@ ClientBin/
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
@ -1,97 +0,0 @@
|
||||
# FreeSql 简介
|
||||
|
||||
FreeSql 是轻量化、可扩展和跨平台版的 .NETStandard 数据访问技术实现。
|
||||
|
||||
FreeSql 可用作对象关系映射程序 (O/RM),以便于开发人员能够使用 .NETStandard 对象来处理数据库,不必经常编写大部分数据访问代码。
|
||||
|
||||
FreeSql 支持 MySql/SqlServer/PostgreSQL 数据库技术实现。
|
||||
|
||||
## 模型
|
||||
|
||||
FreeSql 使用模型执行数据访问,模型由实体类表示数据库表或视图,用于查询和保存数据。 有关详细信息,请参阅创建模型。
|
||||
|
||||
可从现有数据库生成实体模型,提供 IDbFirst 生成实体模型。
|
||||
|
||||
或者手动创建模型,基于模型创建或修改数据库,提供 ICodeFirst 同步结构的 API(甚至可以做到开发阶段自动同步)。
|
||||
|
||||
```csharp
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
|
||||
public class Blog
|
||||
{
|
||||
[Column(IsIdentity = true, IsPrimary = true)]
|
||||
public int BlogId { get; set; }
|
||||
public string Url { get; set; }
|
||||
public int Rating { get; set; }
|
||||
}
|
||||
|
||||
public class Post
|
||||
{
|
||||
public int PostId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Content { get; set; }
|
||||
|
||||
public int BlogId { get; set; }
|
||||
public Blog Blog { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
## 声明
|
||||
|
||||
```csharp
|
||||
var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" +
|
||||
"Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10";
|
||||
|
||||
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseConnectionString(FreeSql.DataType.MySql, connstr)
|
||||
.UseSlave("connectionString1", "connectionString2") //使用从数据库,支持多个
|
||||
|
||||
.UseLogger(null) //使用日志,不指定默认输出控制台 ILogger
|
||||
.UseCache(null) //使用缓存,不指定默认使用内存 IDistributedCache
|
||||
|
||||
.UseAutoSyncStructure(true) //自动同步实体结构到数据库
|
||||
.UseSyncStructureToLower(true) //转小写同步结构
|
||||
.Build();
|
||||
```
|
||||
|
||||
注意: IFreeSql 在项目中应以单例声明,而不是在每次使用的时候创建。
|
||||
|
||||
## 查询
|
||||
|
||||
```csharp
|
||||
var blogs = fsql.Select<Blog>
|
||||
.Where(b => b.Rating > 3)
|
||||
.OrderBy(b => b.Url)
|
||||
.ToList();
|
||||
```
|
||||
|
||||
## 插入
|
||||
|
||||
```csharp
|
||||
var blog = new Blog { Url = "http://sample.com" };
|
||||
blog.BlogId = (int)fsql.Insert<Blog>()
|
||||
.AppendData(blog)
|
||||
.ExecuteIdentity();
|
||||
```
|
||||
|
||||
## 更新
|
||||
|
||||
```csharp
|
||||
fsql.Update<Blog>()
|
||||
.Set(b => b.Url, "http://sample2222.com")
|
||||
.Where(b => b.Url == "http://sample.com")
|
||||
.ExecuteAffrows();
|
||||
```
|
||||
|
||||
## 删除
|
||||
|
||||
```csharp
|
||||
fsql.Delete<Blog>()
|
||||
.Where(b => b.Url == "http://sample.com")
|
||||
.ExecuteAffrows();
|
||||
```
|
||||
|
||||
## 后续步骤
|
||||
|
||||
有关介绍性教程,请参阅 [FreeSql 入门]()。
|
28
Docs/2 入门.md
@ -1,28 +0,0 @@
|
||||
# FreeSql 入门
|
||||
|
||||
## 安装
|
||||
|
||||
FreeSql 是一个 .NET Standard 2.0 库,支持 .NET Framework 4.6.1 或 .NET Core 或更高版本的应用程序。
|
||||
|
||||
```shell
|
||||
dotnet add package FreeSql
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```shell
|
||||
Install-Package FreeSql
|
||||
```
|
||||
|
||||
## 入门教程
|
||||
|
||||
FreeSql 可基于现有数据库创建模型,也可基于模型创建数据库。 提供的教程演示了这两种方法。
|
||||
|
||||
* .NET Core 控制台应用
|
||||
|
||||
- * 新建数据库
|
||||
|
||||
* ASP.NET Core 应用
|
||||
|
||||
- * 新建数据库
|
||||
- * 现有数据库
|
@ -1,193 +0,0 @@
|
||||
# CodeFirst
|
||||
|
||||
## 类型映射
|
||||
|
||||
| csharp | MySql | SqlServer | PostgreSQL | oracle |
|
||||
| - | - | - | - | - |
|
||||
| bool \| bool? | bit(1) | bit | bool | number(1) |
|
||||
| sbyte \| sbyte? | tinyint(3) | smallint | int2 | number(4) |
|
||||
| short \| short? | smallint(6) | smallint | int2 | number(6) |
|
||||
| int \| int? | int(11) | int | int4 | number(11) |
|
||||
| long \| long? | bigint(20) | bigint | int8 | number(21) |
|
||||
| byte \| byte? | tinyint(3) unsigned | tinyint | int2 | number(3) |
|
||||
| ushort \| ushort? | smallint(5) unsigned | int | int4 | number(5) |
|
||||
| uint \| uint? | int(10) unsigned | bigint | int8 | number(10) |
|
||||
| ulong \| ulong? | bigint(20) unsigned | decimal(20,0) | numeric(20,0) | number(20) |
|
||||
| double \| double? | double | float | float8 | float(126) |
|
||||
| float \| float? | float | real | float4 | float(63) |
|
||||
| decimal \| decimal? | decimal(10,2) | decimal(10,2) | numeric(10,2) | number(10,2) |
|
||||
| Guid \| Guid? | char(36) | uniqueidentifier | uuid | char(36 CHAR) |
|
||||
| TimeSpan \| TimeSpan? | time | time | time | interval day(2) to second(6) |
|
||||
| DateTime \| DateTime? | datetime | datetime | timestamp | timestamp(6) |
|
||||
| DateTimeOffset \| DateTimeOffset? | - | - | datetimeoffset | timestamp(6) with local time zone |
|
||||
| Enum \| Enum? | enum | int | int4 | number(16) |
|
||||
| FlagsEnum \| FlagsEnum? | set | bigint | int8 | number(32) |
|
||||
| byte[] | varbinary(255) | varbinary(255) | bytea | blob |
|
||||
| string | varchar(255) | nvarchar(255) | varchar(255) | nvarchar2(255) |
|
||||
| MygisPoint | point | - | - | - |
|
||||
| MygisLineString | linestring | - | - | - |
|
||||
| MygisPolygon | polygon | - | - | - |
|
||||
| MygisMultiPoint | multipoint | - | - | - |
|
||||
| MygisMultiLineString | multilinestring | - | - | - |
|
||||
| MygisMultiPolygon | multipolygon | - | - | - |
|
||||
| BitArray | - | - | varbit(64) | - |
|
||||
| NpgsqlPoint \| NpgsqlPoint? | - | - | point | - |
|
||||
| NpgsqlLine \| NpgsqlLine? | - | - | line | - |
|
||||
| NpgsqlLSeg \| NpgsqlLSeg? | - | - | lseg | - |
|
||||
| NpgsqlBox \| NpgsqlBox? | - | - | box | - |
|
||||
| NpgsqlPath \| NpgsqlPath? | - | - | path | - |
|
||||
| NpgsqlPolygon \| NpgsqlPolygon? | - | - | polygon | - |
|
||||
| NpgsqlCircle \| NpgsqlCircle? | - | - | circle | - |
|
||||
| (IPAddress Address, int Subnet) \| (IPAddress Address, int Subnet)? | - | - | cidr | - |
|
||||
| IPAddress | - | - | inet | - |
|
||||
| PhysicalAddress | - | - | macaddr | - |
|
||||
| NpgsqlRange\<int\> \| NpgsqlRange\<int\>? | - | - | int4range | - |
|
||||
| NpgsqlRange\<long\> \| NpgsqlRange\<long\>? | - | - | int8range | - |
|
||||
| NpgsqlRange\<decimal\> \| NpgsqlRange\<decimal\>? | - | - | numrange | - |
|
||||
| NpgsqlRange\<DateTime\> \| NpgsqlRange\<DateTime\>? | - | - | tsrange | - |
|
||||
| PostgisPoint | - | - | geometry | - |
|
||||
| PostgisLineString | - | - | geometry | - |
|
||||
| PostgisPolygon | - | - | geometry | - |
|
||||
| PostgisMultiPoint | - | - | geometry | - |
|
||||
| PostgisMultiLineString | - | - | geometry | - |
|
||||
| PostgisMultiPolygon | - | - | geometry | - |
|
||||
| PostgisGeometry | - | - | geometry | - |
|
||||
| PostgisGeometryCollection | - | - | geometry | - |
|
||||
| Dictionary<string, string> | - | - | hstore | - |
|
||||
| JToken | - | - | jsonb | - |
|
||||
| JObject | - | - | jsonb | - |
|
||||
| JArray | - | - | jsonb | - |
|
||||
| 数组 | - | - | 以上所有类型都支持 | - |
|
||||
|
||||
> 以上类型和长度是默认值,可手工设置,如 string 属性可指定 [Column(DbType = "varchar(max)")]
|
||||
|
||||
```csharp
|
||||
IFreeSql fsql = 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")
|
||||
.UseAutoSyncStructure(true)
|
||||
|
||||
.UseMonitorCommand(
|
||||
cmd => {
|
||||
Console.WriteLine(cmd.CommandText);
|
||||
}, //监听SQL命令对象,在执行前
|
||||
(cmd, traceLog) => {
|
||||
Console.WriteLine(traceLog);
|
||||
}) //监听SQL命令对象,在执行后
|
||||
.Build();
|
||||
```
|
||||
|
||||
### 自动同步实体结构【开发环境必备】
|
||||
|
||||
自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改
|
||||
|
||||
```csharp
|
||||
fsql.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 = fsql.CodeFirst.SyncStructure<Topic>();
|
||||
//同步实体类型到数据库
|
||||
```
|
109
Docs/dbfirst.md
@ -1,109 +0,0 @@
|
||||
# DbFirst
|
||||
|
||||
```csharp
|
||||
IFreeSql fsql = 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();
|
||||
```
|
||||
|
||||
### 获取所有数据库
|
||||
|
||||
```csharp
|
||||
var t1 = fsql.DbFirst.GetDatabases();
|
||||
//返回字符串数组, ["cccddd", "test"]
|
||||
```
|
||||
|
||||
### 获取指定数据库的表信息
|
||||
|
||||
```csharp
|
||||
var t2 = fsql.DbFirst.GetTablesByDatabase(fsql.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
|
||||
//创建模板生成类实现
|
||||
var gen = new FreeSql.Generator.TemplateGenerator();
|
||||
gen.Build(fsql.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>
|
||||
```
|
@ -1,82 +0,0 @@
|
||||
# 删除数据
|
||||
|
||||
| 方法 | 返回值 | 参数 | 描述 |
|
||||
| - | - | - | - |
|
||||
| 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
|
||||
IFreeSql fsql = 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();
|
||||
IDelete<Topic> delete => fsql.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 = fsql.Delete<Topic>(new[] { 1, 2 }).ToSql();
|
||||
//DELETE FROM `tb_topic` WHERE (`Id` = 1 OR `Id` = 2)
|
||||
|
||||
var t2 = fsql.Delete<Topic>(new Topic { Id = 1, Title = "test" }).ToSql();
|
||||
//DELETE FROM `tb_topic` WHERE (`Id` = 1)
|
||||
|
||||
var t3 = fsql.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 = fsql.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语句,返回被删除的记录 |
|
@ -1,177 +0,0 @@
|
||||
# 表达式函数
|
||||
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle | 功能说明 |
|
||||
| - | - | - | - | - | - |
|
||||
| a ? b : c | case when a then b else c end | case when a then b else c end | case when a then b else c end | case when a then b else c end | a成立时取b值,否则取c值 |
|
||||
| a ?? b | ifnull(a, b) | isnull(a, b) | coalesce(a, b) | nvl(a, b) | 当a为null时,取b值 |
|
||||
| 数字 + 数字 | a + b | a + b | a + b | a + b | 数字相加 |
|
||||
| 数字 + 字符串 | concat(a, b) | cast(a as varchar) + cast(b as varchar) | case(a as varchar)\|\| b | a\|\| b | 字符串相加,a或b任意一个为字符串时 |
|
||||
| a - b | a - b | a - b | a - b | a - b | 减
|
||||
| a * b | a * b | a * b | a * b | a * b | 乘
|
||||
| a / b | a / b | a / b | a / b | a / b | 除
|
||||
| a % b | a % b | a % b | a % b | mod(a,b) | 模
|
||||
|
||||
> 等等...
|
||||
|
||||
### 数组
|
||||
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle | 功能说明 |
|
||||
| - | - | - | - | - | - |
|
||||
| a.Length | - | - | case when a is null then 0 else array_length(a,1) end | - | 数组长度 |
|
||||
| 常量数组.Length | - | - | array_length(array[常量数组元素逗号分割],1) | - | 数组长度 |
|
||||
| a.Any() | - | - | case when a is null then 0 else array_length(a,1) end > 0 | - | 数组是否为空 |
|
||||
| 常量数组.Contains(b) | b in (常量数组元素逗号分割) | b in (常量数组元素逗号分割) | b in (常量数组元素逗号分割) | b in (常量数组元素逗号分割) | IN查询 |
|
||||
| a.Contains(b) | - | - | a @> array[b] | - | a数组是否包含b元素 |
|
||||
| a.Concat(b) | - | - | a \|\| b | - | 数组相连 |
|
||||
| a.Count() | - | - | 同 Length | - | 数组长度 |
|
||||
|
||||
### 字典 Dictionary<string, string>
|
||||
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle | 功能说明 |
|
||||
| - | - | - | - | - | - |
|
||||
| a.Count | - | - | case when a is null then 0 else array_length(akeys(a),1) end | - | 字典长度 |
|
||||
| a.Keys | - | - | akeys(a) | - | 返回字典所有key数组 |
|
||||
| a.Values | - | - | avals(a) | - | 返回字典所有value数组 |
|
||||
| a.Contains(b) | - | - | a @> b | - | 字典是否包含b
|
||||
| a.ContainsKey(b) | - | - | a? b | - | 字典是否包含key
|
||||
| a.Concat(b) | - | - | a \|\| b | - | 字典相连 |
|
||||
| a.Count() | - | - | 同 Count | - | 字典长度 |
|
||||
|
||||
### JSON JToken/JObject/JArray
|
||||
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle | 功能说明 |
|
||||
| - | - | - | - | - | - |
|
||||
| a.Count | - | - | jsonb_array_length(coalesce(a, '[])) | - | json数组类型的长度 |
|
||||
| a.Any() | - | - | jsonb_array_length(coalesce(a, '[])) > 0 | - | json数组类型,是否为空 |
|
||||
| a.Contains(b) | - | - | coalesce(a, '{}') @> b::jsonb | - | json中是否包含b |
|
||||
| a.ContainsKey(b) | - | - | coalesce(a, '{}') ? b | - | json中是否包含键b |
|
||||
| a.Concat(b) | - | - | coalesce(a, '{}') || b::jsonb | - | 连接两个json |
|
||||
| Parse(a) | - | - | a::jsonb | - | 转化字符串为json类型 |
|
||||
|
||||
### 字符串对象
|
||||
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle | 功能说明 |
|
||||
| - | - | - | - | - | - |
|
||||
| string.Empty | '' | '' | '' | 空字符串表示 |
|
||||
| string.IsNullOrEmpty(a) | (a is null or a = '') | (a is null or a = '') | (a is null or a = '') | (a is null or a = '') | 空字符串表示 |
|
||||
| a.CompareTo(b) | strcmp(a, b) | - | case when a = b then 0 when a > b then 1 else -1 end | case when a = b then 0 when a > b then 1 else -1 end | 比较a和b大小 |
|
||||
| a.Contains('b') | a like '%b%' | a like '%b%' | a ilike'%b%' | a like '%b%' | a是否包含b |
|
||||
| a.EndsWith('b') | a like '%b' | a like '%b' | a ilike'%b' | a like '%b' | a尾部是否包含b |
|
||||
| a.IndexOf(b) | locate(a, b) - 1 | locate(a, b) - 1 | strpos(a, b) - 1 | instr(a, b, 1, 1) - 1 | 查找a中出现b的位置 |
|
||||
| a.Length | char_length(a) | len(a) | char_length(a) | length(a) | 返回a的字符串长度 |
|
||||
| a.PadLeft(b, c) | lpad(a, b, c) | - | lpad(a, b, c) | lpad(a, b, c) | 在a的左侧充字符c,直到字符串长度大于b |
|
||||
| a.PadRight(b, c) | rpad(a, b, c) | - | rpad(a, b, c) | rpad(a, b, c) | 在a的右侧充字符c,直到字符串长度大于b |
|
||||
| a.Replace(b, c) | replace(a, b, c) | replace(a, b, c) | replace(a, b, c) | replace(a, b, c) | 将a中字符串b,替换成c |
|
||||
| a.StartsWith('b') | a like 'b%' | a like 'b%' | a ilike'b%' | a like 'b%' | a头部是否包含b |
|
||||
| a.Substring(b, c) | substr(a, b, c + 1) | substring(a, b, c + 1) | substr(a, b, c + 1) | substr(a, b, c + 1) | 截取a中位置b到c的内容 |
|
||||
| a.ToLower | lower(a) | lower(a) | lower(a) | lower(a) | 转小写 |
|
||||
| a.ToUpper | upper(a) | upper(a) | upper(a) | upper(a) | 转大写 |
|
||||
| a.Trim | trim(a) | trim(a) | trim(a) | trim(a) | 移除两边字符 |
|
||||
| a.TrimEnd | rtrim(a) | rtrim(a) | rtrim(a) | rtrim(a) | 移除左侧指定字符 |
|
||||
| a.TrimStart | ltrim(a) | ltrim(a) | ltrim(a) | ltrim(a) | 移除右侧指定字符 |
|
||||
|
||||
### 日期对象
|
||||
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle |
|
||||
| - | - | - | - | - |
|
||||
| DateTime.Now | now() | getdate() | current_timestamp | systimestamp |
|
||||
| DateTime.UtcNow | utc_timestamp() | getutcdate() | (current_timestamp at time zone 'UTC') | sys_extract_utc(systimestamp) |
|
||||
| DateTime.Today | curdate | convert(char(10),getdate(),120) | current_date | trunc(systimestamp) |
|
||||
| DateTime.MaxValue | cast('9999/12/31 23:59:59' as datetime) | '9999/12/31 23:59:59' | '9999/12/31 23:59:59'::timestamp | to_timestamp('9999-12-31 23:59:59','YYYY-MM-DD HH24:MI:SS.FF6') |
|
||||
| DateTime.MinValue | cast('0001/1/1 0:00:00' as datetime) | '1753/1/1 0:00:00' | '0001/1/1 0:00:00'::timestamp | to_timestamp('0001-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS.FF6') |
|
||||
| DateTime.Compare(a, b) | a - b | a - b | extract(epoch from a::timestamp-b::timestamp) | extract(day from (a-b)) |
|
||||
| DateTime.DaysInMonth(a, b) | dayofmonth(last_day(concat(a, '-', b, '-1'))) | datepart(day, dateadd(day, -1, dateadd(month, 1, cast(a as varchar) + '-' + cast(b as varchar) + '-1'))) | extract(day from (a || '-' || b || '-01')::timestamp+'1 month'::interval-'1 day'::interval) | cast(to_char(last_day(a||'-'||b||'-01'),'DD') as number) |
|
||||
| DateTime.Equals(a, b) | a = b | a = b | a = b | a = b |
|
||||
| DateTime.IsLeapYear(a) | a%4=0 and a%100<>0 or a%400=0 | a%4=0 and a%100<>0 or a%400=0 | a%4=0 and a%100<>0 or a%400=0 | mod(a,4)=0 AND mod(a,100)<>0 OR mod(a,400)=0 |
|
||||
| DateTime.Parse(a) | cast(a as datetime) | cast(a as datetime) | a::timestamp | to_timestamp(a,'YYYY-MM-DD HH24:MI:SS.FF6') |
|
||||
| a.Add(b) | date_add(a, interval b microsecond) | dateadd(millisecond, b / 1000, a) | a::timestamp+(b||' microseconds')::interval | 增加TimeSpan值 | a + b |
|
||||
| a.AddDays(b) | date_add(a, interval b day) | dateadd(day, b, a) | a::timestamp+(b||' day')::interval | a + b |
|
||||
| a.AddHours(b) | date_add(a, interval b hour) | dateadd(hour, b, a) | a::timestamp+(b||' hour')::interval | a + b/24 |
|
||||
| a.AddMilliseconds(b) | date_add(a, interval b*1000 microsecond) | dateadd(millisecond, b, a) | a::timestamp+(b||' milliseconds')::interval | a + b/86400000 |
|
||||
| a.AddMinutes(b) | date_add(a, interval b minute) | dateadd(minute, b, a) | a::timestamp+(b||' minute')::interval | a + b/1440 |
|
||||
| a.AddMonths(b) | date_add(a, interval b month) | dateadd(month, b, a) | a::timestamp+(b||' month')::interval | add_months(a,b) |
|
||||
| a.AddSeconds(b) | date_add(a, interval b second) | dateadd(second, b, a) | a::timestamp+(b||' second')::interval | a + b/86400 |
|
||||
| a.AddTicks(b) | date_add(a, interval b/10 microsecond) | dateadd(millisecond, b / 10000, a) | a::timestamp+(b||' microseconds')::interval | a + b/86400000000 |
|
||||
| a.AddYears(b) | date_add(a, interval b year) | dateadd(year, b, a) | a::timestamp+(b||' year')::interval | add_months(a,b*12) |
|
||||
| a.Date | cast(date_format(a, '%Y-%m-%d') as datetime) | convert(char(10),a,120) | a::date | trunc(a) |
|
||||
| a.Day | dayofmonth(a) | datepart(day, a) | extract(day from a::timestamp) | cast(to_char(a,'DD') as number) |
|
||||
| a.DayOfWeek | dayofweek(a) | datepart(weekday, a) - 1 | extract(dow from a::timestamp) | case when to_char(a)='7' then 0 else cast(to_char(a) as number) end |
|
||||
| a.DayOfYear | dayofyear(a) | datepart(dayofyear, a) | extract(doy from a::timestamp) | cast(to_char(a,'DDD') as number) |
|
||||
| a.Hour | hour(a) | datepart(hour, a) | extract(hour from a::timestamp) | cast(to_char(a,'HH24') as number) |
|
||||
| a.Millisecond | floor(microsecond(a) / 1000) | datepart(millisecond, a) | extract(milliseconds from a::timestamp)-extract(second from a::timestamp)*1000 | cast(to_char(a,'FF3') as number) |
|
||||
| a.Minute | minute(a) | datepart(minute, a) | extract(minute from a::timestamp) | cast(to_char(a,'MI') as number) |
|
||||
| a.Month | month(a) | datepart(month, a) | extract(month from a::timestamp) | cast(to_char(a,'FF3') as number) |
|
||||
| a.Second | second(a) | datepart(second, a) | extract(second from a::timestamp) | cast(to_char(a,'SS') as number) |
|
||||
| a.Subtract(b) | timestampdiff(microsecond, b, a) | datediff(millisecond, b, a) * 1000 | (extract(epoch from a::timestamp-b::timestamp)*1000000) | a - b |
|
||||
| a.Ticks | timestampdiff(microsecond, '0001-1-1', a) * 10 | datediff(millisecond, '1970-1-1', a) * 10000 + 621355968000000000 | extract(epoch from a::timestamp)*10000000+621355968000000000 | cast(to_char(a,'FF7') as number) |
|
||||
| a.TimeOfDay | timestampdiff(microsecond, date_format(a, '%Y-%m-%d'), a) | '1970-1-1 ' + convert(varchar, a, 14) | extract(epoch from a::time)*1000000 | a - trunc(a) |
|
||||
| a.Year | year(a) | datepart(year, a) | extract(year from a::timestamp) | 年 | cast(to_char(a,'YYYY') as number) |
|
||||
| a.Equals(b) | a = b | a = b | a = b | a = b |
|
||||
| a.CompareTo(b) | a - b | a - b | a - b | a - b |
|
||||
| a.ToString() | date_format(a, '%Y-%m-%d %H:%i:%s.%f') | convert(varchar, a, 121) | to_char(a, 'YYYY-MM-DD HH24:MI:SS.US') | to_char(a,'YYYY-MM-DD HH24:MI:SS.FF6') |
|
||||
|
||||
### 时间对象
|
||||
| 表达式 | MySql(微秒) | SqlServer(秒) | PostgreSQL(微秒) | Oracle(Interval day(9) to second(7)) |
|
||||
| - | - | - | - | - |
|
||||
| TimeSpan.Zero | 0 | 0 | - | 0微秒 | numtodsinterval(0,'second') |
|
||||
| TimeSpan.MaxValue | 922337203685477580 | 922337203685477580 | - | numtodsinterval(233720368.5477580,'second') |
|
||||
| TimeSpan.MinValue | -922337203685477580 | -922337203685477580 | - | numtodsinterval(-233720368.5477580,'second') |
|
||||
| TimeSpan.Compare(a, b) | a - b | a - b | - | extract(day from (a-b)) |
|
||||
| TimeSpan.Equals(a, b) | a = b | a = b | - | a = b |
|
||||
| TimeSpan.FromDays(a) | a * 1000000 * 60 * 60 * 24 | a * 1000000 * 60 * 60 * 24 | - | numtodsinterval(a*86400,'second') |
|
||||
| TimeSpan.FromHours(a) | a * 1000000 * 60 * 60 | a * 1000000 * 60 * 60 | - | numtodsinterval(a*3600,'second') |
|
||||
| TimeSpan.FromMilliseconds(a) | a * 1000 | a * 1000 | - | numtodsinterval(a/1000,'second') |
|
||||
| TimeSpan.FromMinutes(a) | a * 1000000 * 60 | a * 1000000 * 60 | - | numtodsinterval(a*60,'second') |
|
||||
| TimeSpan.FromSeconds(a) | a * 1000000 | a * 1000000 | - | numtodsinterval(a,'second') |
|
||||
| TimeSpan.FromTicks(a) | a / 10 | a / 10 | - | numtodsinterval(a/10000000,'second') |
|
||||
| a.Add(b) | a + b | a + b | - | a + b |
|
||||
| a.Subtract(b) | a - b | a - b | - | a - b |
|
||||
| a.CompareTo(b) | a - b | a - b | - | extract(day from (a-b)) |
|
||||
| a.Days | a div (1000000 * 60 * 60 * 24) | a div (1000000 * 60 * 60 * 24) | - | extract(day from a) |
|
||||
| a.Hours | a div (1000000 * 60 * 60) mod 24 | a div (1000000 * 60 * 60) mod 24 | - | extract(hour from a) |
|
||||
| a.Milliseconds | a div 1000 mod 1000 | a div 1000 mod 1000 | - | cast(substr(extract(second from a)-floor(extract(second from a)),2,3) as number) |
|
||||
| a.Seconds | a div 1000000 mod 60 | a div 1000000 mod 60 | - | extract(second from a) |
|
||||
| a.Ticks | a * 10 | a * 10 | - | (extract(day from a)*86400+extract(hour from a)*3600+extract(minute from a)*60+extract(second from a))*10000000 |
|
||||
| a.TotalDays | a / (1000000 * 60 * 60 * 24) | a / (1000000 * 60 * 60 * 24) | - | extract(day from a) |
|
||||
| a.TotalHours | a / (1000000 * 60 * 60) | a / (1000000 * 60 * 60) | - | (extract(day from a)*24+extract(hour from a)) |
|
||||
| a.TotalMilliseconds | a / 1000 | a / 1000 | - | (extract(day from a)*86400+extract(hour from a)*3600+extract(minute from a)*60+extract(second from a))*1000 |
|
||||
| a.TotalMinutes | a / (1000000 * 60) | a / (1000000 * 60) | - | | (extract(day from a)*1440+extract(hour from a)*60+extract(minute from a)) |
|
||||
| a.TotalSeconds | a / 1000000 | a / 1000000 | - | (extract(day from a)*86400+extract(hour from a)*3600+extract(minute from a)*60+extract(second from a)) |
|
||||
| a.Equals(b) | a = b | a = b | - | a = b |
|
||||
| a.ToString() | cast(a as varchar) | cast(a as varchar) | - | to_char(a) |
|
||||
|
||||
### 数学函数
|
||||
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle |
|
||||
| - | - | - | - | - |
|
||||
| Math.Abs(a) | abs(a) | abs(a) | abs(a) |
|
||||
| Math.Acos(a) | acos(a) | acos(a) | acos(a) | acos(a) |
|
||||
| Math.Asin(a) | asin(a) | asin(a) | asin(a) | asin(a) |
|
||||
| Math.Atan(a) | atan(a) | atan(a) | atan(a) | atan(a) |
|
||||
| Math.Atan2(a, b) | atan2(a, b) | atan2(a, b) | atan2(a, b) | - |
|
||||
| Math.Ceiling(a) | ceiling(a) | ceiling(a) | ceiling(a) | ceil(a) |
|
||||
| Math.Cos(a) | cos(a) | cos(a) | cos(a) | cos(a) |
|
||||
| Math.Exp(a) | exp(a) | exp(a) | exp(a) | exp(a) |
|
||||
| Math.Floor(a) | floor(a) | floor(a) | floor(a) | floor(a) |
|
||||
| Math.Log(a) | log(a) | log(a) | log(a) | log(e,a) |
|
||||
| Math.Log10(a) | log10(a) | log10(a) | log10(a) | log(10,a) |
|
||||
| Math.PI(a) | 3.1415926535897931 | 3.1415926535897931 | 3.1415926535897931 | 3.1415926535897931 |
|
||||
| Math.Pow(a, b) | pow(a, b) | power(a, b) | pow(a, b) | power(a, b) |
|
||||
| Math.Round(a, b) | round(a, b) | round(a, b) | round(a, b) | round(a, b) |
|
||||
| Math.Sign(a) | sign(a) | sign(a) | sign(a) | sign(a) |
|
||||
| Math.Sin(a) | sin(a) | sin(a) | sin(a) | sin(a) |
|
||||
| Math.Sqrt(a) | sqrt(a) | sqrt(a) | sqrt(a) | sqrt(a) |
|
||||
| Math.Tan(a) | tan(a) | tan(a) | tan(a) | tan(a) |
|
||||
| Math.Truncate(a) | truncate(a, 0) | floor(a) | trunc(a, 0) | trunc(a, 0) |
|
||||
|
||||
### 类型转换
|
||||
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle |
|
||||
| - | - | - | - | - |
|
||||
| Convert.ToBoolean(a) | a not in ('0','false') | a not in ('0','false') | a::varchar not in ('0','false','f','no') | - |
|
||||
| Convert.ToByte(a) | cast(a as unsigned) | cast(a as tinyint) | a::int2 | cast(a as number) |
|
||||
| Convert.ToChar(a) | substr(cast(a as char),1,1) | substring(cast(a as nvarchar),1,1) | substr(a::char,1,1) | substr(to_char(a),1,1) |
|
||||
| Convert.ToDateTime(a) | cast(a as datetime) | cast(a as datetime) | a::timestamp | to_timestamp(a,'YYYY-MM-DD HH24:MI:SS.FF6') |
|
||||
| Convert.ToDecimal(a) | cast(a as decimal(36,18)) | cast(a as decimal(36,19)) | a::numeric | cast(a as number) |
|
||||
| Convert.ToDouble(a) | cast(a as decimal(32,16)) | cast(a as decimal(32,16)) | a::float8 | cast(a as number) |
|
||||
| Convert.ToInt16(a) | cast(a as signed) | cast(a as smallint) | a::int2 | cast(a as number) |
|
||||
| Convert.ToInt32(a) | cast(a as signed) | cast(a as int) | a::int4 | cast(a as number) |
|
||||
| Convert.ToInt64(a) | cast(a as signed) | cast(a as bigint) | a::int8 | cast(a as number) |
|
||||
| Convert.ToSByte(a) | cast(a as signed) | cast(a as tinyint) | a::int2 | cast(a as number) |
|
||||
| Convert.ToString(a) | cast(a as decimal(14,7)) | cast(a as decimal(14,7)) | a::float4 | to_char(a) |
|
||||
| Convert.ToSingle(a) | cast(a as char) | cast(a as nvarchar) | a::varchar | cast(a as number) |
|
||||
| Convert.ToUInt16(a) | cast(a as unsigned) | cast(a as smallint) | a::int2 | cast(a as number) |
|
||||
| Convert.ToUInt32(a) | cast(a as unsigned) | cast(a as int) | a::int4 | cast(a as number) |
|
||||
| Convert.ToUInt64(a) | cast(a as unsigned) | cast(a as bigint) | a::int8 | cast(a as number) |
|
@ -1,103 +0,0 @@
|
||||
# 生成器
|
||||
|
||||
生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板:
|
||||
|
||||
| 模板名称 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 |
|
||||
| ------------- | - | - |- | - |- | - |
|
||||
| simple-entity | √ | X | X | √ | X | X |
|
||||
| simple-entity-navigation-object | √ | √ | X | √ | X | X |
|
||||
| rich-entity-navigation-object | √ | √ | √ | X | √ | X |
|
||||
|
||||
模板在项目目录:/Templates/MySql
|
||||
|
||||
> 更多模板逐步开发中。。。
|
||||
|
||||
```csharp
|
||||
//定义 mysql FreeSql
|
||||
IFreeSql fsql = 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")
|
||||
.UseAutoSyncStructure(true)
|
||||
|
||||
.UseMonitorCommand(
|
||||
cmd => {
|
||||
Console.WriteLine(cmd.CommandText);
|
||||
}, //监听SQL命令对象,在执行前
|
||||
(cmd, traceLog) => {
|
||||
Console.WriteLine(traceLog);
|
||||
}) //监听SQL命令对象,在执行后
|
||||
.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>
|
||||
```
|
@ -1,79 +0,0 @@
|
||||
# 插入数据
|
||||
|
||||
| 方法 | 返回值 | 参数 | 描述 |
|
||||
| - | - | - | - |
|
||||
| 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
|
||||
IFreeSql fsql = 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();
|
||||
IInsert<Topic> insert => fsql.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语句,返回插入后的记录 |
|
259
Docs/select.md
@ -1,259 +0,0 @@
|
||||
# 查询数据
|
||||
|
||||
## 测试代码
|
||||
|
||||
```csharp
|
||||
IFreeSql fsql = 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();
|
||||
ISelect<Topic> select => fsql.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; }
|
||||
}
|
||||
```
|
||||
|
||||
# Where
|
||||
|
||||
### 单表
|
||||
```csharp
|
||||
var sql = select.Where(a => a.Id == 10).ToSql();
|
||||
///SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a WHERE (a.`Id` = 10)
|
||||
|
||||
sql = select.Where(a => a.Id == 10 && a.Id > 10 || a.Clicks > 100).ToSql();
|
||||
///SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a WHERE (a.`Id` = 10 AND a.`Id` > 10 OR a.`Clicks` > 100)
|
||||
|
||||
sql = select.Where(a => new []{1,2,3}.Contains(a.Id)).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a WHERE (a.`Id` in (1,2,3))
|
||||
```
|
||||
> [《Expression 表达式函数文档》](Docs/expression.md)
|
||||
|
||||
### 多表,使用导航属性
|
||||
```csharp
|
||||
sql = select.Where(a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid).ToSql();
|
||||
///SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeInfo` a__Type WHERE (a__Type.`Name` = 'typeTitle' AND a__Type.`Guid` = a.`TestTypeInfoGuid`)
|
||||
|
||||
sql = select.Where(a => a.Type.Parent.Name == "tparent").ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeInfo` a__Type, `TestTypeParentInfo` a__Type__Parent WHERE (a__Type__Parent.`Name` = 'tparent')
|
||||
```
|
||||
|
||||
### 多表,没有导航属性
|
||||
```csharp
|
||||
sql = select.Where<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "typeTitle").ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeInfo` b WHERE (b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'typeTitle')
|
||||
|
||||
sql = select.Where<TestTypeInfo, TestTypeParentInfo>((a, b, c) => c.Name == "tparent").ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeParentInfo` c WHERE (c.`Name` = 'tparent')
|
||||
```
|
||||
|
||||
### 多表,任意查
|
||||
```csharp
|
||||
sql = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||
.Where(a => a.Id == 10 && c.Name == "xxx")
|
||||
.Where(a => b.ParentId == 20)).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeParentInfo` c, `TestTypeInfo` b WHERE (a.`Id` = 10 AND c.`Name` = 'xxx') AND (b.`ParentId` = 20)
|
||||
```
|
||||
|
||||
### 子表 Exists 查询
|
||||
```csharp
|
||||
var sql2222 = select.Where(a => select.Where(b => b.Id == a.Id).Any()).ToList();
|
||||
// SELECT a.`Id`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
|
||||
// FROM `xxx` a
|
||||
// WHERE (exists(SELECT 1
|
||||
// FROM `xxx` b
|
||||
// WHERE (b.`Id` = a.`Id`)))
|
||||
|
||||
//两级相同的子表查询
|
||||
sql2222 = select.Where(a =>
|
||||
select.Where(b => b.Id == a.Id && select.Where(c => c.Id == b.Id).Where(d => d.Id == a.Id).Where(e => e.Id == b.Id)
|
||||
.Offset(a.Id)
|
||||
.Any()
|
||||
).Any()
|
||||
).ToList();
|
||||
// SELECT a.`Id`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
|
||||
// FROM `xxx` a
|
||||
// WHERE (exists(SELECT 1
|
||||
// FROM `xxx` b
|
||||
// WHERE (b.`Id` = a.`Id` AND exists(SELECT 1
|
||||
// FROM `xxx` c
|
||||
// WHERE (c.`Id` = b.`Id`) AND (c.`Id` = a.`Id`) AND (c.`Id` = b.`Id`)
|
||||
// limit 0,1))
|
||||
// limit 0,1))
|
||||
```
|
||||
|
||||
### 原生SQL
|
||||
```csharp
|
||||
sql = select.Where("a.clicks > 100 && a.id = ?id", new { id = 10 }).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a WHERE (a.clicks > 100 && a.id = ?id)
|
||||
```
|
||||
|
||||
> 以上条件查询,支持 WhereIf
|
||||
|
||||
# 联表
|
||||
|
||||
### 使用导航属性联表
|
||||
```csharp
|
||||
sql = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`
|
||||
|
||||
sql = select
|
||||
.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid)
|
||||
.LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime` 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`
|
||||
```
|
||||
|
||||
### 没有导航属性联表
|
||||
```csharp
|
||||
sql = select.LeftJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid`
|
||||
|
||||
sql = select
|
||||
.LeftJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid)
|
||||
.LeftJoin<TestTypeParentInfo>((a, c) => c.Id == a.Type.ParentId).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` LEFT JOIN `TestTypeParentInfo` c ON c.`Id` = b.`ParentId`
|
||||
```
|
||||
|
||||
### 联表任意查
|
||||
```csharp
|
||||
sql = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
|
||||
.LeftJoin(a => a.TestTypeInfoGuid == b.Guid)
|
||||
.LeftJoin(a => b.ParentId == c.Id)).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON a.`TestTypeInfoGuid` = b.`Guid` LEFT JOIN `TestTypeParentInfo` c ON b.`ParentId` = c.`Id`
|
||||
```
|
||||
|
||||
### 原生SQL联表
|
||||
```csharp
|
||||
sql = select.LeftJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", new { bname = "xxx" }).ToSql();
|
||||
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname
|
||||
```
|
||||
|
||||
# 查询数据
|
||||
|
||||
### 返回 List
|
||||
```csharp
|
||||
List<Topic> t1 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList();
|
||||
```
|
||||
|
||||
### 返回 List + 导航属性的数据
|
||||
```csharp
|
||||
List<Topic> t2 = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToList();
|
||||
//此时会返回普通字段 + 导航对象 Type 的数据
|
||||
```
|
||||
|
||||
### 指定字段返回
|
||||
```csharp
|
||||
//返回一个字段
|
||||
List<int> t3 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList(a => a.Id);
|
||||
|
||||
//返回匿名类
|
||||
List<匿名类> t4 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList(a => new { a.Id, a.Title });
|
||||
|
||||
//返回元组
|
||||
List<(int, string)> t5 = select.Where(a => a.Id > 0).Skip(100).Limit(200).ToList<(int, string)>("id, title");
|
||||
|
||||
//返回SQL字段
|
||||
List<匿名类> t4 = select.Where(a => a.Id > 0).Skip(100).Limit(200)
|
||||
.ToList(a => new {
|
||||
a.Id,
|
||||
a.Title,
|
||||
cstitle = "substr(a.title, 0, 2)", //将 substr(a.title, 0, 2) 作为查询字段
|
||||
csnow = Convert.ToDateTime("now()"), //将 now() 作为查询字段
|
||||
//奇思妙想:怎么查询开窗函数的结果
|
||||
});
|
||||
```
|
||||
|
||||
### 执行SQL返回数据
|
||||
```csharp
|
||||
class xxx {
|
||||
public int Id { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string Title2 { get; set; }
|
||||
}
|
||||
|
||||
List<xxx> t6 = fsql.Ado.Query<xxx>("select * from song");
|
||||
List<(int, string ,string)> t7 = fsql.Ado.Query<(int, string, string)>("select * from song");
|
||||
List<dynamic> t8 = fsql.Ado.Query<dynamic>("select * from song");
|
||||
```
|
||||
|
||||
### 分组聚合
|
||||
```csharp
|
||||
var groupby = fsql.Select<Topic>()
|
||||
.GroupBy(a => new { tt2 = a.Title.Substring(0, 2), mod4 = a.Id % 4 })
|
||||
.Having(a => a.Count() > 0 && a.Avg(a.Key.mod4) > 0 && a.Max(a.Key.mod4) > 0)
|
||||
.Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100)
|
||||
.OrderBy(a => a.Key.tt2)
|
||||
.OrderByDescending(a => a.Count())
|
||||
.ToList(a => new { a.Key.tt2, cou1 = a.Count(), arg1 = a.Avg(a.Key.mod4) });
|
||||
//SELECT substr(a.`Title`, 1, 2) as1, count(1) as2, avg((a.`Id` % 4)) as3
|
||||
//FROM `xxx` a
|
||||
//GROUP BY substr(a.`Title`, 1, 2), (a.`Id` % 4)
|
||||
//HAVING (count(1) > 0 AND avg((a.`Id` % 4)) > 0 AND max((a.`Id` % 4)) > 0) AND (count(1) < 300 OR avg((a.`Id` % 4)) < 100)
|
||||
//ORDER BY substr(a.`Title`, 1, 2), count(1) DESC
|
||||
```
|
||||
|
||||
# 更多文档整理中。。。
|
||||
|
||||
| 方法 | 返回值 | 参数 | 描述 |
|
||||
| ------------- | - | - | - |
|
||||
| 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 }) |
|
||||
| 【分组】 |
|
||||
| GroupBy | \<this\> | Lambda | 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.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 | 缓存查询结果 |
|
129
Docs/update.md
@ -1,129 +0,0 @@
|
||||
# 更新数据
|
||||
|
||||
| 方法 | 返回值 | 参数 | 描述 |
|
||||
| - | - | - | - |
|
||||
| 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; }
|
||||
}
|
||||
|
||||
IFreeSql fsql = 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();
|
||||
IUpdate<Topic> update => fsql.Update<Topic>();
|
||||
```
|
||||
|
||||
### 动态条件
|
||||
```csharp
|
||||
Update<Topic>(object dywhere)
|
||||
```
|
||||
dywhere 支持
|
||||
|
||||
* 主键值
|
||||
* new[] { 主键值1, 主键值2 }
|
||||
* Topic对象
|
||||
* new[] { Topic对象1, Topic对象2 }
|
||||
* new { id = 1 }
|
||||
|
||||
### 更新指定列
|
||||
```csharp
|
||||
var t1 = fsql.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 = fsql.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语句,返回更新后的记录 |
|
158
Examples/aspnetcore_transaction/Controllers/HomeController.cs
Normal file
@ -0,0 +1,158 @@
|
||||
using FreeSql;
|
||||
using FreeSql.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace aspnetcore_transaction.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("")]
|
||||
public class HomeController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
|
||||
public HomeController(ILogger<HomeController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet("1")]
|
||||
//[Transactional]
|
||||
virtual public object Get([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
|
||||
[FromServices] SongService serviceSong)
|
||||
{
|
||||
serviceSong.Test1();
|
||||
return "111";
|
||||
}
|
||||
|
||||
[HttpGet("2")]
|
||||
//[Transactional]
|
||||
async virtual public Task<object> GetAsync([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
|
||||
[FromServices] SongService serviceSong)
|
||||
{
|
||||
await serviceSong.Test2();
|
||||
await serviceSong.Test3();
|
||||
return "111";
|
||||
}
|
||||
}
|
||||
|
||||
public class SongService
|
||||
{
|
||||
BaseRepository<Song> _repoSong;
|
||||
BaseRepository<Detail> _repoDetail;
|
||||
SongRepository _repoSong2;
|
||||
|
||||
public SongService(BaseRepository<Song> repoSong, BaseRepository<Detail> repoDetail, SongRepository repoSong2)
|
||||
{
|
||||
var tb = repoSong.Orm.CodeFirst.GetTableByEntity(typeof(Song));
|
||||
_repoSong = repoSong;
|
||||
_repoDetail = repoDetail;
|
||||
_repoSong2 = repoSong2;
|
||||
}
|
||||
|
||||
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
||||
public virtual void Test1()
|
||||
{
|
||||
_repoSong.Insert(new Song());
|
||||
_repoDetail.Insert(new Detail());
|
||||
_repoSong2.Insert(new Song());
|
||||
}
|
||||
|
||||
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
||||
async public virtual Task Test2()
|
||||
{
|
||||
await _repoSong.InsertAsync(new Song());
|
||||
await _repoDetail.InsertAsync(new Detail());
|
||||
await _repoSong2.InsertAsync(new Song());
|
||||
}
|
||||
|
||||
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
||||
async public virtual Task<object> Test3()
|
||||
{
|
||||
await _repoSong.InsertAsync(new Song());
|
||||
await _repoDetail.InsertAsync(new Detail());
|
||||
await _repoSong2.InsertAsync(new Song());
|
||||
return "123";
|
||||
}
|
||||
}
|
||||
|
||||
public class SongRepository : DefaultRepository<Song, int>
|
||||
{
|
||||
public SongRepository(UnitOfWorkManager uowm) : base(uowm?.Orm, uowm) { }
|
||||
}
|
||||
|
||||
[Description("123")]
|
||||
public class Song
|
||||
{
|
||||
/// <summary>
|
||||
/// 自增
|
||||
/// </summary>
|
||||
[Column(IsIdentity = true)]
|
||||
[Description("自增id")]
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
}
|
||||
public class Detail
|
||||
{
|
||||
[Column(IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
public int SongId { get; set; }
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
||||
public static class IdleBusExtesions
|
||||
{
|
||||
static AsyncLocal<string> AsyncLocalTenantId = new AsyncLocal<string>();
|
||||
public static IdleBus<IFreeSql> ChangeTenant(this IdleBus<IFreeSql> ib, string tenantId)
|
||||
{
|
||||
AsyncLocalTenantId.Value = tenantId;
|
||||
return ib;
|
||||
}
|
||||
public static IFreeSql Get(this IdleBus<IFreeSql> ib) => ib.Get(AsyncLocalTenantId.Value ?? "default");
|
||||
public static IBaseRepository<T> GetRepository<T>(this IdleBus<IFreeSql> ib) where T : class => ib.Get().GetRepository<T>();
|
||||
|
||||
static void test()
|
||||
{
|
||||
IdleBus<IFreeSql> ib = null; //单例注入
|
||||
|
||||
var fsql = ib.Get(); //获取当前租户对应的 IFreeSql
|
||||
|
||||
var fsql00102 = ib.ChangeTenant("00102").Get(); //切换租户,后面的操作都是针对 00102
|
||||
|
||||
var songRepository = ib.GetRepository<Song>();
|
||||
var detailRepository = ib.GetRepository<Detail>();
|
||||
}
|
||||
|
||||
public static IServiceCollection AddRepository(this IServiceCollection services, params Assembly[] assemblies)
|
||||
{
|
||||
services.AddScoped(typeof(IBaseRepository<>), typeof(YourDefaultRepository<>));
|
||||
services.AddScoped(typeof(BaseRepository<>), typeof(YourDefaultRepository<>));
|
||||
|
||||
services.AddScoped(typeof(IBaseRepository<,>), typeof(YourDefaultRepository<,>));
|
||||
services.AddScoped(typeof(BaseRepository<,>), typeof(YourDefaultRepository<,>));
|
||||
|
||||
if (assemblies?.Any() == true)
|
||||
foreach (var asse in assemblies)
|
||||
foreach (var repo in asse.GetTypes().Where(a => a.IsAbstract == false && typeof(IBaseRepository).IsAssignableFrom(a)))
|
||||
services.AddScoped(repo);
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
class YourDefaultRepository<T> : BaseRepository<T> where T : class
|
||||
{
|
||||
public YourDefaultRepository(IdleBus<IFreeSql> ib) : base(ib.Get(), null, null) { }
|
||||
}
|
||||
class YourDefaultRepository<T, TKey> : BaseRepository<T, TKey> where T : class
|
||||
{
|
||||
public YourDefaultRepository(IdleBus<IFreeSql> ib) : base(ib.Get(), null, null) { }
|
||||
}
|
||||
}
|
27
Examples/aspnetcore_transaction/Program.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace aspnetcore_transaction
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
})
|
||||
.UseServiceProviderFactory(new FreeSql.DynamicProxyServiceProviderFactory());
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:35350/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"dbcontext_01": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:35351/"
|
||||
}
|
||||
}
|
||||
}
|
61
Examples/aspnetcore_transaction/Startup.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using aspnetcore_transaction.Controllers;
|
||||
using FreeSql;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace aspnetcore_transaction
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
Fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\test_trans.db")
|
||||
.UseAutoSyncStructure(true)
|
||||
.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText))
|
||||
.UseNoneCommandParameter(true)
|
||||
.Build();
|
||||
|
||||
Fsql.Aop.TraceBefore += (_, e) => Trace.WriteLine($"----TraceBefore---{e.Identifier} {e.Operation}");
|
||||
Fsql.Aop.TraceAfter += (_, e) => Trace.WriteLine($"----TraceAfter---{e.Identifier} {e.Operation} {e.Remark} {e.Exception?.Message} {e.ElapsedMilliseconds}ms\r\n");
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
public static IFreeSql Fsql { get; private set; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllersWithViews();
|
||||
|
||||
services.AddSingleton<IFreeSql>(Fsql);
|
||||
services.AddScoped<UnitOfWorkManager>();
|
||||
services.AddFreeRepository(null, typeof(Startup).Assembly);
|
||||
services.AddScoped<SongService>();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
||||
Console.InputEncoding = Encoding.GetEncoding("GB2312");
|
||||
|
||||
app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(a => a.MapControllers());
|
||||
}
|
||||
}
|
||||
}
|
54
Examples/aspnetcore_transaction/TransactionalAttribute.cs
Normal file
@ -0,0 +1,54 @@
|
||||
using FreeSql;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FreeSql
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用事务执行,请查看 Program.cs 代码开启动态代理
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class TransactionalAttribute : DynamicProxyAttribute, IActionFilter
|
||||
{
|
||||
public Propagation Propagation { get; set; } = Propagation.Required;
|
||||
public IsolationLevel IsolationLevel { get => _IsolationLevelPriv.Value; set => _IsolationLevelPriv = value; }
|
||||
IsolationLevel? _IsolationLevelPriv;
|
||||
|
||||
[DynamicProxyFromServices]
|
||||
#pragma warning disable IDE0044 // 添加只读修饰符
|
||||
UnitOfWorkManager _uowManager;
|
||||
#pragma warning restore IDE0044 // 添加只读修饰符
|
||||
IUnitOfWork _uow;
|
||||
|
||||
public override Task Before(DynamicProxyBeforeArguments args) => OnBefore(_uowManager);
|
||||
public override Task After(DynamicProxyAfterArguments args) => OnAfter(args.Exception);
|
||||
|
||||
//这里是为了 controller
|
||||
public void OnActionExecuting(ActionExecutingContext context) => OnBefore(context.HttpContext.RequestServices.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager);
|
||||
public void OnActionExecuted(ActionExecutedContext context) => OnAfter(context.Exception);
|
||||
|
||||
|
||||
Task OnBefore(UnitOfWorkManager uowm)
|
||||
{
|
||||
_uow = uowm.Begin(this.Propagation, this._IsolationLevelPriv);
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
Task OnAfter(Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ex == null) _uow.Commit();
|
||||
else _uow.Rollback();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_uow.Dispose();
|
||||
}
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>aspnetcore_transaction.xml</DocumentationFile>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<NoWarn>1701;1702;1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
<PackageReference Include="FreeSql.DynamicProxy" Version="1.4.0" />
|
||||
<PackageReference Include="IdleBus" Version="1.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
18
Examples/aspnetcore_transaction/aspnetcore_transaction.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>aspnetcore_transaction</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="P:aspnetcore_transaction.Controllers.Song.Id">
|
||||
<summary>
|
||||
自增
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:FreeSql.TransactionalAttribute">
|
||||
<summary>
|
||||
使用事务执行,请查看 Program.cs 代码开启动态代理
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
59
Examples/base_entity/Entities/User.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using FreeSql;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class UserGroup : BaseEntity<UserGroup, int>
|
||||
{
|
||||
/// <summary>
|
||||
/// 组名
|
||||
/// </summary>
|
||||
public string GroupName { get; set; }
|
||||
|
||||
public List<User1> User1s { get; set; }
|
||||
}
|
||||
|
||||
public class Role : BaseEntity<Role, string>
|
||||
{
|
||||
public List<User1> User1s { get; set; }
|
||||
}
|
||||
public class RoleUser1 : BaseEntity<RoleUser1>
|
||||
{
|
||||
public string RoleId { get; set; }
|
||||
public Guid User1Id { get; set; }
|
||||
|
||||
public Role Role { get; set; }
|
||||
public User1 User1 { get; set; }
|
||||
}
|
||||
|
||||
public class User1 : BaseEntity<User1, Guid>
|
||||
{
|
||||
public int GroupId { get; set; }
|
||||
public UserGroup Group { get; set; }
|
||||
|
||||
public virtual List<Role> Roles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 登陆名
|
||||
/// </summary>
|
||||
[MaxLength(32)]
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// </summary>
|
||||
[MaxLength(64)]
|
||||
public string Nickname { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 头像
|
||||
/// </summary>
|
||||
[MaxLength(1024)]
|
||||
public string Avatar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
[MaxLength(4000)]
|
||||
public string Description { get; set; }
|
||||
}
|
405
Examples/base_entity/Program.cs
Normal file
@ -0,0 +1,405 @@
|
||||
using FreeSql;
|
||||
using FreeSql.DataAnnotations;
|
||||
using FreeSql.Extensions;
|
||||
using FreeSql.Internal.CommonProvider;
|
||||
using FreeSql.Internal.Model;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Data.Odbc;
|
||||
using System.Data.SqlClient;
|
||||
using System.Data.SQLite;
|
||||
using System.Diagnostics;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace base_entity
|
||||
{
|
||||
class Program
|
||||
{
|
||||
class TestConfig
|
||||
{
|
||||
public int clicks { get; set; }
|
||||
public string title { get; set; }
|
||||
}
|
||||
[Table(Name = "sysconfig")]
|
||||
public class S_SysConfig<T> : BaseEntity<S_SysConfig<T>>
|
||||
{
|
||||
[Column(IsPrimary = true)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonMap]
|
||||
public T Config { get; set; }
|
||||
|
||||
public T Config2 { get; set; }
|
||||
}
|
||||
|
||||
public class Products : BaseEntity<Products, int>
|
||||
{
|
||||
public string title { get; set; }
|
||||
public int testint { get; set; }
|
||||
}
|
||||
|
||||
static AsyncLocal<IUnitOfWork> _asyncUow = new AsyncLocal<IUnitOfWork>();
|
||||
|
||||
public class TestEnumCls
|
||||
{
|
||||
public CollationTypeEnum val { get; set; } = CollationTypeEnum.Binary;
|
||||
}
|
||||
|
||||
class Sys_reg_user
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid OwnerId { get; set; }
|
||||
public string UnionId { get; set; }
|
||||
|
||||
[Navigate(nameof(OwnerId))]
|
||||
public Sys_owner Owner { get; set; }
|
||||
}
|
||||
class Sys_owner
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid RegUserId { get; set; }
|
||||
|
||||
[Navigate(nameof(RegUserId))]
|
||||
public Sys_reg_user RegUser { get; set; }
|
||||
}
|
||||
|
||||
public class tttorder
|
||||
{
|
||||
[Column(IsPrimary = true)]
|
||||
public long Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
|
||||
|
||||
public tttorder(string title, int quantity, decimal price)
|
||||
{
|
||||
Id = DateTime.Now.Ticks;
|
||||
Title = title;
|
||||
Quantity = quantity;
|
||||
Price = price;
|
||||
}
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
#region 初始化 IFreeSql
|
||||
var fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseAutoSyncStructure(true)
|
||||
.UseNoneCommandParameter(true)
|
||||
|
||||
.UseConnectionString(FreeSql.DataType.Sqlite, "data source=test.db;max pool size=5")
|
||||
|
||||
.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=2")
|
||||
|
||||
//.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=3")
|
||||
|
||||
//.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=2")
|
||||
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToLower)
|
||||
|
||||
//.UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2")
|
||||
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper)
|
||||
|
||||
|
||||
//.UseConnectionString(FreeSql.DataType.OdbcMySql, "Driver={MySQL ODBC 8.0 Unicode Driver};Server=127.0.0.1;Persist Security Info=False;Trusted_Connection=Yes;UID=root;PWD=root;DATABASE=cccddd_odbc;Charset=utf8;SslMode=none;Max pool size=2")
|
||||
|
||||
//.UseConnectionString(FreeSql.DataType.OdbcSqlServer, "Driver={SQL Server};Server=.;Persist Security Info=False;Trusted_Connection=Yes;Integrated Security=True;DATABASE=freesqlTest_odbc;Pooling=true;Max pool size=3")
|
||||
|
||||
//.UseConnectionString(FreeSql.DataType.OdbcPostgreSQL, "Driver={PostgreSQL Unicode(x64)};Server=192.168.164.10;Port=5432;UID=postgres;PWD=123456;Database=tedb_odbc;Pooling=true;Maximum Pool Size=2")
|
||||
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToLower)
|
||||
|
||||
//.UseConnectionString(FreeSql.DataType.OdbcOracle, "Driver={Oracle in XE};Server=//127.0.0.1:1521/XE;Persist Security Info=False;Trusted_Connection=Yes;UID=odbc1;PWD=123456")
|
||||
//.UseNameConvert(FreeSql.Internal.NameConvertType.ToUpper)
|
||||
|
||||
//.UseConnectionString(FreeSql.DataType.OdbcDameng, "Driver={DM8 ODBC DRIVER};Server=127.0.0.1:5236;Persist Security Info=False;Trusted_Connection=Yes;UID=USER1;PWD=123456789")
|
||||
|
||||
.UseMonitorCommand(umcmd => Console.WriteLine(umcmd.CommandText))
|
||||
.UseLazyLoading(true)
|
||||
.Build();
|
||||
BaseEntity.Initialization(fsql, () => _asyncUow.Value);
|
||||
#endregion
|
||||
|
||||
fsql.Insert(new tttorder("xx1", 1, 10)).ExecuteAffrows();
|
||||
fsql.Insert(new tttorder("xx2", 2, 20)).ExecuteAffrows();
|
||||
|
||||
var tttorders = fsql.Select<tttorder>().Limit(2).ToList();
|
||||
|
||||
var tsql1 = fsql.Select<Sys_reg_user>()
|
||||
.Include(a => a.Owner)
|
||||
.Where(a => a.UnionId == "xxx")
|
||||
.ToSql();
|
||||
var tsql2 = fsql.Select<Sys_owner>()
|
||||
.Where(a => a.RegUser.UnionId == "xxx2")
|
||||
.ToSql();
|
||||
|
||||
|
||||
var names = (fsql.Select<object>() as Select0Provider)._commonUtils.SplitTableName("`Backups.ProductStockBak`");
|
||||
|
||||
|
||||
var dbparams = fsql.Ado.GetDbParamtersByObject(new { id = 1, name = "xxx" });
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var sql = fsql.CodeFirst.GetComparisonDDLStatements(typeof(EMSServerModel.Model.User), "testxsx001");
|
||||
|
||||
var test01 = EMSServerModel.Model.User.Select.IncludeMany(a => a.Roles).ToList();
|
||||
var test02 = EMSServerModel.Model.UserRole.Select.ToList();
|
||||
var test01tb = EMSServerModel.Model.User.Orm.CodeFirst.GetTableByEntity(typeof(EMSServerModel.Model.User));
|
||||
|
||||
var us = User1.Select.Limit(10).ToList();
|
||||
|
||||
new Products { title = "product-1" }.Save();
|
||||
new Products { title = "product-2" }.Save();
|
||||
new Products { title = "product-3" }.Save();
|
||||
new Products { title = "product-4" }.Save();
|
||||
new Products { title = "product-5" }.Save();
|
||||
|
||||
var wdy1 = JsonConvert.DeserializeObject<DynamicFilterInfo>(@"
|
||||
{
|
||||
""Logic"" : ""And"",
|
||||
""Filters"" :
|
||||
[
|
||||
{
|
||||
""Logic"" : ""Or"",
|
||||
""Filters"" :
|
||||
[
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : ""contains"",
|
||||
""Value"" : ""product-1111"",
|
||||
},
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : ""contains"",
|
||||
""Value"" : ""product-2222"",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : ""eq"",
|
||||
""Value"" : ""product-2""
|
||||
},
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : ""eq"",
|
||||
""Value"" : ""product-3""
|
||||
},
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : ""eq"",
|
||||
""Value"" : ""product-4""
|
||||
},
|
||||
{
|
||||
""Field"" : ""testint"",
|
||||
""Operator"" : ""Range"",
|
||||
""Value"" : [100,200]
|
||||
},
|
||||
{
|
||||
""Field"" : ""testint"",
|
||||
""Operator"" : ""Range"",
|
||||
""Value"" : [""101"",""202""]
|
||||
},
|
||||
]
|
||||
}
|
||||
");
|
||||
var config = new JsonSerializerOptions()
|
||||
{
|
||||
PropertyNamingPolicy = null,
|
||||
AllowTrailingCommas = true,
|
||||
IgnoreNullValues = true,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
Converters = { new JsonStringEnumConverter() }
|
||||
};
|
||||
var wdy2 = System.Text.Json.JsonSerializer.Deserialize<DynamicFilterInfo>(@"
|
||||
{
|
||||
""Logic"" : 1,
|
||||
""Filters"" :
|
||||
[
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : 8,
|
||||
""Value"" : ""product-1"",
|
||||
""Filters"" :
|
||||
[
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : 0,
|
||||
""Value"" : ""product-1111""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : 8,
|
||||
""Value"" : ""product-2""
|
||||
},
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : 8,
|
||||
""Value"" : ""product-3""
|
||||
},
|
||||
{
|
||||
""Field"" : ""title"",
|
||||
""Operator"" : 8,
|
||||
""Value"" : ""product-4""
|
||||
},
|
||||
{
|
||||
""Field"" : ""testint"",
|
||||
""Operator"" : 8,
|
||||
""Value"" : 11
|
||||
},
|
||||
{
|
||||
""Field"" : ""testint"",
|
||||
""Operator"" : 8,
|
||||
""Value"" : ""12""
|
||||
},
|
||||
{
|
||||
""Field"" : ""testint"",
|
||||
""Operator"" : ""Range"",
|
||||
""Value"" : [100,200]
|
||||
},
|
||||
{
|
||||
""Field"" : ""testint"",
|
||||
""Operator"" : ""Range"",
|
||||
""Value"" : [""101"",""202""]
|
||||
}
|
||||
]
|
||||
}
|
||||
", config);
|
||||
Products.Select.WhereDynamicFilter(wdy1).ToList();
|
||||
Products.Select.WhereDynamicFilter(wdy2).ToList();
|
||||
|
||||
var items1 = Products.Select.Limit(10).OrderByDescending(a => a.CreateTime).ToList();
|
||||
var items2 = fsql.Select<Products>().Limit(10).OrderByDescending(a => a.CreateTime).ToList();
|
||||
|
||||
BaseEntity.Orm.UseJsonMap();
|
||||
BaseEntity.Orm.UseJsonMap();
|
||||
BaseEntity.Orm.CodeFirst.ConfigEntity<S_SysConfig<TestConfig>>(a =>
|
||||
{
|
||||
a.Property(b => b.Config2).JsonMap();
|
||||
});
|
||||
|
||||
new S_SysConfig<TestConfig> { Name = "testkey11", Config = new TestConfig { clicks = 11, title = "testtitle11" }, Config2 = new TestConfig { clicks = 11, title = "testtitle11" } }.Save();
|
||||
new S_SysConfig<TestConfig> { Name = "testkey22", Config = new TestConfig { clicks = 22, title = "testtitle22" }, Config2 = new TestConfig { clicks = 11, title = "testtitle11" } }.Save();
|
||||
new S_SysConfig<TestConfig> { Name = "testkey33", Config = new TestConfig { clicks = 33, title = "testtitle33" }, Config2 = new TestConfig { clicks = 11, title = "testtitle11" } }.Save();
|
||||
var testconfigs11 = S_SysConfig<TestConfig>.Select.ToList();
|
||||
var testconfigs11tb = S_SysConfig<TestConfig>.Select.ToDataTable();
|
||||
var testconfigs111 = S_SysConfig<TestConfig>.Select.ToList(a => a.Name);
|
||||
var testconfigs112 = S_SysConfig<TestConfig>.Select.ToList(a => a.Config);
|
||||
var testconfigs1122 = S_SysConfig<TestConfig>.Select.ToList(a => new { a.Name, a.Config });
|
||||
var testconfigs113 = S_SysConfig<TestConfig>.Select.ToList(a => a.Config2);
|
||||
var testconfigs1133 = S_SysConfig<TestConfig>.Select.ToList(a => new { a.Name, a.Config2 });
|
||||
|
||||
var repo = BaseEntity.Orm.Select<TestConfig>().Limit(10).ToList();
|
||||
|
||||
|
||||
//void ConfigEntityProperty(object sender, FreeSql.Aop.ConfigEntityPropertyEventArgs e)
|
||||
//{
|
||||
// if (e.Property.PropertyType == typeof(byte[]))
|
||||
// {
|
||||
// var orm = sender as IFreeSql;
|
||||
// switch (orm.Ado.DataType)
|
||||
// {
|
||||
// case DataType.SqlServer:
|
||||
// e.ModifyResult.DbType = "image";
|
||||
// break;
|
||||
// case DataType.MySql:
|
||||
// e.ModifyResult.DbType = "longblob";
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//fsql.Aop.ConfigEntityProperty += ConfigEntityProperty;
|
||||
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
using (var uow = BaseEntity.Orm.CreateUnitOfWork())
|
||||
{
|
||||
_asyncUow.Value = uow;
|
||||
try
|
||||
{
|
||||
var id = (await new User1().SaveAsync()).Id;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_asyncUow.Value = null;
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
var ug1 = new UserGroup();
|
||||
ug1.GroupName = "分组一";
|
||||
await ug1.InsertAsync();
|
||||
|
||||
var ug2 = new UserGroup();
|
||||
ug2.GroupName = "分组二";
|
||||
await ug2.InsertAsync();
|
||||
|
||||
var u1 = new User1();
|
||||
|
||||
u1.GroupId = ug1.Id;
|
||||
await u1.SaveAsync();
|
||||
|
||||
await u1.DeleteAsync();
|
||||
await u1.RestoreAsync();
|
||||
|
||||
u1.Nickname = "x1";
|
||||
await u1.UpdateAsync();
|
||||
|
||||
var u11 = await User1.FindAsync(u1.Id);
|
||||
u11.Description = "备注";
|
||||
await u11.SaveAsync();
|
||||
|
||||
await u11.DeleteAsync();
|
||||
|
||||
var slslsl = Newtonsoft.Json.JsonConvert.SerializeObject(u1);
|
||||
var u11null = User1.Find(u1.Id);
|
||||
|
||||
var u11s = User1.Where(a => a.Group.Id == ug1.Id).Limit(10).ToList();
|
||||
|
||||
var u11s2 = User1.Select.LeftJoin<UserGroup>((a, b) => a.GroupId == b.Id).Limit(10).ToList();
|
||||
|
||||
var ug1s = UserGroup.Select
|
||||
.IncludeMany(a => a.User1s)
|
||||
.Limit(10).ToList();
|
||||
|
||||
var ug1s2 = UserGroup.Select.Where(a => a.User1s.AsSelect().Any(b => b.Nickname == "x1")).Limit(10).ToList();
|
||||
|
||||
var r1 = new Role();
|
||||
r1.Id = "管理员";
|
||||
await r1.SaveAsync();
|
||||
|
||||
var r2 = new Role();
|
||||
r2.Id = "超级会员";
|
||||
await r2.SaveAsync();
|
||||
|
||||
var ru1 = new RoleUser1();
|
||||
ru1.User1Id = u1.Id;
|
||||
ru1.RoleId = r1.Id;
|
||||
await ru1.SaveAsync();
|
||||
|
||||
ru1.RoleId = r2.Id;
|
||||
await ru1.SaveAsync();
|
||||
|
||||
var u1roles = await User1.Select.IncludeMany(a => a.Roles).ToListAsync();
|
||||
var u1roles2 = await User1.Select.Where(a => a.Roles.AsSelect().Any(b => b.Id == "xx")).ToListAsync();
|
||||
|
||||
}).Wait();
|
||||
|
||||
|
||||
|
||||
Console.WriteLine("按任意键结束。。。");
|
||||
Console.ReadKey();
|
||||
}
|
||||
}
|
||||
}
|
52
Examples/base_entity/Test01/Role.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using FreeSql.DataAnnotations;
|
||||
using FreeSql;
|
||||
|
||||
namespace EMSServerModel.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色表
|
||||
/// </summary>
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public partial class Role : BaseEntity<Role>{
|
||||
/// <summary>
|
||||
/// 角色编号
|
||||
/// </summary>
|
||||
[JsonProperty, Column(IsPrimary = true, IsIdentity = true)]
|
||||
public long RoleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色名称
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string RoleName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 角色描述
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string RoleDesc { get; set; } = string.Empty;
|
||||
|
||||
///// <summary>
|
||||
///// 创建时间
|
||||
///// </summary>
|
||||
//[JsonProperty, Column(DbType = "date")]
|
||||
//public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 启用
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public bool IsEnable { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 角色用户多对多导航
|
||||
/// </summary>
|
||||
[Navigate(ManyToMany = typeof(UserRole))]
|
||||
public virtual ICollection<User> Users { get; protected set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
157
Examples/base_entity/Test01/User.cs
Normal file
@ -0,0 +1,157 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using FreeSql.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using FreeSql;
|
||||
|
||||
namespace EMSServerModel.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户表bb123123
|
||||
/// </summary>
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public partial class User : BaseEntity<User> {
|
||||
|
||||
//[JsonProperty, Column(IsIdentity = true)]
|
||||
//public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 编号
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)", IsPrimary = true)]
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 头像
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string Avatar { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 姓名
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 艺名
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string NickName { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 电话
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string Tel { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 性别
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public Sex Sex { get; set; } = Sex.男;
|
||||
|
||||
/// <summary>
|
||||
/// 证件号
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string UID { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 生日
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "date")]
|
||||
public DateTime? DateOfBirth { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 出生地
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string PlaceOfBirth { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 居住地
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string Addr { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string Pwd { get; set; } = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 部门编号
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public long? DeptId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 职务编号
|
||||
/// </summary>
|
||||
[JsonProperty, Column(IsNullable = true)]
|
||||
public long TitleId { get; set; }
|
||||
|
||||
[JsonProperty]
|
||||
public long TitleId2 { get; set; }
|
||||
|
||||
|
||||
///// <summary>
|
||||
///// 创建时间
|
||||
///// </summary>
|
||||
//[JsonProperty, Column(DbType = "date")]
|
||||
//public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 国籍
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string Nationality { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 经手人
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string Handler { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 启用
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public bool IsEnable { get; set; } = true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(100)")]
|
||||
public string Memos { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Navigate(ManyToMany = typeof(UserRole))]
|
||||
public virtual ICollection<Role> Roles { get; protected set; }
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 性别枚举
|
||||
/// </summary>
|
||||
public enum Sex
|
||||
{
|
||||
/// <summary>
|
||||
/// 女=0
|
||||
/// </summary>
|
||||
女=0,
|
||||
/// <summary>
|
||||
/// 男=1
|
||||
/// </summary>
|
||||
男=1
|
||||
}
|
||||
|
||||
}
|
36
Examples/base_entity/Test01/UserRole.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using Newtonsoft.Json;
|
||||
using FreeSql.DataAnnotations;
|
||||
using FreeSql;
|
||||
|
||||
namespace EMSServerModel.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户角色关系表aa111
|
||||
/// </summary>
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public partial class UserRole : BaseEntity<UserRole>{
|
||||
/// <summary>
|
||||
/// 角色编号1
|
||||
/// </summary>
|
||||
[JsonProperty]
|
||||
public long RoleId { get; set; }
|
||||
/// <summary>
|
||||
/// 角色导航
|
||||
/// </summary>
|
||||
[Navigate("RoleId")]
|
||||
public Role Roles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户编号
|
||||
/// </summary>
|
||||
[JsonProperty, Column(DbType = "varchar(50)")]
|
||||
public string UserId { get; set; }
|
||||
/// <summary>
|
||||
/// 用户导航
|
||||
/// </summary>
|
||||
[Navigate("UserId")]
|
||||
public User Users { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
32
Examples/base_entity/base_entity.csproj
Normal file
@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>base_entity.xml</DocumentationFile>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<NoWarn>1701;1702;1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Extensions\FreeSql.Extensions.BaseEntity\FreeSql.Extensions.BaseEntity.csproj" />
|
||||
<ProjectReference Include="..\..\Extensions\FreeSql.Extensions.JsonMap\FreeSql.Extensions.JsonMap.csproj" />
|
||||
<ProjectReference Include="..\..\Extensions\FreeSql.Extensions.LazyLoading\FreeSql.Extensions.LazyLoading.csproj" />
|
||||
<ProjectReference Include="..\..\FreeSql.Repository\FreeSql.Repository.csproj" />
|
||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.MySql\FreeSql.Provider.MySql.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Odbc\FreeSql.Provider.Odbc.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Oracle\FreeSql.Provider.Oracle.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.PostgreSQL\FreeSql.Provider.PostgreSQL.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.SqlServer\FreeSql.Provider.SqlServer.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
198
Examples/base_entity/base_entity.xml
Normal file
@ -0,0 +1,198 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>base_entity</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="P:UserGroup.GroupName">
|
||||
<summary>
|
||||
组名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:User1.Username">
|
||||
<summary>
|
||||
登陆名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:User1.Nickname">
|
||||
<summary>
|
||||
昵称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:User1.Avatar">
|
||||
<summary>
|
||||
头像
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:User1.Description">
|
||||
<summary>
|
||||
描述
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:EMSServerModel.Model.Role">
|
||||
<summary>
|
||||
角色表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.Role.RoleId">
|
||||
<summary>
|
||||
角色编号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.Role.RoleName">
|
||||
<summary>
|
||||
角色名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.Role.RoleDesc">
|
||||
<summary>
|
||||
角色描述
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.Role.IsEnable">
|
||||
<summary>
|
||||
启用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.Role.Users">
|
||||
<summary>
|
||||
角色用户多对多导航
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:EMSServerModel.Model.User">
|
||||
<summary>
|
||||
用户表bb123123
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.UserId">
|
||||
<summary>
|
||||
编号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Avatar">
|
||||
<summary>
|
||||
头像
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.UserName">
|
||||
<summary>
|
||||
姓名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.NickName">
|
||||
<summary>
|
||||
艺名
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Tel">
|
||||
<summary>
|
||||
电话
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Sex">
|
||||
<summary>
|
||||
性别
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.UID">
|
||||
<summary>
|
||||
证件号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.DateOfBirth">
|
||||
<summary>
|
||||
生日
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.PlaceOfBirth">
|
||||
<summary>
|
||||
出生地
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Addr">
|
||||
<summary>
|
||||
居住地
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Pwd">
|
||||
<summary>
|
||||
密码
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.DeptId">
|
||||
<summary>
|
||||
部门编号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.TitleId">
|
||||
<summary>
|
||||
职务编号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Nationality">
|
||||
<summary>
|
||||
国籍
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Handler">
|
||||
<summary>
|
||||
经手人
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.IsEnable">
|
||||
<summary>
|
||||
启用
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Memos">
|
||||
<summary>
|
||||
备注
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.User.Roles">
|
||||
<summary>
|
||||
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:EMSServerModel.Model.Sex">
|
||||
<summary>
|
||||
性别枚举
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:EMSServerModel.Model.Sex.女">
|
||||
<summary>
|
||||
女=0
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:EMSServerModel.Model.Sex.男">
|
||||
<summary>
|
||||
男=1
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:EMSServerModel.Model.UserRole">
|
||||
<summary>
|
||||
用户角色关系表aa111
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.UserRole.RoleId">
|
||||
<summary>
|
||||
角色编号1
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.UserRole.Roles">
|
||||
<summary>
|
||||
角色导航
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.UserRole.UserId">
|
||||
<summary>
|
||||
用户编号
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:EMSServerModel.Model.UserRole.Users">
|
||||
<summary>
|
||||
用户导航
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
126
Examples/base_entity/readme.md
Normal file
@ -0,0 +1,126 @@
|
||||
# 前言
|
||||
|
||||
尝试过 ado.net、dapper、ef,以及Repository仓储,甚至自己还写过生成器工具,以便做常规CRUD操作。
|
||||
|
||||
它们日常操作不方便之处:
|
||||
|
||||
- 每次使用前需要声明,再操作;
|
||||
|
||||
- 很多人一个实体类,对应一个操作类(或DAL、DbContext、Repository);
|
||||
|
||||
BaseEntity 是一种极简单的 CodeFirst 开发方式,特别对单表或多表CRUD,利用继承节省了每个实体类的重复属性(创建时间、ID等字段),软件删除等功能,进行 crud 操作时不必时常考虑仓储的使用;
|
||||
|
||||
本文介绍 BaseEntity 一种极简约的 CRUD 操作方法。
|
||||
|
||||
# 功能特点
|
||||
|
||||
- 自动迁移实体结构(CodeFirst),到数据库;
|
||||
|
||||
- 直接操作实体的方法,进行 CRUD 操作;
|
||||
|
||||
- 简化用户定义实体类型,省去主键、常用字段的配置(如CreateTime、UpdateTime);
|
||||
|
||||
- 实现单表、多表查询的软删除逻辑;
|
||||
|
||||
# 声明
|
||||
|
||||
> dotnet add package FreeSql.Extensions.BaseEntity
|
||||
|
||||
> dotnet add package FreeSql.Provider.Sqlite
|
||||
|
||||
1、定义一个主键 int 并且自增的实体类型,BaseEntity TKey 指定为 int/long 时,会认为主键是自增;
|
||||
|
||||
```csharp
|
||||
public class UserGroup : BaseEntity<UserGroup, int>
|
||||
{
|
||||
public string GroupName { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
如果不想主键是自增键,可以重写属性:
|
||||
|
||||
```csharp
|
||||
public class UserGroup : BaseEntity<UserGroup, int>
|
||||
{
|
||||
[Column(IsIdentity = false)]
|
||||
public override int Id { get; set; }
|
||||
public string GroupName { get; set; }
|
||||
}
|
||||
```
|
||||
> 有关更多实体的特性配置,请参考资料:https://github.com/2881099/FreeSql/wiki/%e5%ae%9e%e4%bd%93%e7%89%b9%e6%80%a7
|
||||
|
||||
2、定义一个主键 Guid 的实体类型,保存数据时会自动产生有序不重复的 Guid 值(不用自己指定 Guid.NewGuid());
|
||||
|
||||
```csharp
|
||||
public class User : BaseEntity<UserGroup, Guid>
|
||||
{
|
||||
public string UserName { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
# CRUD 使用
|
||||
|
||||
```csharp
|
||||
//添加
|
||||
var item = new UserGroup { GroupName = "组一" };
|
||||
item.Insert();
|
||||
|
||||
//更新
|
||||
item.GroupName = "组二";
|
||||
item.Update();
|
||||
|
||||
//添加或更新
|
||||
item.Save();
|
||||
|
||||
//软删除
|
||||
item.Delete();
|
||||
|
||||
//恢复软删除
|
||||
item.Restore();
|
||||
|
||||
//根据主键获取对象
|
||||
var item = UserGroup.Find(1);
|
||||
|
||||
//查询数据
|
||||
var items = UserGroup.Where(a => a.Id > 10).ToList();
|
||||
```
|
||||
|
||||
实体类型.Select 是一个查询对象,使用方法和 FreeSql.ISelect 一样;
|
||||
|
||||
支持多表查询时,软删除条件会附加在每个表中;
|
||||
|
||||
> 有关更多查询方法,请参考资料:https://github.com/2881099/FreeSql/wiki/%e6%9f%a5%e8%af%a2
|
||||
|
||||
# 事务建议
|
||||
|
||||
由于 AsyncLocal 平台兼容不好,所以交给外部管理事务。
|
||||
|
||||
```csharp
|
||||
static AsyncLocal<IUnitOfWork> _asyncUow = new AsyncLocal<IUnitOfWork>();
|
||||
|
||||
BaseEntity.Initialization(fsql, () => _asyncUow.Value);
|
||||
```
|
||||
|
||||
在 Scoped 开始时: _asyncUow.Value = fsql.CreateUnitOfWork(); (也可以使用 UnitOfWorkManager 对象获取 uow)
|
||||
|
||||
在 Scoped 结束时:_asyncUow.Value = null;
|
||||
|
||||
如下:
|
||||
|
||||
```csharp
|
||||
using (var uow = fsql.CreateUnitOfWork())
|
||||
{
|
||||
_asyncUow.Value = uow;
|
||||
|
||||
try
|
||||
{
|
||||
//todo ... BaseEntity 内部 curd 方法保持使用 uow 事务
|
||||
}
|
||||
finally
|
||||
{
|
||||
_asyncUow.Value = null;
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
```
|
@ -8,17 +8,21 @@ using BenchmarkDotNet.Running;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
//using SqlSugar;
|
||||
|
||||
namespace FreeSql.Bechmarker {
|
||||
namespace FreeSql.Bechmarker
|
||||
{
|
||||
|
||||
public class Program {
|
||||
public static void Main(string[] args) {
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var summaryInsert = BenchmarkRunner.Run<OrmVsInsert>();
|
||||
var summarySelect = BenchmarkRunner.Run<OrmVsSelect>();
|
||||
var summaryUpdate = BenchmarkRunner.Run<OrmVsUpdate>();
|
||||
}
|
||||
}
|
||||
|
||||
public class Orm {
|
||||
public class Orm
|
||||
{
|
||||
public static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=20")
|
||||
//.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=20")
|
||||
@ -39,24 +43,27 @@ namespace FreeSql.Bechmarker {
|
||||
// });
|
||||
//}
|
||||
}
|
||||
class SongContext : DbContext {
|
||||
class SongContext : DbContext
|
||||
{
|
||||
public DbSet<Song> Songs { get; set; }
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
optionsBuilder.UseSqlServer(@"Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=21;Max Pool Size=21");
|
||||
//optionsBuilder.UseMySql("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=21;Max Pool Size=21");
|
||||
}
|
||||
}
|
||||
|
||||
[CoreJob]
|
||||
[RPlotExporter, RankColumn]
|
||||
public class OrmVsInsert {
|
||||
public class OrmVsInsert
|
||||
{
|
||||
public IEnumerable<Song> songs;
|
||||
|
||||
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
||||
public int size;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup() {
|
||||
public void Setup()
|
||||
{
|
||||
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||
//Orm.sugar.CodeFirst.InitTables(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||
//sugar创建表失败:SqlSugar.SqlSugarException: Sequence contains no elements
|
||||
@ -66,7 +73,8 @@ namespace FreeSql.Bechmarker {
|
||||
//Orm.sugar.Deleteable<Song>().Where(a => a.Id > 0).ExecuteCommand();
|
||||
Orm.fsql.Ado.ExecuteNonQuery("delete from efcore_song");
|
||||
|
||||
songs = Enumerable.Range(0, size).Select(a => new Song {
|
||||
songs = Enumerable.Range(0, size).Select(a => new Song
|
||||
{
|
||||
Create_time = DateTime.Now,
|
||||
Is_deleted = false,
|
||||
Title = $"Insert_{a}",
|
||||
@ -76,7 +84,8 @@ namespace FreeSql.Bechmarker {
|
||||
//预热
|
||||
Orm.fsql.Insert(songs.First()).ExecuteAffrows();
|
||||
//Orm.sugar.Insertable(songs.First()).ExecuteCommand();
|
||||
using (var db = new SongContext()) {
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||
db.Songs.AddRange(songs.First());
|
||||
db.SaveChanges();
|
||||
@ -90,8 +99,10 @@ namespace FreeSql.Bechmarker {
|
||||
//public int SqlSugarInsert() => Orm.sugar.Insertable(songs.ToArray()).ExecuteCommand();
|
||||
|
||||
[Benchmark]
|
||||
public int EfCoreInsert() {
|
||||
using (var db = new SongContext()) {
|
||||
public int EfCoreInsert()
|
||||
{
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||
db.Songs.AddRange(songs.ToArray());
|
||||
return db.SaveChanges();
|
||||
@ -99,16 +110,17 @@ namespace FreeSql.Bechmarker {
|
||||
}
|
||||
}
|
||||
|
||||
[CoreJob]
|
||||
[RPlotExporter, RankColumn]
|
||||
public class OrmVsUpdate {
|
||||
public class OrmVsUpdate
|
||||
{
|
||||
public List<Song> songs;
|
||||
|
||||
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
||||
public int size;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup() {
|
||||
public void Setup()
|
||||
{
|
||||
songs = Orm.fsql.Select<Song>().Limit(size).ToList();
|
||||
}
|
||||
|
||||
@ -119,8 +131,10 @@ namespace FreeSql.Bechmarker {
|
||||
//public int SqlSugarUpdate() => Orm.sugar.Updateable(songs).ExecuteCommand();
|
||||
|
||||
[Benchmark]
|
||||
public int EfCoreUpdate() {
|
||||
using (var db = new SongContext()) {
|
||||
public int EfCoreUpdate()
|
||||
{
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||
db.Songs.UpdateRange(songs.ToArray());
|
||||
return db.SaveChanges();
|
||||
@ -128,15 +142,16 @@ namespace FreeSql.Bechmarker {
|
||||
}
|
||||
}
|
||||
|
||||
[CoreJob]
|
||||
[RPlotExporter, RankColumn]
|
||||
public class OrmVsSelect {
|
||||
public class OrmVsSelect
|
||||
{
|
||||
|
||||
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
||||
public int size;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup() {
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -147,8 +162,10 @@ namespace FreeSql.Bechmarker {
|
||||
//public List<Song> SqlSugarSelect() => Orm.sugar.Queryable<Song>().Take(size).ToList();
|
||||
|
||||
[Benchmark]
|
||||
public List<Song> EfCoreSelect() {
|
||||
using (var db = new SongContext()) {
|
||||
public List<Song> EfCoreSelect()
|
||||
{
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
return db.Songs.Take(size).AsNoTracking().ToList();
|
||||
}
|
||||
}
|
||||
@ -157,7 +174,8 @@ namespace FreeSql.Bechmarker {
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song")]
|
||||
//[SugarTable("sugar_song")]
|
||||
[Table("efcore_song")]
|
||||
public class Song {
|
||||
public class Song
|
||||
{
|
||||
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
||||
//[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
[Key]
|
||||
@ -175,7 +193,8 @@ namespace FreeSql.Bechmarker {
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song_tag")]
|
||||
//[SugarTable("sugar_song_tag")]
|
||||
[Table("efcore_song_tag")]
|
||||
public class Song_tag {
|
||||
public class Song_tag
|
||||
{
|
||||
public int Song_id { get; set; }
|
||||
//[SugarColumn(IsIgnore = true)]
|
||||
[NotMapped]
|
||||
@ -189,7 +208,8 @@ namespace FreeSql.Bechmarker {
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_tag")]
|
||||
//[SugarTable("sugar_tag")]
|
||||
[Table("efcore_tag")]
|
||||
public class Tag {
|
||||
public class Tag
|
||||
{
|
||||
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
||||
//[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
[Key]
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.4" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.0-rc1.final" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
12
Examples/dbcontext_01/.config/dotnet-tools.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "5.0.0",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
250
Examples/dbcontext_01/Controllers/ValuesController.cs
Normal file
@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FreeSql;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace dbcontext_01.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class ValuesController : ControllerBase
|
||||
{
|
||||
|
||||
IFreeSql _orm;
|
||||
SongContext _songContext;
|
||||
CurdAfterLog _curdLog;
|
||||
public ValuesController(SongContext songContext, IFreeSql orm1, CurdAfterLog curdLog)
|
||||
{
|
||||
_songContext = songContext;
|
||||
_orm = orm1;
|
||||
_curdLog = curdLog;
|
||||
|
||||
}
|
||||
|
||||
// GET api/values
|
||||
[HttpGet]
|
||||
async public Task<string> Get()
|
||||
{
|
||||
_orm.SetDbContextOptions(opt => {
|
||||
opt.OnEntityChange = changeReport => {
|
||||
Console.WriteLine(changeReport);
|
||||
};
|
||||
});
|
||||
|
||||
long id = 0;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var repos2Song = _orm.GetRepository<Song, int>();
|
||||
repos2Song.Where(a => a.Id > 10).ToList();
|
||||
//查询结果,进入 states
|
||||
|
||||
var song = new Song { Title = "empty" };
|
||||
repos2Song.Insert(song);
|
||||
song.Title = "empty01";
|
||||
repos2Song.Update(song);
|
||||
id = song.Id;
|
||||
|
||||
var adds = Enumerable.Range(0, 100)
|
||||
.Select(a => new Song { CreateTime = DateTime.Now, Title = "xxxx" + a, Url = "url222" })
|
||||
.ToList();
|
||||
//创建一堆无主键值
|
||||
|
||||
repos2Song.Insert(adds);
|
||||
|
||||
for (var a = 0; a < 10; a++)
|
||||
adds[a].Title = "dkdkdkdk" + a;
|
||||
|
||||
repos2Song.Update(adds);
|
||||
//批量修改
|
||||
|
||||
repos2Song.Delete(adds.Skip(10).Take(20).ToList());
|
||||
//批量删除,10-20 元素的主键值会被清除
|
||||
|
||||
adds.Last().Url = "skldfjlksdjglkjjcccc";
|
||||
repos2Song.Update(adds.Last());
|
||||
|
||||
adds.First().Url = "skldfjlksdjglkjjcccc";
|
||||
repos2Song.Update(adds.First());
|
||||
|
||||
|
||||
var ctx = _songContext;
|
||||
var tag = new Tag
|
||||
{
|
||||
Name = "testaddsublist"
|
||||
};
|
||||
ctx.Tags.Add(tag);
|
||||
|
||||
|
||||
ctx.UnitOfWork.GetOrBeginTransaction();
|
||||
|
||||
var tagAsync = new Tag
|
||||
{
|
||||
Name = "testaddsublist"
|
||||
};
|
||||
await ctx.Tags.AddAsync(tagAsync);
|
||||
|
||||
|
||||
ctx.Songs.Select.Where(a => a.Id > 10).ToList();
|
||||
//查询结果,进入 states
|
||||
|
||||
song = new Song { Title = "empty" };
|
||||
//可插入的 song
|
||||
|
||||
ctx.Songs.Add(song);
|
||||
id = song.Id;
|
||||
//因有自增类型,立即开启事务执行SQL,返回自增值
|
||||
|
||||
adds = Enumerable.Range(0, 100)
|
||||
.Select(a => new Song { CreateTime = DateTime.Now, Title = "xxxx" + a, Url = "url222" })
|
||||
.ToList();
|
||||
//创建一堆无主键值
|
||||
|
||||
ctx.Songs.AddRange(adds);
|
||||
//立即执行,将自增值赋给 adds 所有元素,因为有自增类型,如果其他类型,指定传入主键值,不会立即执行
|
||||
|
||||
for (var a = 0; a < 10; a++)
|
||||
adds[a].Title = "dkdkdkdk" + a;
|
||||
|
||||
ctx.Songs.UpdateRange(adds);
|
||||
//批量修改,进入队列
|
||||
|
||||
ctx.Songs.RemoveRange(adds.Skip(10).Take(20).ToList());
|
||||
//批量删除,进入队列,完成时 10-20 元素的主键值会被清除
|
||||
|
||||
//ctx.Songs.Update(adds.First());
|
||||
|
||||
adds.Last().Url = "skldfjlksdjglkjjcccc";
|
||||
ctx.Songs.Update(adds.Last());
|
||||
|
||||
adds.First().Url = "skldfjlksdjglkjjcccc";
|
||||
ctx.Songs.Update(adds.First());
|
||||
|
||||
//单条修改 urls 的值,进入队列
|
||||
|
||||
//throw new Exception("回滚");
|
||||
|
||||
//ctx.Songs.Select.First();
|
||||
//这里做一个查询,会立即打包【执行队列】,避免没有提交的数据,影响查询结果
|
||||
|
||||
ctx.SaveChanges();
|
||||
//打包【执行队列】,提交事务
|
||||
|
||||
|
||||
using (var uow = _orm.CreateUnitOfWork())
|
||||
{
|
||||
|
||||
var reposSong = uow.GetRepository<Song, int>();
|
||||
reposSong.Where(a => a.Id > 10).ToList();
|
||||
//查询结果,进入 states
|
||||
|
||||
song = new Song { Title = "empty" };
|
||||
reposSong.Insert(song);
|
||||
id = song.Id;
|
||||
|
||||
adds = Enumerable.Range(0, 100)
|
||||
.Select(a => new Song { CreateTime = DateTime.Now, Title = "xxxx" + a, Url = "url222" })
|
||||
.ToList();
|
||||
//创建一堆无主键值
|
||||
|
||||
reposSong.Insert(adds);
|
||||
|
||||
for (var a = 0; a < 10; a++)
|
||||
adds[a].Title = "dkdkdkdk" + a;
|
||||
|
||||
reposSong.Update(adds);
|
||||
//批量修改
|
||||
|
||||
reposSong.Delete(adds.Skip(10).Take(20).ToList());
|
||||
//批量删除,10-20 元素的主键值会被清除
|
||||
|
||||
adds.Last().Url = "skldfjlksdjglkjjcccc";
|
||||
reposSong.Update(adds.Last());
|
||||
|
||||
adds.First().Url = "skldfjlksdjglkjjcccc";
|
||||
reposSong.Update(adds.First());
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
using (ctx = new SongContext())
|
||||
{
|
||||
|
||||
song = new Song { Title = "empty" };
|
||||
await ctx.Songs.AddAsync(song);
|
||||
id = song.Id;
|
||||
|
||||
adds = Enumerable.Range(0, 100)
|
||||
.Select(a => new Song { CreateTime = DateTime.Now, Title = "xxxx" + a, Url = "url222" })
|
||||
.ToList();
|
||||
await ctx.Songs.AddRangeAsync(adds);
|
||||
|
||||
for (var a = 0; a < adds.Count; a++)
|
||||
adds[a].Title = "dkdkdkdk" + a;
|
||||
|
||||
ctx.Songs.UpdateRange(adds);
|
||||
|
||||
ctx.Songs.RemoveRange(adds.Skip(10).Take(20).ToList());
|
||||
|
||||
//ctx.Songs.Update(adds.First());
|
||||
|
||||
adds.Last().Url = "skldfjlksdjglkjjcccc";
|
||||
ctx.Songs.Update(adds.Last());
|
||||
|
||||
//throw new Exception("回滚");
|
||||
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
var item = await _orm.Select<Song>().Where(a => a.Id == id).FirstAsync();
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
var item22 = await _orm.Select<Song>().Where(a => a.Id == id).FirstAsync();
|
||||
var item33 = await _orm.Select<Song>().Where(a => a.Id > id).ToListAsync();
|
||||
|
||||
return item22.Id.ToString() + "\r\n\r\n" + _curdLog.Sb.ToString();
|
||||
}
|
||||
|
||||
// GET api/values/5
|
||||
[HttpGet("{id}")]
|
||||
public ActionResult<object> Get(int id)
|
||||
{
|
||||
return _orm.Select<Song>().Where(a => a.Id == id).First();
|
||||
}
|
||||
|
||||
[HttpGet("get{id}")]
|
||||
public ActionResult<string> Get2(int id)
|
||||
{
|
||||
var item1 = _orm.Select<Song>().Where(a => a.Id == id).First();
|
||||
var item2 = _orm.Select<Song>().Where(a => a.Id == id).First();
|
||||
return _curdLog.Sb.ToString();
|
||||
}
|
||||
|
||||
// POST api/values
|
||||
[HttpPost]
|
||||
public void Post([FromBody] string value)
|
||||
{
|
||||
}
|
||||
|
||||
// PUT api/values/5
|
||||
[HttpPut("{id}")]
|
||||
public void Put(int id, [FromBody] string value)
|
||||
{
|
||||
}
|
||||
|
||||
// DELETE api/values/5
|
||||
[HttpDelete("{id}")]
|
||||
public void Delete(int id)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
113
Examples/dbcontext_01/DbContexts/SongContext.cs
Normal file
@ -0,0 +1,113 @@
|
||||
using FreeSql;
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace dbcontext_01
|
||||
{
|
||||
public class SongContext : DbContext
|
||||
{
|
||||
public DbSet<Song> Songs { get; set; }
|
||||
public DbSet<Tag> Tags { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder builder)
|
||||
{
|
||||
builder.UseFreeSql(Startup.Fsql);
|
||||
//这里直接指定一个静态的 IFreeSql 对象即可,切勿重新 Build()
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ICodeFirst codefirst)
|
||||
{
|
||||
codefirst.Entity<Song>(eb =>
|
||||
{
|
||||
eb.ToTable("tb_song");
|
||||
eb.Ignore(a => a.Field1);
|
||||
eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired();
|
||||
eb.Property(a => a.Url).HasMaxLength(100);
|
||||
|
||||
eb.Property(a => a.RowVersion).IsRowVersion();
|
||||
eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp");
|
||||
|
||||
eb.HasKey(a => a.Id);
|
||||
eb.HasIndex(a => new { a.Id, a.Title }).IsUnique().HasName("idx_xxx11");
|
||||
|
||||
//一对多、多对一
|
||||
eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs);
|
||||
|
||||
//多对多
|
||||
eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag));
|
||||
});
|
||||
|
||||
codefirst.Entity<SongType>(eb =>
|
||||
{
|
||||
eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId);
|
||||
|
||||
eb.HasData(new[]
|
||||
{
|
||||
new SongType
|
||||
{
|
||||
Id = 1,
|
||||
Name = "流行",
|
||||
Songs = new List<Song>(new[]
|
||||
{
|
||||
new Song{ Title = "真的爱你" },
|
||||
new Song{ Title = "爱你一万年" },
|
||||
})
|
||||
},
|
||||
new SongType
|
||||
{
|
||||
Id = 2,
|
||||
Name = "乡村",
|
||||
Songs = new List<Song>(new[]
|
||||
{
|
||||
new Song{ Title = "乡里乡亲" },
|
||||
})
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
codefirst.SyncStructure<SongType>();
|
||||
codefirst.SyncStructure<Song>();
|
||||
}
|
||||
}
|
||||
|
||||
public class SongType
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<Song> Songs { get; set; }
|
||||
}
|
||||
public class Song
|
||||
{
|
||||
[Column(IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Url { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public int TypeId { get; set; }
|
||||
public SongType Type { get; set; }
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
public int Field1 { get; set; }
|
||||
public long RowVersion { get; set; }
|
||||
}
|
||||
public class Song_tag
|
||||
{
|
||||
public int Song_id { get; set; }
|
||||
public Song Song { get; set; }
|
||||
|
||||
public int Tag_id { get; set; }
|
||||
public Tag Tag { get; set; }
|
||||
}
|
||||
public class Tag
|
||||
{
|
||||
[Column(IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<Song> Songs { get; set; }
|
||||
}
|
||||
}
|
28
Examples/dbcontext_01/Program.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using FreeSql;
|
||||
using FreeSql.DataAnnotations;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace dbcontext_01
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<DeleteExistingFiles>True</DeleteExistingFiles>
|
||||
<ExcludeApp_Data>False</ExcludeApp_Data>
|
||||
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||
<PublishProvider>FileSystem</PublishProvider>
|
||||
<PublishUrl>bin\Release\net5.0\publish\</PublishUrl>
|
||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<ProjectGuid>690f89e0-a721-423f-8f5d-d262f73235ea</ProjectGuid>
|
||||
<SelfContained>true</SelfContained>
|
||||
<PublishSingleFile>True</PublishSingleFile>
|
||||
</PropertyGroup>
|
||||
</Project>
|
27
Examples/dbcontext_01/Properties/launchSettings.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:53030/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"dbcontext_01": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:53031/"
|
||||
}
|
||||
}
|
||||
}
|
84
Examples/dbcontext_01/Startup.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using FreeSql;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace dbcontext_01
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
|
||||
{
|
||||
Configuration = configuration;
|
||||
|
||||
Fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document2.db;Pooling=true;Max Pool Size=10")
|
||||
//.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=10")
|
||||
//.UseConnectionString(DataType.MySql, "Data Source=192.168.164.10;Port=33061;User ID=root;Password=123456;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=5")
|
||||
//.UseSlave("Data Source=192.168.164.10;Port=33062;User ID=root;Password=123456;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=5")
|
||||
//.UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=10")
|
||||
//.UseSyncStructureToUpper(true)
|
||||
.UseAutoSyncStructure(true)
|
||||
.UseLazyLoading(true)
|
||||
.UseNoneCommandParameter(true)
|
||||
.UseMonitorCommand(cmd => { }, (cmd, log) => Trace.WriteLine(log))
|
||||
.Build();
|
||||
|
||||
Fsql.Aop.CurdAfter += (s, e) =>
|
||||
{
|
||||
Console.WriteLine(e.Identifier + ": " + e.EntityType.FullName + " " + e.ElapsedMilliseconds + "ms, " + e.Sql);
|
||||
CurdAfterLog.Current.Value?.Sb.AppendLine($"{Thread.CurrentThread.ManagedThreadId}: {e.EntityType.FullName} {e.ElapsedMilliseconds}ms, {e.Sql}");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
enum MySql { }
|
||||
enum PgSql { }
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
public static IFreeSql Fsql { get; private set; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllersWithViews();
|
||||
|
||||
services.AddSingleton<IFreeSql>(Fsql);
|
||||
services.AddFreeDbContext<SongContext>(options => options.UseFreeSql(Fsql));
|
||||
services.AddScoped<CurdAfterLog>();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
||||
Console.InputEncoding = Encoding.GetEncoding("GB2312");
|
||||
|
||||
app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(a => a.MapControllers());
|
||||
}
|
||||
}
|
||||
|
||||
public class CurdAfterLog : IDisposable
|
||||
{
|
||||
public static AsyncLocal<CurdAfterLog> Current = new AsyncLocal<CurdAfterLog>();
|
||||
public StringBuilder Sb { get; } = new StringBuilder();
|
||||
|
||||
public CurdAfterLog()
|
||||
{
|
||||
Current.Value = this;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
Sb.Clear();
|
||||
Current.Value = null;
|
||||
}
|
||||
}
|
||||
}
|
9
Examples/dbcontext_01/appsettings.Development.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
}
|
8
Examples/dbcontext_01/appsettings.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
25
Examples/dbcontext_01/dbcontext_01.csproj
Normal file
@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>dbcontext_01.xml</DocumentationFile>
|
||||
<WarningLevel>3</WarningLevel>
|
||||
<NoWarn>1701;1702;1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Extensions\FreeSql.Extensions.LazyLoading\FreeSql.Extensions.LazyLoading.csproj" />
|
||||
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.MySqlConnector\FreeSql.Provider.MySqlConnector.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
8
Examples/dbcontext_01/dbcontext_01.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>dbcontext_01</name>
|
||||
</assembly>
|
||||
<members>
|
||||
</members>
|
||||
</doc>
|
@ -2,17 +2,21 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
|
||||
namespace efcore_to_freesql.DBContexts {
|
||||
namespace efcore_to_freesql.DBContexts
|
||||
{
|
||||
|
||||
public class BaseDBContext : DbContext {
|
||||
public class BaseDBContext : DbContext
|
||||
{
|
||||
|
||||
public static IFreeSql Fsql { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
Fsql.CodeFirst.ConfigEntity(modelBuilder.Model); //ͬ²½ÅäÖÃ
|
||||
}
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
optionsBuilder.UseSqlite(@"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10");
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
using efcore_to_freesql.Entitys;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace efcore_to_freesql.DBContexts {
|
||||
namespace efcore_to_freesql.DBContexts
|
||||
{
|
||||
|
||||
public class Topic1Context : BaseDBContext {
|
||||
public class Topic1Context : BaseDBContext
|
||||
{
|
||||
|
||||
public DbSet<Topic1> Topic1s { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
||||
modelBuilder.Entity<Topic1>().ToTable("topic1_sss").HasKey(a => a.Id);
|
||||
modelBuilder.Entity<Topic1>().Property(a => a.Id).HasColumnName("topic1_id").ValueGeneratedOnAdd();
|
||||
|
@ -1,13 +1,16 @@
|
||||
using efcore_to_freesql.Entitys;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace efcore_to_freesql.DBContexts {
|
||||
namespace efcore_to_freesql.DBContexts
|
||||
{
|
||||
|
||||
public class Topic2Context : BaseDBContext {
|
||||
public class Topic2Context : BaseDBContext
|
||||
{
|
||||
|
||||
public DbSet<Topic2> Topic2s { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
||||
modelBuilder.Entity<Topic2>().ToTable("topic2_sss");
|
||||
modelBuilder.Entity<Topic2>().Property(a => a.Id).HasColumnName("topic2_id");
|
||||
|
48
Examples/efcore_to_freesql/Entitys/Song.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace efcore_to_freesql.Entitys
|
||||
{
|
||||
public class SongType
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<Song> Songs { get; set; }
|
||||
}
|
||||
|
||||
public class Song
|
||||
{
|
||||
[Column(IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Url { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public int TypeId { get; set; }
|
||||
public SongType Type { get; set; }
|
||||
public List<Tag> Tags { get; set; }
|
||||
|
||||
public int Field1 { get; set; }
|
||||
public long RowVersion { get; set; }
|
||||
}
|
||||
public class Song_tag
|
||||
{
|
||||
public int Song_id { get; set; }
|
||||
public Song Song { get; set; }
|
||||
|
||||
public int Tag_id { get; set; }
|
||||
public Tag Tag { get; set; }
|
||||
}
|
||||
|
||||
public class Tag
|
||||
{
|
||||
[Column(IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public List<Song> Songs { get; set; }
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace efcore_to_freesql.Entitys {
|
||||
namespace efcore_to_freesql.Entitys
|
||||
{
|
||||
|
||||
public class Topic1
|
||||
{
|
||||
|
@ -2,7 +2,8 @@ using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace efcore_to_freesql.Entitys {
|
||||
namespace efcore_to_freesql.Entitys
|
||||
{
|
||||
|
||||
public class Topic2
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using FreeSql;
|
||||
using efcore_to_freesql.Entitys;
|
||||
using FreeSql;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using System;
|
||||
@ -6,20 +7,25 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class CodeFirstExtensions {
|
||||
public static class CodeFirstExtensions
|
||||
{
|
||||
|
||||
public static void ConfigEntity(this ICodeFirst codeFirst, IModel efmodel) {
|
||||
public static void ConfigEntity(this ICodeFirst codeFirst, IModel efmodel)
|
||||
{
|
||||
|
||||
foreach (var type in efmodel.GetEntityTypes()) {
|
||||
foreach (var type in efmodel.GetEntityTypes())
|
||||
{
|
||||
|
||||
codeFirst.ConfigEntity(type.ClrType, a => {
|
||||
codeFirst.ConfigEntity(type.ClrType, a =>
|
||||
{
|
||||
|
||||
//表名
|
||||
var relationalTableName = type.FindAnnotation("Relational:TableName");
|
||||
if (relationalTableName != null)
|
||||
a.Name(relationalTableName.Value?.ToString() ?? type.ClrType.Name);
|
||||
|
||||
foreach (var prop in type.GetProperties()) {
|
||||
foreach (var prop in type.GetProperties())
|
||||
{
|
||||
|
||||
var freeProp = a.Property(prop.Name);
|
||||
|
||||
@ -42,14 +48,16 @@ public static class CodeFirstExtensions {
|
||||
);
|
||||
|
||||
//可空
|
||||
freeProp.IsNullable(prop.AfterSaveBehavior != PropertySaveBehavior.Throw);
|
||||
freeProp.IsNullable(prop.GetAfterSaveBehavior() != PropertySaveBehavior.Throw);
|
||||
|
||||
//类型
|
||||
var relationalColumnType = prop.FindAnnotation("Relational:ColumnType");
|
||||
if (relationalColumnType != null) {
|
||||
if (relationalColumnType != null)
|
||||
{
|
||||
|
||||
var dbType = relationalColumnType.ToString();
|
||||
if (!string.IsNullOrEmpty(dbType)) {
|
||||
if (!string.IsNullOrEmpty(dbType))
|
||||
{
|
||||
|
||||
var maxLength = prop.FindAnnotation("MaxLength");
|
||||
if (maxLength != null)
|
||||
@ -62,4 +70,112 @@ public static class CodeFirstExtensions {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void EfCoreFluentApiTestGeneric(this ICodeFirst cf)
|
||||
{
|
||||
cf.Entity<Song>(eb =>
|
||||
{
|
||||
eb.ToTable("tb_song1");
|
||||
eb.Ignore(a => a.Field1);
|
||||
eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired();
|
||||
eb.Property(a => a.Url).HasMaxLength(100);
|
||||
|
||||
eb.Property(a => a.RowVersion).IsRowVersion();
|
||||
eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp");
|
||||
|
||||
eb.HasKey(a => a.Id);
|
||||
eb.HasIndex(a => a.Title).IsUnique().HasName("idx_tb_song1111");
|
||||
|
||||
//一对多、多对一
|
||||
eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs);
|
||||
|
||||
//多对多
|
||||
eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag));
|
||||
});
|
||||
cf.Entity<SongType>(eb =>
|
||||
{
|
||||
eb.ToTable("tb_songtype1");
|
||||
eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId);
|
||||
|
||||
eb.HasData(new[]
|
||||
{
|
||||
new SongType
|
||||
{
|
||||
Id = 1,
|
||||
Name = "流行",
|
||||
Songs = new List<Song>(new[]
|
||||
{
|
||||
new Song{ Title = "真的爱你" },
|
||||
new Song{ Title = "爱你一万年" },
|
||||
})
|
||||
},
|
||||
new SongType
|
||||
{
|
||||
Id = 2,
|
||||
Name = "乡村",
|
||||
Songs = new List<Song>(new[]
|
||||
{
|
||||
new Song{ Title = "乡里乡亲" },
|
||||
})
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
cf.SyncStructure<SongType>();
|
||||
cf.SyncStructure<Song>();
|
||||
}
|
||||
|
||||
public static void EfCoreFluentApiTestDynamic(this ICodeFirst cf)
|
||||
{
|
||||
cf.Entity(typeof(Song), eb =>
|
||||
{
|
||||
eb.ToTable("tb_song2");
|
||||
eb.Ignore("Field1");
|
||||
eb.Property("Title").HasColumnType("varchar(50)").IsRequired();
|
||||
eb.Property("Url").HasMaxLength(100);
|
||||
|
||||
eb.Property("RowVersion").IsRowVersion();
|
||||
eb.Property("CreateTime").HasDefaultValueSql("current_timestamp");
|
||||
|
||||
eb.HasKey("Id");
|
||||
eb.HasIndex("Title").IsUnique().HasName("idx_tb_song2222");
|
||||
|
||||
//一对多、多对一
|
||||
eb.HasOne("Type").HasForeignKey("TypeId").WithMany("Songs");
|
||||
|
||||
//多对多
|
||||
eb.HasMany("Tags").WithMany("Songs", typeof(Song_tag));
|
||||
});
|
||||
cf.Entity(typeof(SongType), eb =>
|
||||
{
|
||||
eb.ToTable("tb_songtype2");
|
||||
eb.HasMany("Songs").WithOne("Type").HasForeignKey("TypeId");
|
||||
|
||||
eb.HasData(new[]
|
||||
{
|
||||
new SongType
|
||||
{
|
||||
Id = 1,
|
||||
Name = "流行",
|
||||
Songs = new List<Song>(new[]
|
||||
{
|
||||
new Song{ Title = "真的爱你" },
|
||||
new Song{ Title = "爱你一万年" },
|
||||
})
|
||||
},
|
||||
new SongType
|
||||
{
|
||||
Id = 2,
|
||||
Name = "乡村",
|
||||
Songs = new List<Song>(new[]
|
||||
{
|
||||
new Song{ Title = "乡里乡亲" },
|
||||
})
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
cf.SyncStructure<SongType>();
|
||||
cf.SyncStructure<Song>();
|
||||
}
|
||||
}
|
@ -27,7 +27,10 @@ namespace efcore_to_freesql
|
||||
.UseAutoSyncStructure(true)
|
||||
.Build();
|
||||
|
||||
DBContexts.BaseDBContext.Fsql = Fsql;
|
||||
//Fsql.CodeFirst.EfCoreFluentApiTestGeneric();
|
||||
Fsql.CodeFirst.EfCoreFluentApiTestDynamic();
|
||||
|
||||
BaseDBContext.Fsql = Fsql;
|
||||
|
||||
var sql11 = Fsql.Select<Topic1>().ToSql();
|
||||
//SELECT a."Id", a."Title", a."CreateTime" FROM "Topic1" a
|
||||
@ -39,10 +42,12 @@ namespace efcore_to_freesql
|
||||
var sql22 = Fsql.Insert<Topic2>().AppendData(new Topic2()).ToSql();
|
||||
//INSERT INTO "Topic2"("Id", "Title", "CreateTime") VALUES(@Id0, @Title0, @CreateTime0)
|
||||
|
||||
using (var db = new Topic1Context()) {
|
||||
using (var db = new Topic1Context())
|
||||
{
|
||||
db.Topic1s.Add(new Topic1());
|
||||
}
|
||||
using (var db = new Topic2Context()) {
|
||||
using (var db = new Topic2Context())
|
||||
{
|
||||
db.Topic2s.Add(new Topic2());
|
||||
}
|
||||
|
||||
@ -62,17 +67,21 @@ namespace efcore_to_freesql
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllersWithViews();
|
||||
services.AddSingleton<IFreeSql>(Fsql);
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||
loggerFactory.AddDebug();
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
||||
Console.InputEncoding = Encoding.GetEncoding("GB2312");
|
||||
|
||||
app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseMvc();
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(a => a.MapControllers());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
|
||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,11 +1,14 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using FreeSql.Internal;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -15,50 +18,387 @@ namespace orm_vs
|
||||
class Program
|
||||
{
|
||||
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=20")
|
||||
//.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=20")
|
||||
//.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=20")
|
||||
.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=20")
|
||||
//.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=20")
|
||||
.UseAutoSyncStructure(false)
|
||||
.UseNoneCommandParameter(true)
|
||||
//.UseConfigEntityFromDbFirst(true)
|
||||
.Build();
|
||||
|
||||
static SqlSugarClient sugar {
|
||||
get => new SqlSugarClient(new ConnectionConfig() {
|
||||
//不欺负,让连接池100个最小
|
||||
ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=20;Max Pool Size=20",
|
||||
DbType = DbType.SqlServer,
|
||||
//ConnectionString = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=20;Max Pool Size=20",
|
||||
//DbType = DbType.MySql,
|
||||
static SqlSugarClient sugar
|
||||
{
|
||||
get => new SqlSugarClient(new ConnectionConfig()
|
||||
{
|
||||
//ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=20;Max Pool Size=20",
|
||||
//DbType = DbType.SqlServer,
|
||||
ConnectionString = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=20;Max Pool Size=20",
|
||||
DbType = DbType.MySql,
|
||||
//ConnectionString = "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=21",
|
||||
//DbType = DbType.PostgreSQL,
|
||||
IsAutoCloseConnection = true,
|
||||
InitKeyType = InitKeyType.Attribute
|
||||
});
|
||||
}
|
||||
|
||||
class SongContext : DbContext {
|
||||
class SongContext : DbContext
|
||||
{
|
||||
public DbSet<Song> Songs { get; set; }
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||
optionsBuilder.UseSqlServer(@"Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=21;Max Pool Size=21");
|
||||
//optionsBuilder.UseMySql("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=21;Max Pool Size=21");
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
//optionsBuilder.UseSqlServer(@"Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=21;Max Pool Size=21");
|
||||
optionsBuilder.UseMySql("Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=21;Max Pool Size=21");
|
||||
//optionsBuilder.UseNpgsql("Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=21");
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.Entity<Song>()
|
||||
.Property(a => a.create_time)
|
||||
.HasConversion(a => int.Parse(a.ToString()), a => new DateTime(a));
|
||||
}
|
||||
}
|
||||
|
||||
static void Main(string[] args) {
|
||||
|
||||
fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||
static void Main(string[] args)
|
||||
{
|
||||
//fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||
//sugar.CodeFirst.InitTables(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||
//sugar创建表失败:SqlSugar.SqlSugarException: Sequence contains no elements
|
||||
fsql.CodeFirst.SyncStructure(typeof(Song), "freesql_song");
|
||||
fsql.CodeFirst.SyncStructure(typeof(Song), "sugar_song");
|
||||
fsql.CodeFirst.SyncStructure(typeof(Song), "efcore_song");
|
||||
|
||||
//测试前清空数据
|
||||
fsql.Delete<Song>().Where(a => a.Id > 0).ExecuteAffrows();
|
||||
sugar.Deleteable<Song>().Where(a => a.Id > 0).ExecuteCommand();
|
||||
fsql.Ado.ExecuteNonQuery("delete from efcore_song");
|
||||
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "freesql_song_tag");
|
||||
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "sugar_song_tag");
|
||||
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "efcore_song_tag");
|
||||
|
||||
fsql.CodeFirst.SyncStructure(typeof(Tag), "freesql_tag");
|
||||
fsql.CodeFirst.SyncStructure(typeof(Tag), "sugar_tag");
|
||||
fsql.CodeFirst.SyncStructure(typeof(Tag), "efcore_tag");
|
||||
|
||||
var sb = new StringBuilder();
|
||||
var time = new Stopwatch();
|
||||
|
||||
var sql222 = fsql.Select<Song>().Where(a => DateTime.Now.Subtract(a.create_time.Value).TotalHours > 0).ToSql();
|
||||
|
||||
#region ET test
|
||||
////var t31 = fsql.Select<xxx>().ToList();
|
||||
//fsql.Select<Song>().First();
|
||||
|
||||
//time.Restart();
|
||||
//var t3 = fsql.Select<Song>().ToList();
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*");
|
||||
|
||||
//time.Restart();
|
||||
//var adoarr1 = fsql.Ado.ExecuteArray("select * from freesql_song");
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteArray Entity Counts: {adoarr1.Length}; ORM: FreeSql ExecuteArray*");
|
||||
|
||||
//time.Restart();
|
||||
//var adolist1 = new List<Song>();
|
||||
//fsql.Ado.ExecuteReader(dr =>
|
||||
//{
|
||||
// var xim = new Song();
|
||||
// dr.GetValue(0)?.GetType();
|
||||
// dr.GetValue(1)?.GetType();
|
||||
// dr.GetValue(2)?.GetType();
|
||||
// dr.GetValue(3)?.GetType();
|
||||
// dr.GetValue(4)?.GetType();
|
||||
// adolist1.Add(xim);
|
||||
//}, "select * from freesql_song");
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader*");
|
||||
|
||||
|
||||
//time.Restart();
|
||||
//adolist1 = new List<Song>();
|
||||
//fsql.Ado.ExecuteReader(dr =>
|
||||
//{
|
||||
// var xim = new Song();
|
||||
// var v1 = dr.GetValue(0);
|
||||
// var locvalue = (object)v1;
|
||||
// if (locvalue == null || locvalue == DBNull.Value) xim.Id = default;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is int iv) xim.Id = iv;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is string)
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// v1 = dr.GetValue(1);
|
||||
// locvalue = (object)v1;
|
||||
// if (locvalue == null || locvalue == DBNull.Value) xim.Create_time = default;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is DateTime dt) xim.Create_time = dt;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is string)
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// v1 = dr.GetValue(2);
|
||||
// locvalue = (object)v1;
|
||||
// if (locvalue == null || locvalue == DBNull.Value) xim.Is_deleted = default;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is bool bl) xim.Is_deleted = bl;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is string)
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// v1 = dr.GetValue(3);
|
||||
// locvalue = (object)v1;
|
||||
// if (locvalue == null || locvalue == DBNull.Value) xim.Title = default;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is string str) xim.Title = str;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is string)
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// v1 = dr.GetValue(4);
|
||||
// locvalue = (object)v1;
|
||||
// if (locvalue == null || locvalue == DBNull.Value) xim.Url = default;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is string str) xim.Url = str;
|
||||
// else
|
||||
// {
|
||||
// if (locvalue is string)
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// adolist1.Add(xim);
|
||||
//}, "select * from freesql_song");
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReaderObject Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReaderObject*");
|
||||
|
||||
////var type = typeof(Song);
|
||||
////var myfuncParam1 = Expression.Parameter(typeof(object[]), "values");
|
||||
////var retExp = Expression.Variable(type, "ret");
|
||||
////var objExp = Expression.Variable(typeof(object), "obj");
|
||||
////var returnTarget = Expression.Label(type);
|
||||
////var myfuncBody = Expression.Block(
|
||||
//// new[] { retExp, objExp },
|
||||
//// Expression.Assign(retExp, type.InternalNewExpression()),
|
||||
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(0))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Id").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Id")), Expression.Convert(objExp, type.GetProperty("Id").PropertyType)),
|
||||
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(1))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Create_time").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Create_time")), Expression.Convert(objExp, type.GetProperty("Create_time").PropertyType)),
|
||||
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(2))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Is_deleted").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Is_deleted")), Expression.Convert(objExp, type.GetProperty("Is_deleted").PropertyType)),
|
||||
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(3))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Title").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Title")), Expression.Convert(objExp, type.GetProperty("Title").PropertyType)),
|
||||
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(4))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Url").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Url")), Expression.Convert(objExp, type.GetProperty("Url").PropertyType)),
|
||||
//// Expression.Return(returnTarget, retExp),
|
||||
//// Expression.Label(returnTarget, Expression.Default(type))
|
||||
////);
|
||||
////var myfunc = Expression.Lambda<Func<object[], Song>>(myfuncBody, myfuncParam1).Compile();
|
||||
////time.Restart();
|
||||
////adolist1 = new List<Song>();
|
||||
////fsql.Ado.ExecuteReader(dr =>
|
||||
////{
|
||||
//// var values = new object[dr.FieldCount];
|
||||
//// dr.GetValues(values);
|
||||
//// var xim = myfunc(values);
|
||||
//// adolist1.Add(xim);
|
||||
////}, "select * from freesql_song");
|
||||
////time.Stop();
|
||||
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReaderMyFunc Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReaderMyFunc*");
|
||||
|
||||
|
||||
////var methodDrgv = typeof(DbDataReader).GetMethod("GetValue");
|
||||
////var myfunc2Param1 = Expression.Parameter(typeof(DbDataReader), "dr");
|
||||
////var myfunc2Body = Expression.Block(
|
||||
//// new[] { retExp, objExp },
|
||||
//// Expression.Assign(retExp, type.InternalNewExpression()),
|
||||
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(0))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Id").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Id")), Expression.Convert(objExp, type.GetProperty("Id").PropertyType)),
|
||||
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(1))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Create_time").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Create_time")), Expression.Convert(objExp, type.GetProperty("Create_time").PropertyType)),
|
||||
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(2))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Is_deleted").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Is_deleted")), Expression.Convert(objExp, type.GetProperty("Is_deleted").PropertyType)),
|
||||
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(3))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Title").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Title")), Expression.Convert(objExp, type.GetProperty("Title").PropertyType)),
|
||||
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(4))),
|
||||
//// Utils.GetConvertExpression(type.GetProperty("Url").PropertyType, objExp),
|
||||
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Url")), Expression.Convert(objExp, type.GetProperty("Url").PropertyType)),
|
||||
//// Expression.Return(returnTarget, retExp),
|
||||
//// Expression.Label(returnTarget, Expression.Default(type))
|
||||
////);
|
||||
////var myfunc2 = Expression.Lambda<Func<DbDataReader, Song>>(myfunc2Body, myfunc2Param1).Compile();
|
||||
////time.Restart();
|
||||
////adolist1 = new List<Song>();
|
||||
////fsql.Ado.ExecuteReader(dr =>
|
||||
////{
|
||||
//// var xim = myfunc2(dr);
|
||||
//// adolist1.Add(xim);
|
||||
////}, "select * from freesql_song");
|
||||
////time.Stop();
|
||||
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReaderMyFunc22 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReaderMyFunc22*");
|
||||
|
||||
|
||||
//time.Restart();
|
||||
//adolist1 = new List<Song>();
|
||||
//fsql.Ado.ExecuteReader(dr =>
|
||||
//{
|
||||
// var xim = new Song();
|
||||
// dr.GetFieldValue<int>(0);
|
||||
// dr.GetFieldValue<DateTime>(1);
|
||||
// dr.GetFieldValue<bool>(2);
|
||||
// dr.GetFieldValue<string>(3);
|
||||
// dr.GetFieldValue<string>(4);
|
||||
// adolist1.Add(xim);
|
||||
//}, "select * from freesql_song");
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader0000 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader0000*");
|
||||
|
||||
//time.Restart();
|
||||
//adolist1 = new List<Song>();
|
||||
//fsql.Ado.ExecuteReader(dr =>
|
||||
//{
|
||||
// var xim = new Song();
|
||||
// Utils.GetDataReaderValue(typeof(int), dr.GetValue(0));
|
||||
// Utils.GetDataReaderValue(typeof(DateTime), dr.GetValue(1));
|
||||
// Utils.GetDataReaderValue(typeof(bool), dr.GetValue(2));
|
||||
// Utils.GetDataReaderValue(typeof(string), dr.GetValue(3));
|
||||
// Utils.GetDataReaderValue(typeof(string), dr.GetValue(4));
|
||||
// adolist1.Add(xim);
|
||||
//}, "select * from freesql_song");
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader1111 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader1111*");
|
||||
|
||||
|
||||
////time.Restart();
|
||||
////adolist1 = new List<Song>();
|
||||
////fsql.Ado.ExecuteReader(dr =>
|
||||
////{
|
||||
//// var xim = new Song();
|
||||
//// Utils.GetConvertValue(typeof(int), dr.GetValue(0));
|
||||
//// Utils.GetConvertValue(typeof(DateTime), dr.GetValue(1));
|
||||
//// Utils.GetConvertValue(typeof(bool), dr.GetValue(2));
|
||||
//// Utils.GetConvertValue(typeof(string), dr.GetValue(3));
|
||||
//// Utils.GetConvertValue(typeof(string), dr.GetValue(4));
|
||||
//// adolist1.Add(xim);
|
||||
////}, "select * from freesql_song");
|
||||
////time.Stop();
|
||||
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader11112222 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader11112222*");
|
||||
|
||||
|
||||
//time.Restart();
|
||||
//adolist1 = new List<Song>();
|
||||
//fsql.Ado.ExecuteReader(dr =>
|
||||
//{
|
||||
// var values = new object[dr.FieldCount];
|
||||
// dr.GetValues(values);
|
||||
|
||||
// var xim = new Song();
|
||||
// xim.Id = (int)Utils.GetDataReaderValue(typeof(int), values[0]);
|
||||
// xim.Create_time = (DateTime)Utils.GetDataReaderValue(typeof(DateTime), values[1]);
|
||||
// xim.Is_deleted = (bool)Utils.GetDataReaderValue(typeof(bool), values[2]);
|
||||
// xim.Title = (string)Utils.GetDataReaderValue(typeof(string), values[3]);
|
||||
// xim.Url = (string)Utils.GetDataReaderValue(typeof(string), values[4]);
|
||||
// adolist1.Add(xim);
|
||||
//}, "select * from freesql_song");
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader1111 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader1111*");
|
||||
|
||||
|
||||
////time.Restart();
|
||||
////adolist1 = new List<Song>();
|
||||
////fsql.Ado.ExecuteReader(dr =>
|
||||
////{
|
||||
//// var values = new object[dr.FieldCount];
|
||||
//// dr.GetValues(values);
|
||||
|
||||
//// var xim = new Song();
|
||||
//// xim.Id = (int)Utils.GetConvertValue(typeof(int), values[0]);
|
||||
//// xim.Create_time = (DateTime)Utils.GetConvertValue(typeof(DateTime), values[1]);
|
||||
//// xim.Is_deleted = (bool)Utils.GetConvertValue(typeof(bool), values[2]);
|
||||
//// xim.Title = (string)Utils.GetConvertValue(typeof(string), values[3]);
|
||||
//// xim.Url = (string)Utils.GetConvertValue(typeof(string), values[4]);
|
||||
//// adolist1.Add(xim);
|
||||
////}, "select * from freesql_song");
|
||||
////time.Stop();
|
||||
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader11112222 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader11112222*");
|
||||
|
||||
|
||||
//time.Restart();
|
||||
//List<Song> dplist1 = null;
|
||||
//using (var conn = fsql.Ado.MasterPool.Get())
|
||||
//{
|
||||
// dplist1 = Dapper.SqlMapper.Query<Song>(conn.Value, "select * from freesql_song").ToList();
|
||||
//}
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1.Count}; ORM: Dapper");
|
||||
|
||||
//time.Restart();
|
||||
//t3 = fsql.Select<Song>().ToList();
|
||||
//time.Stop();
|
||||
//sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*");
|
||||
|
||||
//Console.WriteLine(sb.ToString());
|
||||
//Console.ReadKey();
|
||||
|
||||
#endregion
|
||||
|
||||
var testlist1 = fsql.Select<Song>().OrderBy(a => a.id).ToList();
|
||||
var testlist2 = new List<Song>();
|
||||
fsql.Select<Song>().OrderBy(a => a.id).ToChunk(2, fetch =>
|
||||
{
|
||||
testlist2.AddRange(fetch.Object);
|
||||
});
|
||||
|
||||
var testlist22 = new List<object>();
|
||||
fsql.Select<Song, Song_tag>().LeftJoin((a, b) => a.id == b.song_id).ToChunk((a, b) => new { a.title, a.create_time, b.tag_id }, 2, fetch =>
|
||||
{
|
||||
testlist22.AddRange(fetch.Object);
|
||||
});
|
||||
|
||||
//sugar.Aop.OnLogExecuted = (s, e) =>
|
||||
//{
|
||||
// Trace.WriteLine(s);
|
||||
//};
|
||||
//测试前清空数据
|
||||
fsql.Delete<Song>().Where(a => a.id > 0).ExecuteAffrows();
|
||||
sugar.Deleteable<Song>().Where(a => a.id > 0).ExecuteCommand();
|
||||
fsql.Ado.ExecuteNonQuery("delete from efcore_song");
|
||||
|
||||
Console.WriteLine("插入性能:");
|
||||
Insert(sb, 1000, 1);
|
||||
Insert(sb, 100, 1);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Insert(sb, 1000, 10);
|
||||
Insert(sb, 100, 10);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
@ -76,10 +416,10 @@ namespace orm_vs
|
||||
sb.Clear();
|
||||
|
||||
Console.WriteLine("查询性能:");
|
||||
Select(sb, 1000, 1);
|
||||
Select(sb, 100, 1);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Select(sb, 1000, 10);
|
||||
Select(sb, 100, 10);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
@ -97,10 +437,10 @@ namespace orm_vs
|
||||
sb.Clear();
|
||||
|
||||
Console.WriteLine("更新:");
|
||||
Update(sb, 1000, 1);
|
||||
Update(sb, 100, 1);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Update(sb, 1000, 10);
|
||||
Update(sb, 100, 10);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
@ -121,7 +461,8 @@ namespace orm_vs
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
static void Select(StringBuilder sb, int forTime, int size) {
|
||||
static void Select(StringBuilder sb, int forTime, int size)
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++)
|
||||
@ -136,35 +477,50 @@ namespace orm_vs
|
||||
sb.AppendLine($"SqlSugar Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
||||
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++) {
|
||||
using (var db = new SongContext()) {
|
||||
db.Songs.Take(size).AsNoTracking().ToList();
|
||||
for (var a = 0; a < forTime; a++)
|
||||
{
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
//db.Songs.Take(size).AsNoTracking().ToList();
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"EFCore Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms\r\n");
|
||||
sb.AppendLine($"EFCore Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms .net5.0无效");
|
||||
|
||||
sw.Restart();
|
||||
using (var conn = fsql.Ado.MasterPool.Get())
|
||||
{
|
||||
for (var a = 0; a < forTime; a++)
|
||||
Dapper.SqlMapper.Query<Song>(conn.Value, $"select top {size} * from freesql_song").ToList();
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"Dapper Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms\r\n");
|
||||
}
|
||||
|
||||
static void Insert(StringBuilder sb, int forTime, int size) {
|
||||
var songs = Enumerable.Range(0, size).Select(a => new Song {
|
||||
Create_time = DateTime.Now,
|
||||
Is_deleted = false,
|
||||
Title = $"Insert_{a}",
|
||||
Url = $"Url_{a}"
|
||||
static void Insert(StringBuilder sb, int forTime, int size)
|
||||
{
|
||||
var songs = Enumerable.Range(0, size).Select(a => new Song
|
||||
{
|
||||
create_time = DateTime.Now,
|
||||
is_deleted = false,
|
||||
title = $"Insert_{a}",
|
||||
url = $"Url_{a}"
|
||||
});
|
||||
|
||||
//预热
|
||||
fsql.Insert(songs.First()).ExecuteAffrows();
|
||||
sugar.Insertable(songs.First()).ExecuteCommand();
|
||||
using (var db = new SongContext()) {
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||
db.Songs.AddRange(songs.First());
|
||||
db.SaveChanges();
|
||||
//db.Songs.AddRange(songs.First());
|
||||
//db.SaveChanges(); //.net5.0 throw Microsoft.EntityFrameworkCore.DbUpdateException
|
||||
}
|
||||
Stopwatch sw = new Stopwatch();
|
||||
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++) {
|
||||
for (var a = 0; a < forTime; a++)
|
||||
{
|
||||
fsql.Insert(songs).ExecuteAffrows();
|
||||
//using (var db = new FreeSongContext()) {
|
||||
// //db.Configuration.AutoDetectChangesEnabled = false;
|
||||
@ -177,34 +533,41 @@ namespace orm_vs
|
||||
|
||||
sw.Restart();
|
||||
Exception sugarEx = null;
|
||||
try {
|
||||
try
|
||||
{
|
||||
for (var a = 0; a < forTime; a++)
|
||||
sugar.Insertable(songs.ToArray()).ExecuteCommand();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sugarEx = ex;
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"SqlSugar Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms" + (sugarEx != null ? $"成绩无效,错误:{sugarEx.Message}" : ""));
|
||||
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++) {
|
||||
for (var a = 0; a < forTime; a++)
|
||||
{
|
||||
|
||||
using (var db = new SongContext()) {
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||
db.Songs.AddRange(songs.ToArray());
|
||||
db.SaveChanges();
|
||||
//db.Songs.AddRange(songs.ToArray());
|
||||
//db.SaveChanges(); //.net5.0 throw Microsoft.EntityFrameworkCore.DbUpdateException
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"EFCore Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms\r\n");
|
||||
sb.AppendLine($"EFCore Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms .net5.0无效\r\n");
|
||||
}
|
||||
|
||||
static void Update(StringBuilder sb, int forTime, int size) {
|
||||
static void Update(StringBuilder sb, int forTime, int size)
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
|
||||
var songs = fsql.Select<Song>().Limit(size).ToList();
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++) {
|
||||
for (var a = 0; a < forTime; a++)
|
||||
{
|
||||
fsql.Update<Song>().SetSource(songs).ExecuteAffrows();
|
||||
}
|
||||
sw.Stop();
|
||||
@ -213,45 +576,52 @@ namespace orm_vs
|
||||
songs = sugar.Queryable<Song>().Take(size).ToList();
|
||||
sw.Restart();
|
||||
Exception sugarEx = null;
|
||||
try {
|
||||
try
|
||||
{
|
||||
for (var a = 0; a < forTime; a++)
|
||||
sugar.Updateable(songs).ExecuteCommand();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
sugarEx = ex;
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"SqlSugar Update {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms" + (sugarEx != null ? $"成绩无效,错误:{sugarEx.Message}" : ""));
|
||||
|
||||
using (var db = new SongContext()) {
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
songs = db.Songs.Take(size).AsNoTracking().ToList();
|
||||
}
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++) {
|
||||
for (var a = 0; a < forTime; a++)
|
||||
{
|
||||
|
||||
using (var db = new SongContext()) {
|
||||
using (var db = new SongContext())
|
||||
{
|
||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||
db.Songs.UpdateRange(songs.ToArray());
|
||||
db.SaveChanges();
|
||||
//db.Songs.UpdateRange(songs.ToArray());
|
||||
//db.SaveChanges();
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"EFCore Update {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms\r\n");
|
||||
sb.AppendLine($"EFCore Update {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms .net5.0无效\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song")]
|
||||
[SugarTable("sugar_song")]
|
||||
[Table("efcore_song")]
|
||||
public class Song {
|
||||
public class Song
|
||||
{
|
||||
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; set; }
|
||||
public DateTime? Create_time { get; set; }
|
||||
public bool? Is_deleted { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Url { get; set; }
|
||||
public int id { get; set; }
|
||||
public DateTime? create_time { get; set; }
|
||||
public bool? is_deleted { get; set; }
|
||||
public string title { get; set; }
|
||||
public string url { get; set; }
|
||||
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
[NotMapped]
|
||||
@ -260,13 +630,14 @@ namespace orm_vs
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song_tag")]
|
||||
[SugarTable("sugar_song_tag")]
|
||||
[Table("efcore_song_tag")]
|
||||
public class Song_tag {
|
||||
public int Song_id { get; set; }
|
||||
public class Song_tag
|
||||
{
|
||||
public int song_id { get; set; }
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
[NotMapped]
|
||||
public virtual Song Song { get; set; }
|
||||
|
||||
public int Tag_id { get; set; }
|
||||
public int tag_id { get; set; }
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
[NotMapped]
|
||||
public virtual Tag Tag { get; set; }
|
||||
@ -274,19 +645,20 @@ namespace orm_vs
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_tag")]
|
||||
[SugarTable("sugar_tag")]
|
||||
[Table("efcore_tag")]
|
||||
public class Tag {
|
||||
public class Tag
|
||||
{
|
||||
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
||||
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; set; }
|
||||
public int? Parent_id { get; set; }
|
||||
public int id { get; set; }
|
||||
public int? parent_id { get; set; }
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
[NotMapped]
|
||||
public virtual Tag Parent { get; set; }
|
||||
|
||||
public decimal? Ddd { get; set; }
|
||||
public string Name { get; set; }
|
||||
public decimal? ddd { get; set; }
|
||||
public string name { get; set; }
|
||||
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
[NotMapped]
|
||||
|
@ -2,17 +2,22 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.3" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.0" />
|
||||
<PackageReference Include="sqlSugarCore" Version="4.9.9.3" />
|
||||
<PackageReference Include="Dapper" Version="2.0.35" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.0" />
|
||||
<PackageReference Include="sqlSugarCore" Version="5.0.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.MySql\FreeSql.Provider.MySql.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.PostgreSQL\FreeSql.Provider.PostgreSQL.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.SqlServer\FreeSql.Provider.SqlServer.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
263
Examples/orm_vs_net40/Program.cs
Normal file
@ -0,0 +1,263 @@
|
||||
//using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace orm_vs
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=20")
|
||||
//.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=20")
|
||||
.UseAutoSyncStructure(false)
|
||||
.UseNoneCommandParameter(true)
|
||||
//.UseConfigEntityFromDbFirst(true)
|
||||
.Build();
|
||||
|
||||
//static SqlSugarClient sugar
|
||||
//{
|
||||
// get => new SqlSugarClient(new ConnectionConfig()
|
||||
// {
|
||||
// //不欺负,让连接池100个最小
|
||||
// //ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=20;Max Pool Size=20",
|
||||
// //DbType = DbType.SqlServer,
|
||||
// ConnectionString = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=20;Max Pool Size=20",
|
||||
// DbType = DbType.MySql,
|
||||
// IsAutoCloseConnection = true,
|
||||
// InitKeyType = InitKeyType.Attribute
|
||||
// });
|
||||
//}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||
//sugar.CodeFirst.InitTables(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||
//sugar创建表失败:SqlSugar.SqlSugarException: Sequence contains no elements
|
||||
|
||||
//sugar.Aop.OnLogExecuted = (s, e) =>
|
||||
//{
|
||||
// Trace.WriteLine(s);
|
||||
//};
|
||||
//测试前清空数据
|
||||
fsql.Delete<Song>().Where(a => a.Id > 0).ExecuteAffrows();
|
||||
//sugar.Deleteable<Song>().Where(a => a.Id > 0).ExecuteCommand();
|
||||
fsql.Ado.ExecuteNonQuery("delete from efcore_song");
|
||||
|
||||
var sb = new StringBuilder();
|
||||
Console.WriteLine("插入性能:");
|
||||
Insert(sb, 1000, 1);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Insert(sb, 1000, 10);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
Insert(sb, 1, 1000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Insert(sb, 1, 10000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Insert(sb, 1, 50000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Insert(sb, 1, 100000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
Console.WriteLine("查询性能:");
|
||||
Select(sb, 1000, 1);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Select(sb, 1000, 10);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
Select(sb, 1, 1000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Select(sb, 1, 10000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Select(sb, 1, 50000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Select(sb, 1, 100000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
Console.WriteLine("更新:");
|
||||
Update(sb, 1000, 1);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Update(sb, 1000, 10);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
Update(sb, 1, 1000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Update(sb, 1, 10000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Update(sb, 1, 50000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
Update(sb, 1, 100000);
|
||||
Console.Write(sb.ToString());
|
||||
sb.Clear();
|
||||
|
||||
Console.WriteLine("测试结束,按任意键退出...");
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
static void Select(StringBuilder sb, int forTime, int size)
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++)
|
||||
fsql.Select<Song>().Limit(size).ToList();
|
||||
sw.Stop();
|
||||
sb.AppendLine($"FreeSql Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
||||
|
||||
//sw.Restart();
|
||||
//for (var a = 0; a < forTime; a++)
|
||||
// sugar.Queryable<Song>().Take(size).ToList();
|
||||
//sw.Stop();
|
||||
//sb.AppendLine($"SqlSugar Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
||||
|
||||
sw.Restart();
|
||||
using (var conn = fsql.Ado.MasterPool.Get())
|
||||
{
|
||||
for (var a = 0; a < forTime; a++)
|
||||
Dapper.SqlMapper.Query<Song>(conn.Value, $"select top {size} * from freesql_song").ToList();
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"Dapper Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
||||
}
|
||||
|
||||
static void Insert(StringBuilder sb, int forTime, int size)
|
||||
{
|
||||
var songs = Enumerable.Range(0, size).Select(a => new Song
|
||||
{
|
||||
Create_time = DateTime.Now,
|
||||
Is_deleted = false,
|
||||
Title = $"Insert_{a}",
|
||||
Url = $"Url_{a}"
|
||||
});
|
||||
|
||||
//预热
|
||||
fsql.Insert(songs.First()).ExecuteAffrows();
|
||||
//sugar.Insertable(songs.First()).ExecuteCommand();
|
||||
Stopwatch sw = new Stopwatch();
|
||||
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++)
|
||||
{
|
||||
fsql.Insert(songs).ExecuteAffrows();
|
||||
//using (var db = new FreeSongContext()) {
|
||||
// //db.Configuration.AutoDetectChangesEnabled = false;
|
||||
// db.Songs.AddRange(songs.ToArray());
|
||||
// db.SaveChanges();
|
||||
//}
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"FreeSql Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
||||
|
||||
//sw.Restart();
|
||||
//Exception sugarEx = null;
|
||||
//try
|
||||
//{
|
||||
// for (var a = 0; a < forTime; a++)
|
||||
// sugar.Insertable(songs.ToArray()).ExecuteCommand();
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// sugarEx = ex;
|
||||
//}
|
||||
//sw.Stop();
|
||||
//sb.AppendLine($"SqlSugar Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms" + (sugarEx != null ? $"成绩无效,错误:{sugarEx.Message}" : ""));
|
||||
}
|
||||
|
||||
static void Update(StringBuilder sb, int forTime, int size)
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
|
||||
var songs = fsql.Select<Song>().Limit(size).ToList();
|
||||
sw.Restart();
|
||||
for (var a = 0; a < forTime; a++)
|
||||
{
|
||||
fsql.Update<Song>().SetSource(songs).ExecuteAffrows();
|
||||
}
|
||||
sw.Stop();
|
||||
sb.AppendLine($"FreeSql Update {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
||||
|
||||
//songs = sugar.Queryable<Song>().Take(size).ToList();
|
||||
//sw.Restart();
|
||||
//Exception sugarEx = null;
|
||||
//try
|
||||
//{
|
||||
// for (var a = 0; a < forTime; a++)
|
||||
// sugar.Updateable(songs).ExecuteCommand();
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// sugarEx = ex;
|
||||
//}
|
||||
//sw.Stop();
|
||||
//sb.AppendLine($"SqlSugar Update {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms" + (sugarEx != null ? $"成绩无效,错误:{sugarEx.Message}" : ""));
|
||||
}
|
||||
}
|
||||
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song")]
|
||||
//[SugarTable("sugar_song")]
|
||||
public class Song
|
||||
{
|
||||
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
||||
//[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
public DateTime? Create_time { get; set; }
|
||||
public bool? Is_deleted { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Url { get; set; }
|
||||
|
||||
//[SugarColumn(IsIgnore = true)]
|
||||
public virtual ICollection<Tag> Tags { get; set; }
|
||||
}
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song_tag")]
|
||||
//[SugarTable("sugar_song_tag")]
|
||||
public class Song_tag
|
||||
{
|
||||
public int Song_id { get; set; }
|
||||
//[SugarColumn(IsIgnore = true)]
|
||||
public virtual Song Song { get; set; }
|
||||
|
||||
public int Tag_id { get; set; }
|
||||
//[SugarColumn(IsIgnore = true)]
|
||||
public virtual Tag Tag { get; set; }
|
||||
}
|
||||
[FreeSql.DataAnnotations.Table(Name = "freesql_tag")]
|
||||
//[SugarTable("sugar_tag")]
|
||||
public class Tag
|
||||
{
|
||||
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
||||
//[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
public int? Parent_id { get; set; }
|
||||
//[SugarColumn(IsIgnore = true)]
|
||||
public virtual Tag Parent { get; set; }
|
||||
|
||||
public decimal? Ddd { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
//[SugarColumn(IsIgnore = true)]
|
||||
public virtual ICollection<Song> Songs { get; set; }
|
||||
//[SugarColumn(IsIgnore = true)]
|
||||
public virtual ICollection<Tag> Tags { get; set; }
|
||||
}
|
||||
}
|
36
Examples/orm_vs_net40/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("orm_vs_net40")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("orm_vs_net40")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||
[assembly: Guid("1674bce3-eeb4-4003-a2a7-06f51efaea23")]
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
75
Examples/orm_vs_net40/orm_vs_net40.csproj
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{1674BCE3-EEB4-4003-A2A7-06F51EFAEA23}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>orm_vs_net40</RootNamespace>
|
||||
<AssemblyName>orm_vs_net40</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj">
|
||||
<Project>{af9c50ec-6eb6-494b-9b3b-7edba6fd0ebb}</Project>
|
||||
<Name>FreeSql</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.MySql\FreeSql.Provider.MySql.csproj">
|
||||
<Project>{28c6a39c-7ae7-4210-b7b0-0970216637a8}</Project>
|
||||
<Name>FreeSql.Provider.MySql</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.SqlServer\FreeSql.Provider.SqlServer.csproj">
|
||||
<Project>{b61aac9e-59e9-4f47-bbe3-97ac24112efe}</Project>
|
||||
<Name>FreeSql.Provider.SqlServer</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper">
|
||||
<Version>1.50.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json">
|
||||
<Version>12.0.3</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\.editorconfig">
|
||||
<Link>.editorconfig</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
104
Examples/repository_01/Controllers/SongController.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using FreeSql;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using repository_01;
|
||||
using restful.Entitys;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace restful.Controllers
|
||||
{
|
||||
|
||||
public class SongRepository : GuidRepository<Song>
|
||||
{
|
||||
public SongRepository(IFreeSql fsql) : base(fsql)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Route("restapi/[controller]")]
|
||||
public class SongsController : Controller
|
||||
{
|
||||
|
||||
BaseRepository<Song, int> _songRepository;
|
||||
|
||||
public class xxxx
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public bool IsDeleted { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public SongsController(IFreeSql fsql,
|
||||
BaseRepository<Song> repos3, BaseRepository<Song, int> repos4,
|
||||
IBaseRepository<Song> repos31, IBaseRepository<Song, int> repos41,
|
||||
|
||||
SongRepository reposSong,
|
||||
IBaseRepository<TestSoftDelete> reposTest
|
||||
)
|
||||
{
|
||||
Console.Write(reposTest.Select.ToSql());
|
||||
|
||||
_songRepository = repos4;
|
||||
//test code
|
||||
var curd1 = fsql.GetRepository<Song, int>();
|
||||
var curd2 = fsql.GetRepository<Song, string>();
|
||||
var curd3 = fsql.GetRepository<Song, Guid>();
|
||||
var curd4 = fsql.GetGuidRepository<Song>();
|
||||
|
||||
Console.WriteLine(reposSong.Select.ToSql());
|
||||
|
||||
using (reposSong.DataFilter.DisableAll())
|
||||
{
|
||||
Console.WriteLine(reposSong.Select.ToSql());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public Task<List<Song>> GetItems([FromQuery] string key, [FromQuery] int page = 1, [FromQuery] int limit = 20)
|
||||
{
|
||||
return _songRepository.Select.WhereIf(!string.IsNullOrEmpty(key), a => a.Title.Contains(key)).Page(page, limit).ToListAsync();
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public Task<Song> GetItem([FromRoute] int id)
|
||||
{
|
||||
return _songRepository.FindAsync(id);
|
||||
}
|
||||
|
||||
public class ModelSong
|
||||
{
|
||||
public string title { get; set; }
|
||||
}
|
||||
|
||||
[HttpPost, ProducesResponseType(201)]
|
||||
public Task<Song> Create([FromBody] ModelSong model)
|
||||
{
|
||||
return _songRepository.InsertAsync(new Song { Title = model.title });
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
public Task Update([FromRoute] int id, [FromBody] ModelSong model)
|
||||
{
|
||||
return _songRepository.UpdateAsync(new Song { Id = id, Title = model.title });
|
||||
}
|
||||
|
||||
[HttpPatch("{id}")]
|
||||
async public Task<Song> UpdateDiy([FromRoute] int id, [FromForm] string title)
|
||||
{
|
||||
var up = _songRepository.UpdateDiy.Where(a => a.Id == id);
|
||||
if (!string.IsNullOrEmpty(title)) up.Set(a => a.Title, title);
|
||||
var ret = await up.ExecuteUpdatedAsync();
|
||||
return ret.FirstOrDefault();
|
||||
}
|
||||
|
||||
[HttpDelete("{id}"), ProducesResponseType(204)]
|
||||
public Task Delete([FromRoute] int id)
|
||||
{
|
||||
return _songRepository.DeleteAsync(a => a.Id == id);
|
||||
}
|
||||
}
|
||||
}
|
13
Examples/repository_01/Entitys/Song.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using repository_01;
|
||||
|
||||
namespace restful.Entitys
|
||||
{
|
||||
public class Song
|
||||
{
|
||||
|
||||
[Column(IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
}
|
||||
}
|
24
Examples/repository_01/Program.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace repository_01
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
}
|
27
Examples/repository_01/Properties/launchSettings.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:52751/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"repository_01": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:52752/"
|
||||
}
|
||||
}
|
||||
}
|
95
Examples/repository_01/Startup.cs
Normal file
@ -0,0 +1,95 @@
|
||||
using FreeSql;
|
||||
using FreeSql.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace repository_01
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 用户密码信息
|
||||
/// </summary>
|
||||
public class Sys1UserLogOn
|
||||
{
|
||||
[Column(IsPrimary = true, Name = "Id")]
|
||||
public Guid UserLogOnId { get; set; }
|
||||
public virtual Sys1User User { get; set; }
|
||||
}
|
||||
public class Sys1User
|
||||
{
|
||||
[Column(IsPrimary = true, Name = "Id")]
|
||||
public Guid UserId { get; set; }
|
||||
public virtual Sys1UserLogOn UserLogOn { get; set; }
|
||||
}
|
||||
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
|
||||
{
|
||||
Configuration = configuration;
|
||||
|
||||
Fsql = new FreeSql.FreeSqlBuilder()
|
||||
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
|
||||
.UseAutoSyncStructure(true)
|
||||
.UseLazyLoading(true)
|
||||
|
||||
.UseMonitorCommand(cmd => Trace.WriteLine(cmd.CommandText))
|
||||
.Build();
|
||||
|
||||
var sysu = new Sys1User { };
|
||||
Fsql.Insert<Sys1User>().AppendData(sysu).ExecuteAffrows();
|
||||
Fsql.Insert<Sys1UserLogOn>().AppendData(new Sys1UserLogOn { UserLogOnId = sysu.UserId }).ExecuteAffrows();
|
||||
var a = Fsql.Select<Sys1UserLogOn>().ToList();
|
||||
var b = Fsql.Select<Sys1UserLogOn>().Any();
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
public static IFreeSql Fsql { get; private set; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
//services.AddTransient(s => s.)
|
||||
|
||||
services.AddControllersWithViews();
|
||||
services.AddSingleton<IFreeSql>(Fsql);
|
||||
|
||||
services.AddFreeRepository(filter =>
|
||||
{
|
||||
filter
|
||||
//.Apply<Song>("test", a => a.Title == DateTime.Now.ToString() + System.Threading.Thread.CurrentThread.ManagedThreadId)
|
||||
.Apply<ISoftDelete>("softdelete", a => a.IsDeleted == false);
|
||||
}, this.GetType().Assembly);
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
||||
Console.InputEncoding = Encoding.GetEncoding("GB2312");
|
||||
|
||||
app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(a => a.MapControllers());
|
||||
}
|
||||
}
|
||||
|
||||
public interface ISoftDelete
|
||||
{
|
||||
bool IsDeleted { get; set; }
|
||||
}
|
||||
|
||||
public class TestSoftDelete : ISoftDelete
|
||||
{
|
||||
[Column(IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public bool IsDeleted { get; set; }
|
||||
}
|
||||
}
|
9
Examples/repository_01/appsettings.Development.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Warning",
|
||||
"Microsoft": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
8
Examples/repository_01/appsettings.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
18
Examples/repository_01/repository_01.csproj
Normal file
@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Extensions\FreeSql.Extensions.LazyLoading\FreeSql.Extensions.LazyLoading.csproj" />
|
||||
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
BIN
Examples/restful/001.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
Examples/restful/002.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
Examples/restful/003.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
Examples/restful/004.png
Normal file
After Width: | Height: | Size: 16 KiB |
@ -4,46 +4,55 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace restful.Controllers {
|
||||
namespace restful.Controllers
|
||||
{
|
||||
|
||||
|
||||
[Route("restapi/[controller]")]
|
||||
public class SongsController : Controller {
|
||||
public class SongsController : Controller
|
||||
{
|
||||
|
||||
IFreeSql _fsql;
|
||||
|
||||
public SongsController(IFreeSql fsql) {
|
||||
public SongsController(IFreeSql fsql)
|
||||
{
|
||||
_fsql = fsql;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public Task<List<Song>> GetItems([FromQuery] string key, [FromQuery] int page = 1, [FromQuery] int limit = 20) {
|
||||
public Task<List<Song>> GetItems([FromQuery] string key, [FromQuery] int page = 1, [FromQuery] int limit = 20)
|
||||
{
|
||||
return _fsql.Select<Song>().WhereIf(!string.IsNullOrEmpty(key), a => a.Title.Contains(key)).Page(page, limit).ToListAsync();
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public Task<Song> GetItem([FromRoute] int id) {
|
||||
public Task<Song> GetItem([FromRoute] int id)
|
||||
{
|
||||
return _fsql.Select<Song>().Where(a => a.Id == id).ToOneAsync();
|
||||
}
|
||||
|
||||
public class ModelSong {
|
||||
public class ModelSong
|
||||
{
|
||||
public string title { get; set; }
|
||||
}
|
||||
|
||||
[HttpPost, ProducesResponseType(201)]
|
||||
async public Task<Song> Create([FromBody] ModelSong model) {
|
||||
async public Task<Song> Create([FromBody] ModelSong model)
|
||||
{
|
||||
var ret = await _fsql.Insert<Song>().AppendData(new Song { Title = model.title }).ExecuteInsertedAsync();
|
||||
return ret.FirstOrDefault();
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
async public Task<Song> Update([FromRoute] int id, [FromBody] ModelSong model) {
|
||||
async public Task<Song> Update([FromRoute] int id, [FromBody] ModelSong model)
|
||||
{
|
||||
var ret = await _fsql.Update<Song>().SetSource(new Song { Id = id, Title = model.title }).ExecuteUpdatedAsync();
|
||||
return ret.FirstOrDefault();
|
||||
}
|
||||
|
||||
[HttpPatch("{id}")]
|
||||
async public Task<Song> UpdateDiy([FromRoute] int id, [FromForm] string title) {
|
||||
async public Task<Song> UpdateDiy([FromRoute] int id, [FromForm] string title)
|
||||
{
|
||||
var up = _fsql.Update<Song>().Where(a => a.Id == id);
|
||||
if (!string.IsNullOrEmpty(title)) up.Set(a => a.Title, title);
|
||||
var ret = await up.ExecuteUpdatedAsync();
|
||||
@ -51,7 +60,8 @@ namespace restful.Controllers {
|
||||
}
|
||||
|
||||
[HttpDelete("{id}"), ProducesResponseType(204)]
|
||||
async public Task<Song> Delete([FromRoute] int id) {
|
||||
async public Task<Song> Delete([FromRoute] int id)
|
||||
{
|
||||
var ret = await _fsql.Delete<Song>().Where(a => a.Id == id).ExecuteDeletedAsync();
|
||||
return ret.FirstOrDefault();
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
|
||||
namespace restful.Entitys {
|
||||
public class Song {
|
||||
namespace restful.Entitys
|
||||
{
|
||||
public class Song
|
||||
{
|
||||
|
||||
[Column(IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
@ -1,15 +1,16 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace restful {
|
||||
public class Startup {
|
||||
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory) {
|
||||
namespace restful
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
|
||||
{
|
||||
Configuration = configuration;
|
||||
|
||||
Fsql = new FreeSql.FreeSqlBuilder()
|
||||
@ -17,8 +18,10 @@ namespace restful {
|
||||
.UseAutoSyncStructure(true)
|
||||
.Build();
|
||||
|
||||
Fsql.Aop.CurdAfter = (s, e) => {
|
||||
if (e.ElapsedMilliseconds > 200) {
|
||||
Fsql.Aop.CurdAfter += (s, e) =>
|
||||
{
|
||||
if (e.ElapsedMilliseconds > 200)
|
||||
{
|
||||
//记录日志
|
||||
//发送短信给负责人
|
||||
}
|
||||
@ -33,35 +36,22 @@ namespace restful {
|
||||
public IConfiguration Configuration { get; }
|
||||
public IFreeSql Fsql { get; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services) {
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IFreeSql>(Fsql);
|
||||
|
||||
services.AddMvc();
|
||||
services.AddSwaggerGen(options => {
|
||||
options.SwaggerDoc("v1", new Info {
|
||||
Version = "v1",
|
||||
Title = "FreeSql.RESTful API"
|
||||
});
|
||||
//options.IncludeXmlComments(xmlPath);
|
||||
});
|
||||
services.AddControllersWithViews();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
|
||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
||||
Console.InputEncoding = Encoding.GetEncoding("GB2312");
|
||||
|
||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||
loggerFactory.AddDebug();
|
||||
|
||||
app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseMvc();
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c => {
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "FreeSql.RESTful API V1");
|
||||
});
|
||||
app.UseRouting();
|
||||
app.UseEndpoints(a => a.MapControllers());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="4.0.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="4.0.1" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.1" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
6
Examples/xamarinFormApp/xamarinForm.Wpf/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
</configuration>
|
9
Examples/xamarinFormApp/xamarinForm.Wpf/App.xaml
Normal file
@ -0,0 +1,9 @@
|
||||
<Application x:Class="xamarinForm.Wpf.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:xamarinForm.Wpf"
|
||||
StartupUri="MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
17
Examples/xamarinFormApp/xamarinForm.Wpf/App.xaml.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace xamarinForm.Wpf
|
||||
{
|
||||
/// <summary>
|
||||
/// App.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
}
|
||||
}
|
13
Examples/xamarinFormApp/xamarinForm.Wpf/MainWindow.xaml
Normal file
@ -0,0 +1,13 @@
|
||||
<wpf:FormsApplicationPage x:Class="xamarinForm.Wpf.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:xamarinForm.Wpf"
|
||||
mc:Ignorable="d"
|
||||
Title="MainWindow" Height="450" Width="800"
|
||||
xmlns:wpf="clr-namespace:Xamarin.Forms.Platform.WPF;assembly=Xamarin.Forms.Platform.WPF">
|
||||
<Grid>
|
||||
|
||||
</Grid>
|
||||
</wpf:FormsApplicationPage>
|
32
Examples/xamarinFormApp/xamarinForm.Wpf/MainWindow.xaml.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.WPF;
|
||||
|
||||
namespace xamarinForm.Wpf
|
||||
{
|
||||
/// <summary>
|
||||
/// MainWindow.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class MainWindow : FormsApplicationPage
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Forms.Init();
|
||||
LoadApplication(new xamarinFormApp.App());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// 有关程序集的一般信息由以下
|
||||
// 控制。更改这些特性值可修改
|
||||
// 与程序集关联的信息。
|
||||
[assembly: AssemblyTitle("xamarinForm.Wpf")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("xamarinForm.Wpf")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// 将 ComVisible 设置为 false 会使此程序集中的类型
|
||||
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
|
||||
//请将此类型的 ComVisible 特性设置为 true。
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//若要开始生成可本地化的应用程序,请设置
|
||||
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
|
||||
//例如,如果您在源文件中使用的是美国英语,
|
||||
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
|
||||
//对以下 NeutralResourceLanguage 特性的注释。 更新
|
||||
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
|
||||
//(未在页面中找到资源时使用,
|
||||
//或应用程序资源字典中找到时使用)
|
||||
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
|
||||
//(未在页面中找到资源时使用,
|
||||
//、应用程序或任何主题专用资源字典中找到时使用)
|
||||
)]
|
||||
|
||||
|
||||
// 程序集的版本信息由下列四个值组成:
|
||||
//
|
||||
// 主版本
|
||||
// 次版本
|
||||
// 生成号
|
||||
// 修订号
|
||||
//
|
||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
|
||||
//通过使用 "*",如下所示:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
70
Examples/xamarinFormApp/xamarinForm.Wpf/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// 此代码由工具生成。
|
||||
// 运行时版本: 4.0.30319.42000
|
||||
//
|
||||
// 对此文件的更改可能导致不正确的行为,如果
|
||||
// 重新生成代码,则所做更改将丢失。
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace xamarinForm.Wpf.Properties
|
||||
{
|
||||
/// <summary>
|
||||
/// 强类型资源类,用于查找本地化字符串等。
|
||||
/// </summary>
|
||||
// 此类是由 StronglyTypedResourceBuilder
|
||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||
// 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回此类使用的缓存 ResourceManager 实例。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("xamarinForm.Wpf.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
29
Examples/xamarinFormApp/xamarinForm.Wpf/Properties/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,29 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
namespace xamarinForm.Wpf.Properties
|
||||
{
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
109
Examples/xamarinFormApp/xamarinForm.Wpf/xamarinForm.Wpf.csproj
Normal file
@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{12EC22F5-2586-4AD3-AE03-319C2FAC0B06}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>xamarinForm.Wpf</RootNamespace>
|
||||
<AssemblyName>xamarinForm.Wpf</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Forms.Platform.WPF">
|
||||
<Version>4.8.0.1687</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\xamarinFormApp\xamarinFormApp.csproj">
|
||||
<Project>{e4094717-ed1a-4174-8d86-a65d2ad1380c}</Project>
|
||||
<Name>xamarinFormApp</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
@ -0,0 +1,19 @@
|
||||
Any raw assets you want to be deployed with your application can be placed in
|
||||
this directory (and child directories) and given a Build Action of "AndroidAsset".
|
||||
|
||||
These files will be deployed with your package and will be accessible using Android's
|
||||
AssetManager, like this:
|
||||
|
||||
public class ReadAsset : Activity
|
||||
{
|
||||
protected override void OnCreate (Bundle bundle)
|
||||
{
|
||||
base.OnCreate (bundle);
|
||||
|
||||
InputStream input = Assets.Open ("my_asset.txt");
|
||||
}
|
||||
}
|
||||
|
||||
Additionally, some Android functions will automatically load asset files:
|
||||
|
||||
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
|
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.OS;
|
||||
|
||||
namespace xamarinFormApp.Droid
|
||||
{
|
||||
[Activity(Label = "xamarinFormApp", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
|
||||
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
|
||||
{
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
TabLayoutResource = Resource.Layout.Tabbar;
|
||||
ToolbarResource = Resource.Layout.Toolbar;
|
||||
|
||||
base.OnCreate(savedInstanceState);
|
||||
|
||||
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
|
||||
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
|
||||
LoadApplication(new App());
|
||||
}
|
||||
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
|
||||
{
|
||||
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.xamarinformapp" android:installLocation="auto">
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
|
||||
<application android:label="xamarinFormApp.Android" android:theme="@style/MainTheme"></application>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
</manifest>
|
@ -0,0 +1,30 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Android.App;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("xamarinFormApp.Android")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("xamarinFormApp.Android")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
// Add some common permissions, these can be removed if not needed
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
|
@ -0,0 +1,50 @@
|
||||
Images, layout descriptions, binary blobs and string dictionaries can be included
|
||||
in your application as resource files. Various Android APIs are designed to
|
||||
operate on the resource IDs instead of dealing with images, strings or binary blobs
|
||||
directly.
|
||||
|
||||
For example, a sample Android app that contains a user interface layout (main.xml),
|
||||
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
|
||||
would keep its resources in the "Resources" directory of the application:
|
||||
|
||||
Resources/
|
||||
drawable-hdpi/
|
||||
icon.png
|
||||
|
||||
drawable-ldpi/
|
||||
icon.png
|
||||
|
||||
drawable-mdpi/
|
||||
icon.png
|
||||
|
||||
layout/
|
||||
main.xml
|
||||
|
||||
values/
|
||||
strings.xml
|
||||
|
||||
In order to get the build system to recognize Android resources, set the build action to
|
||||
"AndroidResource". The native Android APIs do not operate directly with filenames, but
|
||||
instead operate on resource IDs. When you compile an Android application that uses resources,
|
||||
the build system will package the resources for distribution and generate a class called
|
||||
"Resource" that contains the tokens for each one of the resources included. For example,
|
||||
for the above Resources layout, this is what the Resource class would expose:
|
||||
|
||||
public class Resource {
|
||||
public class drawable {
|
||||
public const int icon = 0x123;
|
||||
}
|
||||
|
||||
public class layout {
|
||||
public const int main = 0x456;
|
||||
}
|
||||
|
||||
public class strings {
|
||||
public const int first_string = 0xabc;
|
||||
public const int second_string = 0xbcd;
|
||||
}
|
||||
}
|
||||
|
||||
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
|
||||
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
|
||||
string in the dictionary file values/strings.xml.
|
14056
Examples/xamarinFormApp/xamarinFormApp.Android/Resources/Resource.designer.cs
generated
Normal file
After Width: | Height: | Size: 518 B |
After Width: | Height: | Size: 415 B |
After Width: | Height: | Size: 21 KiB |
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/sliding_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
app:tabIndicatorColor="@android:color/white"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="fixed" />
|
@ -0,0 +1,9 @@
|
||||
<android.support.v7.widget.Toolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
android:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
|
||||
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/launcher_background" />
|
||||
<foreground android:drawable="@mipmap/launcher_foreground" />
|
||||
</adaptive-icon>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/launcher_background" />
|
||||
<foreground android:drawable="@mipmap/launcher_foreground" />
|
||||
</adaptive-icon>
|
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 6.3 KiB |