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
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
FreeSql.xml
|
||||||
|
FreeSql.DbContext.xml
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
@ -186,7 +189,6 @@ ClientBin/
|
|||||||
*~
|
*~
|
||||||
*.dbmdl
|
*.dbmdl
|
||||||
*.dbproj.schemaview
|
*.dbproj.schemaview
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
*.publishsettings
|
||||||
node_modules/
|
node_modules/
|
||||||
orleans.codegen.cs
|
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,207 +8,227 @@ using BenchmarkDotNet.Running;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
//using SqlSugar;
|
//using SqlSugar;
|
||||||
|
|
||||||
namespace FreeSql.Bechmarker {
|
namespace FreeSql.Bechmarker
|
||||||
|
{
|
||||||
|
|
||||||
public class Program {
|
public class Program
|
||||||
public static void Main(string[] args) {
|
{
|
||||||
var summaryInsert = BenchmarkRunner.Run<OrmVsInsert>();
|
public static void Main(string[] args)
|
||||||
var summarySelect = BenchmarkRunner.Run<OrmVsSelect>();
|
{
|
||||||
var summaryUpdate = BenchmarkRunner.Run<OrmVsUpdate>();
|
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")
|
public static 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=20")
|
.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=20")
|
||||||
.UseAutoSyncStructure(false)
|
//.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")
|
||||||
.UseNoneCommandParameter(true)
|
.UseAutoSyncStructure(false)
|
||||||
//.UseConfigEntityFromDbFirst(true)
|
.UseNoneCommandParameter(true)
|
||||||
.Build();
|
//.UseConfigEntityFromDbFirst(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
//public static SqlSugarClient sugar {
|
//public static SqlSugarClient sugar {
|
||||||
// get => new SqlSugarClient(new ConnectionConfig() {
|
// get => new SqlSugarClient(new ConnectionConfig() {
|
||||||
// //不欺负,让连接池100个最小
|
// //不欺负,让连接池100个最小
|
||||||
// ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=20;Max Pool Size=20",
|
// ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=20;Max Pool Size=20",
|
||||||
// DbType = DbType.SqlServer,
|
// 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",
|
// //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,
|
// //DbType = DbType.MySql,
|
||||||
// IsAutoCloseConnection = true,
|
// IsAutoCloseConnection = true,
|
||||||
// InitKeyType = InitKeyType.Attribute
|
// InitKeyType = InitKeyType.Attribute
|
||||||
// });
|
// });
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
class SongContext : DbContext {
|
class SongContext : DbContext
|
||||||
public DbSet<Song> Songs { get; set; }
|
{
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
public DbSet<Song> Songs { get; set; }
|
||||||
optionsBuilder.UseSqlServer(@"Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=21;Max Pool Size=21");
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
//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.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]
|
||||||
[RPlotExporter, RankColumn]
|
public class OrmVsInsert
|
||||||
public class OrmVsInsert {
|
{
|
||||||
public IEnumerable<Song> songs;
|
public IEnumerable<Song> songs;
|
||||||
|
|
||||||
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
||||||
public int size;
|
public int size;
|
||||||
|
|
||||||
[GlobalSetup]
|
[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));
|
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||||
//sugar创建表失败:SqlSugar.SqlSugarException: Sequence contains no elements
|
//Orm.sugar.CodeFirst.InitTables(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||||
|
//sugar创建表失败:SqlSugar.SqlSugarException: Sequence contains no elements
|
||||||
|
|
||||||
//测试前清空数据
|
//测试前清空数据
|
||||||
Orm.fsql.Delete<Song>().Where(a => a.Id > 0).ExecuteAffrows();
|
Orm.fsql.Delete<Song>().Where(a => a.Id > 0).ExecuteAffrows();
|
||||||
//Orm.sugar.Deleteable<Song>().Where(a => a.Id > 0).ExecuteCommand();
|
//Orm.sugar.Deleteable<Song>().Where(a => a.Id > 0).ExecuteCommand();
|
||||||
Orm.fsql.Ado.ExecuteNonQuery("delete from efcore_song");
|
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,
|
Create_time = DateTime.Now,
|
||||||
Title = $"Insert_{a}",
|
Is_deleted = false,
|
||||||
Url = $"Url_{a}"
|
Title = $"Insert_{a}",
|
||||||
});
|
Url = $"Url_{a}"
|
||||||
|
});
|
||||||
|
|
||||||
//预热
|
//预热
|
||||||
Orm.fsql.Insert(songs.First()).ExecuteAffrows();
|
Orm.fsql.Insert(songs.First()).ExecuteAffrows();
|
||||||
//Orm.sugar.Insertable(songs.First()).ExecuteCommand();
|
//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.Configuration.AutoDetectChangesEnabled = false;
|
||||||
db.SaveChanges();
|
db.Songs.AddRange(songs.First());
|
||||||
}
|
db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public int FreeSqlInsert() => Orm.fsql.Insert(songs).ExecuteAffrows();
|
public int FreeSqlInsert() => Orm.fsql.Insert(songs).ExecuteAffrows();
|
||||||
|
|
||||||
//[Benchmark]
|
//[Benchmark]
|
||||||
//public int SqlSugarInsert() => Orm.sugar.Insertable(songs.ToArray()).ExecuteCommand();
|
//public int SqlSugarInsert() => Orm.sugar.Insertable(songs.ToArray()).ExecuteCommand();
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public int EfCoreInsert() {
|
public int EfCoreInsert()
|
||||||
using (var db = new SongContext()) {
|
{
|
||||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
using (var db = new SongContext())
|
||||||
db.Songs.AddRange(songs.ToArray());
|
{
|
||||||
return db.SaveChanges();
|
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||||
}
|
db.Songs.AddRange(songs.ToArray());
|
||||||
}
|
return db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[CoreJob]
|
[RPlotExporter, RankColumn]
|
||||||
[RPlotExporter, RankColumn]
|
public class OrmVsUpdate
|
||||||
public class OrmVsUpdate {
|
{
|
||||||
public List<Song> songs;
|
public List<Song> songs;
|
||||||
|
|
||||||
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
||||||
public int size;
|
public int size;
|
||||||
|
|
||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup() {
|
public void Setup()
|
||||||
songs = Orm.fsql.Select<Song>().Limit(size).ToList();
|
{
|
||||||
}
|
songs = Orm.fsql.Select<Song>().Limit(size).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public int FreeSqlUpdate() => Orm.fsql.Update<Song>().SetSource(songs).ExecuteAffrows();
|
public int FreeSqlUpdate() => Orm.fsql.Update<Song>().SetSource(songs).ExecuteAffrows();
|
||||||
|
|
||||||
//[Benchmark]
|
//[Benchmark]
|
||||||
//public int SqlSugarUpdate() => Orm.sugar.Updateable(songs).ExecuteCommand();
|
//public int SqlSugarUpdate() => Orm.sugar.Updateable(songs).ExecuteCommand();
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public int EfCoreUpdate() {
|
public int EfCoreUpdate()
|
||||||
using (var db = new SongContext()) {
|
{
|
||||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
using (var db = new SongContext())
|
||||||
db.Songs.UpdateRange(songs.ToArray());
|
{
|
||||||
return db.SaveChanges();
|
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||||
}
|
db.Songs.UpdateRange(songs.ToArray());
|
||||||
}
|
return db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[CoreJob]
|
[RPlotExporter, RankColumn]
|
||||||
[RPlotExporter, RankColumn]
|
public class OrmVsSelect
|
||||||
public class OrmVsSelect {
|
{
|
||||||
|
|
||||||
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
[Params(1, 500, 1000, 5000, 10000, 50000, 100000)]
|
||||||
public int size;
|
public int size;
|
||||||
|
|
||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup() {
|
public void Setup()
|
||||||
|
{
|
||||||
}
|
|
||||||
|
|
||||||
[Benchmark]
|
}
|
||||||
public List<Song> FreeSqlSelect() => Orm.fsql.Select<Song>().Limit(size).ToList();
|
|
||||||
|
|
||||||
//[Benchmark]
|
[Benchmark]
|
||||||
//public List<Song> SqlSugarSelect() => Orm.sugar.Queryable<Song>().Take(size).ToList();
|
public List<Song> FreeSqlSelect() => Orm.fsql.Select<Song>().Limit(size).ToList();
|
||||||
|
|
||||||
[Benchmark]
|
//[Benchmark]
|
||||||
public List<Song> EfCoreSelect() {
|
//public List<Song> SqlSugarSelect() => Orm.sugar.Queryable<Song>().Take(size).ToList();
|
||||||
using (var db = new SongContext()) {
|
|
||||||
return db.Songs.Take(size).AsNoTracking().ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song")]
|
[Benchmark]
|
||||||
//[SugarTable("sugar_song")]
|
public List<Song> EfCoreSelect()
|
||||||
[Table("efcore_song")]
|
{
|
||||||
public class Song {
|
using (var db = new SongContext())
|
||||||
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
{
|
||||||
//[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
return db.Songs.Take(size).AsNoTracking().ToList();
|
||||||
[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; }
|
|
||||||
|
|
||||||
//[SugarColumn(IsIgnore = true)]
|
[FreeSql.DataAnnotations.Table(Name = "freesql_song")]
|
||||||
[NotMapped]
|
//[SugarTable("sugar_song")]
|
||||||
public virtual ICollection<Tag> Tags { get; set; }
|
[Table("efcore_song")]
|
||||||
}
|
public class Song
|
||||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song_tag")]
|
{
|
||||||
//[SugarTable("sugar_song_tag")]
|
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
||||||
[Table("efcore_song_tag")]
|
//[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||||
public class Song_tag {
|
[Key]
|
||||||
public int Song_id { get; set; }
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
//[SugarColumn(IsIgnore = true)]
|
public int Id { get; set; }
|
||||||
[NotMapped]
|
public DateTime? Create_time { get; set; }
|
||||||
public virtual Song Song { get; set; }
|
public bool? Is_deleted { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public string Url { get; set; }
|
||||||
|
|
||||||
public int Tag_id { get; set; }
|
//[SugarColumn(IsIgnore = true)]
|
||||||
//[SugarColumn(IsIgnore = true)]
|
[NotMapped]
|
||||||
[NotMapped]
|
public virtual ICollection<Tag> Tags { get; set; }
|
||||||
public virtual Tag Tag { get; set; }
|
}
|
||||||
}
|
[FreeSql.DataAnnotations.Table(Name = "freesql_song_tag")]
|
||||||
[FreeSql.DataAnnotations.Table(Name = "freesql_tag")]
|
//[SugarTable("sugar_song_tag")]
|
||||||
//[SugarTable("sugar_tag")]
|
[Table("efcore_song_tag")]
|
||||||
[Table("efcore_tag")]
|
public class Song_tag
|
||||||
public class Tag {
|
{
|
||||||
[FreeSql.DataAnnotations.Column(IsIdentity = true)]
|
public int Song_id { get; set; }
|
||||||
//[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
//[SugarColumn(IsIgnore = true)]
|
||||||
[Key]
|
[NotMapped]
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
public virtual Song Song { 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 int Tag_id { get; set; }
|
||||||
public string Name { get; set; }
|
//[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual Tag Tag { get; set; }
|
||||||
|
}
|
||||||
|
[FreeSql.DataAnnotations.Table(Name = "freesql_tag")]
|
||||||
|
//[SugarTable("sugar_tag")]
|
||||||
|
[Table("efcore_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; }
|
||||||
|
//[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual Tag Parent { get; set; }
|
||||||
|
|
||||||
//[SugarColumn(IsIgnore = true)]
|
public decimal? Ddd { get; set; }
|
||||||
[NotMapped]
|
public string Name { get; set; }
|
||||||
public virtual ICollection<Song> Songs { get; set; }
|
|
||||||
//[SugarColumn(IsIgnore = true)]
|
//[SugarColumn(IsIgnore = true)]
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public virtual ICollection<Tag> Tags { get; set; }
|
public virtual ICollection<Song> Songs { get; set; }
|
||||||
}
|
//[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual ICollection<Tag> Tags { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.11.5" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.0-rc1.final" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
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,18 +2,22 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
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; }
|
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); //ͬ²½ÅäÖÃ
|
base.OnModelCreating(modelBuilder);
|
||||||
}
|
Fsql.CodeFirst.ConfigEntity(modelBuilder.Model); //ͬ²½ÅäÖÃ
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
}
|
||||||
optionsBuilder.UseSqlite(@"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10");
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
}
|
{
|
||||||
}
|
optionsBuilder.UseSqlite(@"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,18 +1,21 @@
|
|||||||
using efcore_to_freesql.Entitys;
|
using efcore_to_freesql.Entitys;
|
||||||
using Microsoft.EntityFrameworkCore;
|
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; }
|
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>().ToTable("topic1_sss").HasKey(a => a.Id);
|
||||||
modelBuilder.Entity<Topic1>().Property(a => a.Id).HasColumnName("topic1_id").ValueGeneratedOnAdd();
|
modelBuilder.Entity<Topic1>().Property(a => a.Id).HasColumnName("topic1_id").ValueGeneratedOnAdd();
|
||||||
|
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,21 @@
|
|||||||
using efcore_to_freesql.Entitys;
|
using efcore_to_freesql.Entitys;
|
||||||
using Microsoft.EntityFrameworkCore;
|
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; }
|
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>().ToTable("topic2_sss");
|
||||||
modelBuilder.Entity<Topic2>().Property(a => a.Id).HasColumnName("topic2_id");
|
modelBuilder.Entity<Topic2>().Property(a => a.Id).HasColumnName("topic2_id");
|
||||||
|
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
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;
|
using System;
|
||||||
|
|
||||||
namespace efcore_to_freesql.Entitys {
|
namespace efcore_to_freesql.Entitys
|
||||||
|
{
|
||||||
|
|
||||||
public class Topic1
|
public class Topic1
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,8 @@ using System;
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace efcore_to_freesql.Entitys {
|
namespace efcore_to_freesql.Entitys
|
||||||
|
{
|
||||||
|
|
||||||
public class Topic2
|
public class Topic2
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using FreeSql;
|
using efcore_to_freesql.Entitys;
|
||||||
|
using FreeSql;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using System;
|
using System;
|
||||||
@ -6,60 +7,175 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
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");
|
var relationalTableName = type.FindAnnotation("Relational:TableName");
|
||||||
if (relationalTableName != null)
|
if (relationalTableName != null)
|
||||||
a.Name(relationalTableName.Value?.ToString() ?? type.ClrType.Name);
|
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);
|
var freeProp = a.Property(prop.Name);
|
||||||
|
|
||||||
//列名
|
//列名
|
||||||
var relationalColumnName = prop.FindAnnotation("Relational:ColumnName");
|
var relationalColumnName = prop.FindAnnotation("Relational:ColumnName");
|
||||||
if (relationalColumnName != null)
|
if (relationalColumnName != null)
|
||||||
freeProp.Name(relationalColumnName.Value?.ToString() ?? prop.Name);
|
freeProp.Name(relationalColumnName.Value?.ToString() ?? prop.Name);
|
||||||
|
|
||||||
//主键
|
//主键
|
||||||
freeProp.IsPrimary(prop.IsPrimaryKey());
|
freeProp.IsPrimary(prop.IsPrimaryKey());
|
||||||
|
|
||||||
//自增
|
//自增
|
||||||
freeProp.IsIdentity(
|
freeProp.IsIdentity(
|
||||||
prop.ValueGenerated == ValueGenerated.Never ||
|
prop.ValueGenerated == ValueGenerated.Never ||
|
||||||
prop.ValueGenerated == ValueGenerated.OnAdd ||
|
prop.ValueGenerated == ValueGenerated.OnAdd ||
|
||||||
prop.GetAnnotations().Where(z =>
|
prop.GetAnnotations().Where(z =>
|
||||||
z.Name == "SqlServer:ValueGenerationStrategy" && z.Value.ToString().Contains("IdentityColumn") //sqlserver 自增
|
z.Name == "SqlServer:ValueGenerationStrategy" && z.Value.ToString().Contains("IdentityColumn") //sqlserver 自增
|
||||||
|| z.Value.ToString().Contains("IdentityColumn") //其他数据库实现未经测试
|
|| z.Value.ToString().Contains("IdentityColumn") //其他数据库实现未经测试
|
||||||
).Any()
|
).Any()
|
||||||
);
|
);
|
||||||
|
|
||||||
//可空
|
//可空
|
||||||
freeProp.IsNullable(prop.AfterSaveBehavior != PropertySaveBehavior.Throw);
|
freeProp.IsNullable(prop.GetAfterSaveBehavior() != PropertySaveBehavior.Throw);
|
||||||
|
|
||||||
//类型
|
//类型
|
||||||
var relationalColumnType = prop.FindAnnotation("Relational:ColumnType");
|
var relationalColumnType = prop.FindAnnotation("Relational:ColumnType");
|
||||||
if (relationalColumnType != null) {
|
if (relationalColumnType != null)
|
||||||
|
{
|
||||||
|
|
||||||
var dbType = relationalColumnType.ToString();
|
var dbType = relationalColumnType.ToString();
|
||||||
if (!string.IsNullOrEmpty(dbType)) {
|
if (!string.IsNullOrEmpty(dbType))
|
||||||
|
{
|
||||||
|
|
||||||
var maxLength = prop.FindAnnotation("MaxLength");
|
var maxLength = prop.FindAnnotation("MaxLength");
|
||||||
if (maxLength != null)
|
if (maxLength != null)
|
||||||
dbType += $"({maxLength})";
|
dbType += $"({maxLength})";
|
||||||
|
|
||||||
freeProp.DbType(dbType);
|
freeProp.DbType(dbType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>();
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,30 +1,30 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
"iisSettings": {
|
"iisSettings": {
|
||||||
"windowsAuthentication": false,
|
"windowsAuthentication": false,
|
||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://localhost:58143",
|
"applicationUrl": "http://localhost:58143",
|
||||||
"sslPort": 44349
|
"sslPort": 44349
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"profiles": {
|
|
||||||
"IIS Express": {
|
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"launchUrl": "api/values",
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"efcore_to_freesql": {
|
"profiles": {
|
||||||
"commandName": "Project",
|
"IIS Express": {
|
||||||
"launchBrowser": true,
|
"commandName": "IISExpress",
|
||||||
"launchUrl": "api/values",
|
"launchBrowser": true,
|
||||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
"launchUrl": "api/values",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"efcore_to_freesql": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "api/values",
|
||||||
|
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,57 +22,66 @@ namespace efcore_to_freesql
|
|||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
|
|
||||||
Fsql = new FreeSql.FreeSqlBuilder()
|
Fsql = new FreeSql.FreeSqlBuilder()
|
||||||
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
|
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
|
||||||
.UseAutoSyncStructure(true)
|
.UseAutoSyncStructure(true)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
DBContexts.BaseDBContext.Fsql = Fsql;
|
//Fsql.CodeFirst.EfCoreFluentApiTestGeneric();
|
||||||
|
Fsql.CodeFirst.EfCoreFluentApiTestDynamic();
|
||||||
|
|
||||||
var sql11 = Fsql.Select<Topic1>().ToSql();
|
BaseDBContext.Fsql = Fsql;
|
||||||
//SELECT a."Id", a."Title", a."CreateTime" FROM "Topic1" a
|
|
||||||
var sql12 = Fsql.Insert<Topic1>().AppendData(new Topic1()).ToSql();
|
|
||||||
//INSERT INTO "Topic1"("Id", "Title", "CreateTime") VALUES(@Id0, @Title0, @CreateTime0)
|
|
||||||
|
|
||||||
var sql21 = Fsql.Select<Topic2>().ToSql();
|
var sql11 = Fsql.Select<Topic1>().ToSql();
|
||||||
//SELECT a."Id", a."Title", a."CreateTime" FROM "Topic2" a
|
//SELECT a."Id", a."Title", a."CreateTime" FROM "Topic1" a
|
||||||
var sql22 = Fsql.Insert<Topic2>().AppendData(new Topic2()).ToSql();
|
var sql12 = Fsql.Insert<Topic1>().AppendData(new Topic1()).ToSql();
|
||||||
//INSERT INTO "Topic2"("Id", "Title", "CreateTime") VALUES(@Id0, @Title0, @CreateTime0)
|
//INSERT INTO "Topic1"("Id", "Title", "CreateTime") VALUES(@Id0, @Title0, @CreateTime0)
|
||||||
|
|
||||||
using (var db = new Topic1Context()) {
|
var sql21 = Fsql.Select<Topic2>().ToSql();
|
||||||
db.Topic1s.Add(new Topic1());
|
//SELECT a."Id", a."Title", a."CreateTime" FROM "Topic2" a
|
||||||
}
|
var sql22 = Fsql.Insert<Topic2>().AppendData(new Topic2()).ToSql();
|
||||||
using (var db = new Topic2Context()) {
|
//INSERT INTO "Topic2"("Id", "Title", "CreateTime") VALUES(@Id0, @Title0, @CreateTime0)
|
||||||
db.Topic2s.Add(new Topic2());
|
|
||||||
}
|
|
||||||
|
|
||||||
var sql13 = Fsql.Select<Topic1>().ToSql();
|
using (var db = new Topic1Context())
|
||||||
//SELECT a."topic1_id", a."Title", a."CreateTime" FROM "topic1_sss" a
|
{
|
||||||
var sql14 = Fsql.Insert<Topic1>().AppendData(new Topic1()).ToSql();
|
db.Topic1s.Add(new Topic1());
|
||||||
//INSERT INTO "topic1_sss"("Title", "CreateTime") VALUES(@Title0, @CreateTime0)
|
}
|
||||||
|
using (var db = new Topic2Context())
|
||||||
|
{
|
||||||
|
db.Topic2s.Add(new Topic2());
|
||||||
|
}
|
||||||
|
|
||||||
var sql23 = Fsql.Select<Topic2>().ToSql();
|
var sql13 = Fsql.Select<Topic1>().ToSql();
|
||||||
//SELECT a."topic2_id", a."Title", a."CreateTime" FROM "topic2_sss" a
|
//SELECT a."topic1_id", a."Title", a."CreateTime" FROM "topic1_sss" a
|
||||||
var sql24 = Fsql.Insert<Topic2>().AppendData(new Topic2()).ToSql();
|
var sql14 = Fsql.Insert<Topic1>().AppendData(new Topic1()).ToSql();
|
||||||
//INSERT INTO "topic2_sss"("Title", "CreateTime") VALUES(@Title0, @CreateTime0)
|
//INSERT INTO "topic1_sss"("Title", "CreateTime") VALUES(@Title0, @CreateTime0)
|
||||||
}
|
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
var sql23 = Fsql.Select<Topic2>().ToSql();
|
||||||
public IFreeSql Fsql { get; }
|
//SELECT a."topic2_id", a."Title", a."CreateTime" FROM "topic2_sss" a
|
||||||
|
var sql24 = Fsql.Insert<Topic2>().AppendData(new Topic2()).ToSql();
|
||||||
public void ConfigureServices(IServiceCollection services)
|
//INSERT INTO "topic2_sss"("Title", "CreateTime") VALUES(@Title0, @CreateTime0)
|
||||||
{
|
|
||||||
services.AddSingleton<IFreeSql>(Fsql);
|
|
||||||
services.AddMvc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
public IConfiguration Configuration { get; }
|
||||||
{
|
public IFreeSql Fsql { get; }
|
||||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
|
||||||
loggerFactory.AddDebug();
|
|
||||||
|
|
||||||
app.UseDeveloperExceptionPage();
|
public void ConfigureServices(IServiceCollection services)
|
||||||
app.UseMvc();
|
{
|
||||||
}
|
services.AddControllersWithViews();
|
||||||
|
services.AddSingleton<IFreeSql>(Fsql);
|
||||||
|
services.AddMvc();
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Debug",
|
"Default": "Debug",
|
||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Information"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Warning"
|
"Default": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
|
</ItemGroup>
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
|
||||||
</ItemGroup>
|
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using FreeSql.Internal;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Data.Common;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -14,285 +17,654 @@ namespace orm_vs
|
|||||||
{
|
{
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
|
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.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.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)
|
//.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=20")
|
||||||
.UseNoneCommandParameter(true)
|
.UseAutoSyncStructure(false)
|
||||||
//.UseConfigEntityFromDbFirst(true)
|
.UseNoneCommandParameter(true)
|
||||||
.Build();
|
//.UseConfigEntityFromDbFirst(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
static SqlSugarClient sugar {
|
static SqlSugarClient sugar
|
||||||
get => new SqlSugarClient(new ConnectionConfig() {
|
{
|
||||||
//不欺负,让连接池100个最小
|
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=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=20;Max Pool Size=20",
|
||||||
//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.SqlServer,
|
||||||
//DbType = DbType.MySql,
|
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",
|
||||||
IsAutoCloseConnection = true,
|
DbType = DbType.MySql,
|
||||||
InitKeyType = InitKeyType.Attribute
|
//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) {
|
public DbSet<Song> Songs { get; set; }
|
||||||
optionsBuilder.UseSqlServer(@"Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Min Pool Size=21;Max Pool Size=21");
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
//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.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");
|
||||||
|
}
|
||||||
|
|
||||||
static void Main(string[] args) {
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag));
|
modelBuilder.Entity<Song>()
|
||||||
//sugar.CodeFirst.InitTables(typeof(Song), typeof(Song_tag), typeof(Tag));
|
.Property(a => a.create_time)
|
||||||
//sugar创建表失败:SqlSugar.SqlSugarException: Sequence contains no elements
|
.HasConversion(a => int.Parse(a.ToString()), a => new DateTime(a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//测试前清空数据
|
static void Main(string[] args)
|
||||||
fsql.Delete<Song>().Where(a => a.Id > 0).ExecuteAffrows();
|
{
|
||||||
sugar.Deleteable<Song>().Where(a => a.Id > 0).ExecuteCommand();
|
//fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag));
|
||||||
fsql.Ado.ExecuteNonQuery("delete from efcore_song");
|
//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");
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "freesql_song_tag");
|
||||||
Console.WriteLine("插入性能:");
|
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "sugar_song_tag");
|
||||||
Insert(sb, 1000, 1);
|
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "efcore_song_tag");
|
||||||
Console.Write(sb.ToString());
|
|
||||||
sb.Clear();
|
|
||||||
Insert(sb, 1000, 10);
|
|
||||||
Console.Write(sb.ToString());
|
|
||||||
sb.Clear();
|
|
||||||
|
|
||||||
Insert(sb, 1, 1000);
|
fsql.CodeFirst.SyncStructure(typeof(Tag), "freesql_tag");
|
||||||
Console.Write(sb.ToString());
|
fsql.CodeFirst.SyncStructure(typeof(Tag), "sugar_tag");
|
||||||
sb.Clear();
|
fsql.CodeFirst.SyncStructure(typeof(Tag), "efcore_tag");
|
||||||
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("查询性能:");
|
var sb = new StringBuilder();
|
||||||
Select(sb, 1000, 1);
|
var time = new Stopwatch();
|
||||||
Console.Write(sb.ToString());
|
|
||||||
sb.Clear();
|
|
||||||
Select(sb, 1000, 10);
|
|
||||||
Console.Write(sb.ToString());
|
|
||||||
sb.Clear();
|
|
||||||
|
|
||||||
Select(sb, 1, 1000);
|
var sql222 = fsql.Select<Song>().Where(a => DateTime.Now.Subtract(a.create_time.Value).TotalHours > 0).ToSql();
|
||||||
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("更新:");
|
#region ET test
|
||||||
Update(sb, 1000, 1);
|
////var t31 = fsql.Select<xxx>().ToList();
|
||||||
Console.Write(sb.ToString());
|
//fsql.Select<Song>().First();
|
||||||
sb.Clear();
|
|
||||||
Update(sb, 1000, 10);
|
|
||||||
Console.Write(sb.ToString());
|
|
||||||
sb.Clear();
|
|
||||||
|
|
||||||
Update(sb, 1, 1000);
|
//time.Restart();
|
||||||
Console.Write(sb.ToString());
|
//var t3 = fsql.Select<Song>().ToList();
|
||||||
sb.Clear();
|
//time.Stop();
|
||||||
Update(sb, 1, 10000);
|
//sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*");
|
||||||
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("测试结束,按任意键退出...");
|
//time.Restart();
|
||||||
Console.ReadKey();
|
//var adoarr1 = fsql.Ado.ExecuteArray("select * from freesql_song");
|
||||||
}
|
//time.Stop();
|
||||||
|
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteArray Entity Counts: {adoarr1.Length}; ORM: FreeSql ExecuteArray*");
|
||||||
|
|
||||||
static void Select(StringBuilder sb, int forTime, int size) {
|
//time.Restart();
|
||||||
Stopwatch sw = new Stopwatch();
|
//var adolist1 = new List<Song>();
|
||||||
sw.Restart();
|
//fsql.Ado.ExecuteReader(dr =>
|
||||||
for (var a = 0; a < forTime; a++)
|
//{
|
||||||
fsql.Select<Song>().Limit(size).ToList();
|
// var xim = new Song();
|
||||||
sw.Stop();
|
// dr.GetValue(0)?.GetType();
|
||||||
sb.AppendLine($"FreeSql Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
// 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*");
|
||||||
|
|
||||||
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();
|
//time.Restart();
|
||||||
for (var a = 0; a < forTime; a++) {
|
//adolist1 = new List<Song>();
|
||||||
using (var db = new SongContext()) {
|
//fsql.Ado.ExecuteReader(dr =>
|
||||||
db.Songs.Take(size).AsNoTracking().ToList();
|
//{
|
||||||
}
|
// var xim = new Song();
|
||||||
}
|
// var v1 = dr.GetValue(0);
|
||||||
sw.Stop();
|
// var locvalue = (object)v1;
|
||||||
sb.AppendLine($"EFCore Select {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms\r\n");
|
// if (locvalue == null || locvalue == DBNull.Value) xim.Id = default;
|
||||||
}
|
// else
|
||||||
|
// {
|
||||||
|
// if (locvalue is int iv) xim.Id = iv;
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// if (locvalue is string)
|
||||||
|
// {
|
||||||
|
|
||||||
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,
|
// v1 = dr.GetValue(1);
|
||||||
Title = $"Insert_{a}",
|
// locvalue = (object)v1;
|
||||||
Url = $"Url_{a}"
|
// 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)
|
||||||
|
// {
|
||||||
|
|
||||||
//预热
|
// }
|
||||||
fsql.Insert(songs.First()).ExecuteAffrows();
|
// }
|
||||||
sugar.Insertable(songs.First()).ExecuteCommand();
|
// }
|
||||||
using (var db = new SongContext()) {
|
// v1 = dr.GetValue(2);
|
||||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
// locvalue = (object)v1;
|
||||||
db.Songs.AddRange(songs.First());
|
// if (locvalue == null || locvalue == DBNull.Value) xim.Is_deleted = default;
|
||||||
db.SaveChanges();
|
// else
|
||||||
}
|
// {
|
||||||
Stopwatch sw = new Stopwatch();
|
// if (locvalue is bool bl) xim.Is_deleted = bl;
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// if (locvalue is string)
|
||||||
|
// {
|
||||||
|
|
||||||
sw.Restart();
|
// }
|
||||||
for (var a = 0; a < forTime; a++) {
|
// }
|
||||||
fsql.Insert(songs).ExecuteAffrows();
|
// }
|
||||||
//using (var db = new FreeSongContext()) {
|
// v1 = dr.GetValue(3);
|
||||||
// //db.Configuration.AutoDetectChangesEnabled = false;
|
// locvalue = (object)v1;
|
||||||
// db.Songs.AddRange(songs.ToArray());
|
// if (locvalue == null || locvalue == DBNull.Value) xim.Title = default;
|
||||||
// db.SaveChanges();
|
// else
|
||||||
//}
|
// {
|
||||||
}
|
// if (locvalue is string str) xim.Title = str;
|
||||||
sw.Stop();
|
// else
|
||||||
sb.AppendLine($"FreeSql Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
// {
|
||||||
|
// if (locvalue is string)
|
||||||
|
// {
|
||||||
|
|
||||||
sw.Restart();
|
// }
|
||||||
Exception sugarEx = null;
|
// }
|
||||||
try {
|
// }
|
||||||
for (var a = 0; a < forTime; a++)
|
// v1 = dr.GetValue(4);
|
||||||
sugar.Insertable(songs.ToArray()).ExecuteCommand();
|
// locvalue = (object)v1;
|
||||||
} catch (Exception ex) {
|
// if (locvalue == null || locvalue == DBNull.Value) xim.Url = default;
|
||||||
sugarEx = ex;
|
// else
|
||||||
}
|
// {
|
||||||
sw.Stop();
|
// if (locvalue is string str) xim.Url = str;
|
||||||
sb.AppendLine($"SqlSugar Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms" + (sugarEx != null ? $"成绩无效,错误:{sugarEx.Message}" : ""));
|
// else
|
||||||
|
// {
|
||||||
|
// if (locvalue is string)
|
||||||
|
// {
|
||||||
|
|
||||||
sw.Restart();
|
// }
|
||||||
for (var a = 0; a < forTime; a++) {
|
// }
|
||||||
|
// }
|
||||||
|
// adolist1.Add(xim);
|
||||||
|
//}, "select * from freesql_song");
|
||||||
|
//time.Stop();
|
||||||
|
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReaderObject Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReaderObject*");
|
||||||
|
|
||||||
using (var db = new SongContext()) {
|
////var type = typeof(Song);
|
||||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
////var myfuncParam1 = Expression.Parameter(typeof(object[]), "values");
|
||||||
db.Songs.AddRange(songs.ToArray());
|
////var retExp = Expression.Variable(type, "ret");
|
||||||
db.SaveChanges();
|
////var objExp = Expression.Variable(typeof(object), "obj");
|
||||||
}
|
////var returnTarget = Expression.Label(type);
|
||||||
}
|
////var myfuncBody = Expression.Block(
|
||||||
sw.Stop();
|
//// new[] { retExp, objExp },
|
||||||
sb.AppendLine($"EFCore Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms\r\n");
|
//// 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*");
|
||||||
|
|
||||||
static void Update(StringBuilder sb, int forTime, int size) {
|
|
||||||
Stopwatch sw = new Stopwatch();
|
|
||||||
|
|
||||||
var songs = fsql.Select<Song>().Limit(size).ToList();
|
////var methodDrgv = typeof(DbDataReader).GetMethod("GetValue");
|
||||||
sw.Restart();
|
////var myfunc2Param1 = Expression.Parameter(typeof(DbDataReader), "dr");
|
||||||
for (var a = 0; a < forTime; a++) {
|
////var myfunc2Body = Expression.Block(
|
||||||
fsql.Update<Song>().SetSource(songs).ExecuteAffrows();
|
//// new[] { retExp, objExp },
|
||||||
}
|
//// Expression.Assign(retExp, type.InternalNewExpression()),
|
||||||
sw.Stop();
|
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(0))),
|
||||||
sb.AppendLine($"FreeSql Update {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
|
//// 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*");
|
||||||
|
|
||||||
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}" : ""));
|
|
||||||
|
|
||||||
using (var db = new SongContext()) {
|
//time.Restart();
|
||||||
songs = db.Songs.Take(size).AsNoTracking().ToList();
|
//adolist1 = new List<Song>();
|
||||||
}
|
//fsql.Ado.ExecuteReader(dr =>
|
||||||
sw.Restart();
|
//{
|
||||||
for (var a = 0; a < forTime; a++) {
|
// 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*");
|
||||||
|
|
||||||
using (var db = new SongContext()) {
|
//time.Restart();
|
||||||
//db.Configuration.AutoDetectChangesEnabled = false;
|
//adolist1 = new List<Song>();
|
||||||
db.Songs.UpdateRange(songs.ToArray());
|
//fsql.Ado.ExecuteReader(dr =>
|
||||||
db.SaveChanges();
|
//{
|
||||||
}
|
// var xim = new Song();
|
||||||
}
|
// Utils.GetDataReaderValue(typeof(int), dr.GetValue(0));
|
||||||
sw.Stop();
|
// Utils.GetDataReaderValue(typeof(DateTime), dr.GetValue(1));
|
||||||
sb.AppendLine($"EFCore Update {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms\r\n");
|
// 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*");
|
||||||
|
|
||||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song")]
|
|
||||||
[SugarTable("sugar_song")]
|
|
||||||
[Table("efcore_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; }
|
|
||||||
|
|
||||||
[SugarColumn(IsIgnore = true)]
|
////time.Restart();
|
||||||
[NotMapped]
|
////adolist1 = new List<Song>();
|
||||||
public virtual ICollection<Tag> Tags { get; set; }
|
////fsql.Ado.ExecuteReader(dr =>
|
||||||
}
|
////{
|
||||||
[FreeSql.DataAnnotations.Table(Name = "freesql_song_tag")]
|
//// var xim = new Song();
|
||||||
[SugarTable("sugar_song_tag")]
|
//// Utils.GetConvertValue(typeof(int), dr.GetValue(0));
|
||||||
[Table("efcore_song_tag")]
|
//// Utils.GetConvertValue(typeof(DateTime), dr.GetValue(1));
|
||||||
public class Song_tag {
|
//// Utils.GetConvertValue(typeof(bool), dr.GetValue(2));
|
||||||
public int Song_id { get; set; }
|
//// Utils.GetConvertValue(typeof(string), dr.GetValue(3));
|
||||||
[SugarColumn(IsIgnore = true)]
|
//// Utils.GetConvertValue(typeof(string), dr.GetValue(4));
|
||||||
[NotMapped]
|
//// adolist1.Add(xim);
|
||||||
public virtual Song Song { get; set; }
|
////}, "select * from freesql_song");
|
||||||
|
////time.Stop();
|
||||||
|
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader11112222 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader11112222*");
|
||||||
|
|
||||||
public int Tag_id { get; set; }
|
|
||||||
[SugarColumn(IsIgnore = true)]
|
|
||||||
[NotMapped]
|
|
||||||
public virtual Tag Tag { get; set; }
|
|
||||||
}
|
|
||||||
[FreeSql.DataAnnotations.Table(Name = "freesql_tag")]
|
|
||||||
[SugarTable("sugar_tag")]
|
|
||||||
[Table("efcore_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; }
|
|
||||||
[SugarColumn(IsIgnore = true)]
|
|
||||||
[NotMapped]
|
|
||||||
public virtual Tag Parent { get; set; }
|
|
||||||
|
|
||||||
public decimal? Ddd { get; set; }
|
//time.Restart();
|
||||||
public string Name { get; set; }
|
//adolist1 = new List<Song>();
|
||||||
|
//fsql.Ado.ExecuteReader(dr =>
|
||||||
|
//{
|
||||||
|
// var values = new object[dr.FieldCount];
|
||||||
|
// dr.GetValues(values);
|
||||||
|
|
||||||
[SugarColumn(IsIgnore = true)]
|
// var xim = new Song();
|
||||||
[NotMapped]
|
// xim.Id = (int)Utils.GetDataReaderValue(typeof(int), values[0]);
|
||||||
public virtual ICollection<Song> Songs { get; set; }
|
// xim.Create_time = (DateTime)Utils.GetDataReaderValue(typeof(DateTime), values[1]);
|
||||||
[SugarColumn(IsIgnore = true)]
|
// xim.Is_deleted = (bool)Utils.GetDataReaderValue(typeof(bool), values[2]);
|
||||||
[NotMapped]
|
// xim.Title = (string)Utils.GetDataReaderValue(typeof(string), values[3]);
|
||||||
public virtual ICollection<Tag> Tags { get; set; }
|
// 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, 100, 1);
|
||||||
|
Console.Write(sb.ToString());
|
||||||
|
sb.Clear();
|
||||||
|
Insert(sb, 100, 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, 100, 1);
|
||||||
|
Console.Write(sb.ToString());
|
||||||
|
sb.Clear();
|
||||||
|
Select(sb, 100, 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, 100, 1);
|
||||||
|
Console.Write(sb.ToString());
|
||||||
|
sb.Clear();
|
||||||
|
Update(sb, 100, 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();
|
||||||
|
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 .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}"
|
||||||
|
});
|
||||||
|
|
||||||
|
//预热
|
||||||
|
fsql.Insert(songs.First()).ExecuteAffrows();
|
||||||
|
sugar.Insertable(songs.First()).ExecuteCommand();
|
||||||
|
using (var db = new SongContext())
|
||||||
|
{
|
||||||
|
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||||
|
//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++)
|
||||||
|
{
|
||||||
|
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}" : ""));
|
||||||
|
|
||||||
|
sw.Restart();
|
||||||
|
for (var a = 0; a < forTime; a++)
|
||||||
|
{
|
||||||
|
|
||||||
|
using (var db = new SongContext())
|
||||||
|
{
|
||||||
|
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||||
|
//db.Songs.AddRange(songs.ToArray());
|
||||||
|
//db.SaveChanges(); //.net5.0 throw Microsoft.EntityFrameworkCore.DbUpdateException
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sw.Stop();
|
||||||
|
sb.AppendLine($"EFCore Insert {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms .net5.0无效\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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}" : ""));
|
||||||
|
|
||||||
|
using (var db = new SongContext())
|
||||||
|
{
|
||||||
|
songs = db.Songs.Take(size).AsNoTracking().ToList();
|
||||||
|
}
|
||||||
|
sw.Restart();
|
||||||
|
for (var a = 0; a < forTime; a++)
|
||||||
|
{
|
||||||
|
|
||||||
|
using (var db = new SongContext())
|
||||||
|
{
|
||||||
|
//db.Configuration.AutoDetectChangesEnabled = false;
|
||||||
|
//db.Songs.UpdateRange(songs.ToArray());
|
||||||
|
//db.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sw.Stop();
|
||||||
|
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
|
||||||
|
{
|
||||||
|
[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; }
|
||||||
|
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual ICollection<Tag> Tags { get; set; }
|
||||||
|
}
|
||||||
|
[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; }
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual Song Song { get; set; }
|
||||||
|
|
||||||
|
public int tag_id { get; set; }
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual Tag Tag { get; set; }
|
||||||
|
}
|
||||||
|
[FreeSql.DataAnnotations.Table(Name = "freesql_tag")]
|
||||||
|
[SugarTable("sugar_tag")]
|
||||||
|
[Table("efcore_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; }
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual Tag Parent { get; set; }
|
||||||
|
|
||||||
|
public decimal? ddd { get; set; }
|
||||||
|
public string name { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual ICollection<Song> Songs { get; set; }
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
[NotMapped]
|
||||||
|
public virtual ICollection<Tag> Tags { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,29 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.3" />
|
<PackageReference Include="Dapper" Version="2.0.35" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.1.0" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.0" />
|
||||||
<PackageReference Include="sqlSugarCore" Version="4.9.9.3" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
|
||||||
</ItemGroup>
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.0" />
|
||||||
|
<PackageReference Include="sqlSugarCore" Version="5.0.1.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||||
</ItemGroup>
|
<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>
|
<ItemGroup>
|
||||||
<Reference Include="Microsoft.EntityFrameworkCore">
|
<Reference Include="Microsoft.EntityFrameworkCore">
|
||||||
<HintPath>..\..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.entityframeworkcore\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.entityframeworkcore\2.2.0\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
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,56 +4,66 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace restful.Controllers {
|
namespace restful.Controllers
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
[Route("restapi/[controller]")]
|
[Route("restapi/[controller]")]
|
||||||
public class SongsController : Controller {
|
public class SongsController : Controller
|
||||||
|
{
|
||||||
|
|
||||||
IFreeSql _fsql;
|
IFreeSql _fsql;
|
||||||
|
|
||||||
public SongsController(IFreeSql fsql) {
|
public SongsController(IFreeSql fsql)
|
||||||
_fsql = fsql;
|
{
|
||||||
}
|
_fsql = fsql;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[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();
|
{
|
||||||
}
|
return _fsql.Select<Song>().WhereIf(!string.IsNullOrEmpty(key), a => a.Title.Contains(key)).Page(page, limit).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
[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();
|
{
|
||||||
}
|
return _fsql.Select<Song>().Where(a => a.Id == id).ToOneAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public class ModelSong {
|
public class ModelSong
|
||||||
public string title { get; set; }
|
{
|
||||||
}
|
public string title { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost, ProducesResponseType(201)]
|
[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();
|
var ret = await _fsql.Insert<Song>().AppendData(new Song { Title = model.title }).ExecuteInsertedAsync();
|
||||||
}
|
return ret.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPut("{id}")]
|
[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();
|
var ret = await _fsql.Update<Song>().SetSource(new Song { Id = id, Title = model.title }).ExecuteUpdatedAsync();
|
||||||
}
|
return ret.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPatch("{id}")]
|
[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 up = _fsql.Update<Song>().Where(a => a.Id == id);
|
||||||
var ret = await up.ExecuteUpdatedAsync();
|
if (!string.IsNullOrEmpty(title)) up.Set(a => a.Title, title);
|
||||||
return ret.FirstOrDefault();
|
var ret = await up.ExecuteUpdatedAsync();
|
||||||
}
|
return ret.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpDelete("{id}"), ProducesResponseType(204)]
|
[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();
|
var ret = await _fsql.Delete<Song>().Where(a => a.Id == id).ExecuteDeletedAsync();
|
||||||
}
|
return ret.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
using FreeSql.DataAnnotations;
|
using FreeSql.DataAnnotations;
|
||||||
|
|
||||||
namespace restful.Entitys {
|
namespace restful.Entitys
|
||||||
public class Song {
|
{
|
||||||
|
public class Song
|
||||||
|
{
|
||||||
|
|
||||||
[Column(IsIdentity = true)]
|
[Column(IsIdentity = true)]
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
{
|
{
|
||||||
"iisSettings": {
|
"iisSettings": {
|
||||||
"windowsAuthentication": false,
|
"windowsAuthentication": false,
|
||||||
"anonymousAuthentication": true,
|
"anonymousAuthentication": true,
|
||||||
"iisExpress": {
|
"iisExpress": {
|
||||||
"applicationUrl": "http://localhost:49778/",
|
"applicationUrl": "http://localhost:49778/",
|
||||||
"sslPort": 0
|
"sslPort": 0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"profiles": {
|
|
||||||
"IIS Express": {
|
|
||||||
"commandName": "IISExpress",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"FreeSql.RESTful.Demo": {
|
"profiles": {
|
||||||
"commandName": "Project",
|
"IIS Express": {
|
||||||
"launchBrowser": true,
|
"commandName": "IISExpress",
|
||||||
"environmentVariables": {
|
"launchBrowser": true,
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"environmentVariables": {
|
||||||
},
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
"applicationUrl": "http://localhost:49779/"
|
}
|
||||||
|
},
|
||||||
|
"FreeSql.RESTful.Demo": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:49779/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,67 +1,57 @@
|
|||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Swashbuckle.AspNetCore.Swagger;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace restful {
|
namespace restful
|
||||||
public class Startup {
|
{
|
||||||
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory) {
|
public class Startup
|
||||||
Configuration = configuration;
|
{
|
||||||
|
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
|
||||||
Fsql = new FreeSql.FreeSqlBuilder()
|
Fsql = new FreeSql.FreeSqlBuilder()
|
||||||
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10")
|
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10")
|
||||||
.UseAutoSyncStructure(true)
|
.UseAutoSyncStructure(true)
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
Fsql.Aop.CurdAfter = (s, e) => {
|
Fsql.Aop.CurdAfter += (s, e) =>
|
||||||
if (e.ElapsedMilliseconds > 200) {
|
{
|
||||||
//记录日志
|
if (e.ElapsedMilliseconds > 200)
|
||||||
//发送短信给负责人
|
{
|
||||||
}
|
//记录日志
|
||||||
};
|
//发送短信给负责人
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//Fsql.Aop.Where = (s, e) => {
|
//Fsql.Aop.Where = (s, e) => {
|
||||||
// if (e.Parameters[0]?.ToString() == "1")
|
// if (e.Parameters[0]?.ToString() == "1")
|
||||||
// e.IsCancel = true;
|
// e.IsCancel = true;
|
||||||
//};
|
//};
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
public IFreeSql Fsql { get; }
|
public IFreeSql Fsql { get; }
|
||||||
|
|
||||||
public void ConfigureServices(IServiceCollection services) {
|
public void ConfigureServices(IServiceCollection services)
|
||||||
services.AddSingleton<IFreeSql>(Fsql);
|
{
|
||||||
|
services.AddSingleton<IFreeSql>(Fsql);
|
||||||
|
services.AddControllersWithViews();
|
||||||
|
}
|
||||||
|
|
||||||
services.AddMvc();
|
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
||||||
services.AddSwaggerGen(options => {
|
{
|
||||||
options.SwaggerDoc("v1", new Info {
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
Version = "v1",
|
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
||||||
Title = "FreeSql.RESTful API"
|
Console.InputEncoding = Encoding.GetEncoding("GB2312");
|
||||||
});
|
|
||||||
//options.IncludeXmlComments(xmlPath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) {
|
app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
app.UseDeveloperExceptionPage();
|
||||||
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
app.UseRouting();
|
||||||
Console.InputEncoding = Encoding.GetEncoding("GB2312");
|
app.UseEndpoints(a => a.MapControllers());
|
||||||
|
}
|
||||||
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");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Debug",
|
"Default": "Debug",
|
||||||
"System": "Information",
|
"System": "Information",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Information"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Warning"
|
"Default": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*"
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||||
<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" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</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" />
|
||||||
|
|