initial commit

This commit is contained in:
tk 2024-11-13 18:18:28 +08:00
commit 013f35e296
1500 changed files with 443723 additions and 0 deletions

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
[*.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
# CS8618: 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
dotnet_diagnostic.CS8618.severity = none
charset = utf-8-bom

63
.gitattributes vendored Normal file
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

31
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,31 @@
---
name: "Bug Report 🐛"
about: 这里只能提交 Bug提交其他无关信息会被关闭
title: ''
labels: Bug
assignees: ''
---
<!--
以下为必读项,不仔细阅读会导致你的 Issue 被关闭
1. 该分类下只能提交 Bug如果要询问使用方法等请前往讨论区https://github.com/dotnetcore/FreeSql/discussions
2. FreeSql写了许多文档在提问题前麻烦先查看[常见问题](https://freesql.net/reference/faq.html)
3. 不完整的信息将不会得到任何回复!发布问题后,请保持对 issue 的关注,有时会有需要进一步沟通的信息,很长时间内没有得到答复的 issue 将被关闭。
4. 提供可重现的代码,至少应描述以下信息 -->
#### 问题描述及重现代码:
```c#
// c# code
```
#### 数据库版本
#### 安装的Nuget包
#### .net framework/. net core 及具体版本

View File

@ -0,0 +1,33 @@
---
name: "Feature Request 🚀"
about: 这里只能提交 Feature 请求,提交其他无关信息会被关闭
title: ''
labels: Feature
assignees: ''
---
<!--
以下为必读项,不仔细阅读会导致你的 Issue 被关闭
1. 该分类下只能提交 Feature如果要询问使用方法等请前往讨论区https://github.com/dotnetcore/FreeSql/discussions
2. 请尽量详细的描述清楚你的需求
-->
#### Feature 特性
```c#
// c# code
```
#### 简要描述原因
```c#
// c# code
```
#### 使用场景
```c#
// c# code
```

41
.github/workflows/docfx.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: Docfx Deploy
on:
workflow_dispatch:
push:
branches: [master]
jobs:
generate-docs:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup .NET Core
uses: actions/setup-dotnet@v1
with:
dotnet-version: 7.0.x
- name: Remove Examples
run: dotnet sln FreeSql.sln remove (ls -r Examples/**/*.csproj)
- name: Remove FreeSql.Tests
run: dotnet sln FreeSql.sln remove (ls -r FreeSql.Tests/**/*.csproj)
- name: Install dependencies
run: dotnet restore .\FreeSql.sln
- name: Build solution
run: dotnet build --configuration Release --no-restore .\FreeSql.sln
- name: Setup DocFX
uses: crazy-max/ghaction-chocolatey@v1
with:
args: install docfx
- name: DocFX Build
working-directory: docs
run: docfx docfx.json
continue-on-error: false
- name: Publish
if: github.event_name == 'push'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: docs/_site
force_orphan: true

17
.github/workflows/gitee-mirror.yml vendored Normal file
View 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"

251
.gitignore vendored Normal file
View File

@ -0,0 +1,251 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
FreeSql.xml
FreeSql.DbContext.xml
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
package-lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml

21
Directory.Build.props Normal file
View File

@ -0,0 +1,21 @@
<Project>
<PropertyGroup>
<RepositoryUrl>https://github.com/dotnetcore/FreeSql</RepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
</PropertyGroup>
<!--
经常出于版本交叉问题,暂时关闭,在每个项目上设置版本号
<PropertyGroup>
<Version>3.2.833</Version>
</PropertyGroup>
-->
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup>
</Project>

View File

@ -0,0 +1,117 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using FreeSql;
using FreeSql.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
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]
public async Task<object> Get([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
[FromServices] SongService serviceSong)
{
//repoSong.Insert(new Song());
//repoDetail.Insert(new Detail());
//repoSong2.Insert(new Song());
//serviceSong.Test1();
await serviceSong.Test11();
return "111";
}
[HttpGet("2")]
[Transactional]
public async Task<object> GetAsync([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
[FromServices] SongService serviceSong)
{
await repoSong.InsertAsync(new Song());
await repoDetail.InsertAsync(new Detail());
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 void Test1()
{
_repoSong.Insert(new Song());
_repoDetail.Insert(new Detail());
_repoSong2.Insert(new Song());
}
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
public Task Test11()
{
return Task.Delay(TimeSpan.FromSeconds(1)).ContinueWith(t =>
_repoSong.InsertAsync(new Song()));
}
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
public async Task Test2()
{
await _repoSong.InsertAsync(new Song());
await _repoDetail.InsertAsync(new Detail());
await _repoSong2.InsertAsync(new Song());
}
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
public async 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; }
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using FreeSql;
using FreeSql.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace aspnetcore_transaction.Domain
{
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; }
}
}

View File

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Rougamo />
</Weavers>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Rougamo" minOccurs="0" maxOccurs="1" type="xs:anyType" />
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Hosting;
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)
.ConfigureLogging(loggerBuilder =>
{
loggerBuilder.SetMinimumLevel(LogLevel.Critical);
//loggerBuilder.ClearProviders();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
;
}
}

View File

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:64375/",
"sslPort": 44336
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"aspnetcore_transaction": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using aspnetcore_transaction.Domain;
using FreeSql;
using FreeSql.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace aspnetcore_transaction.Services
{
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 void Test1()
{
_repoSong.Insert(new Song());
_repoDetail.Insert(new Detail());
_repoSong2.Insert(new Song());
}
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
public Task Test11()
{
return Task.Delay(TimeSpan.FromSeconds(1)).ContinueWith(t =>
_repoSong.InsertAsync(new Song()));
}
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
public async Task Test2()
{
await _repoSong.InsertAsync(new Song());
await _repoDetail.InsertAsync(new Detail());
await _repoSong2.InsertAsync(new Song());
}
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
public async Task<object> Test3()
{
await _repoSong.InsertAsync(new Song());
await _repoDetail.InsertAsync(new Detail());
await _repoSong2.InsertAsync(new Song());
return "123";
}
}
}

View File

@ -0,0 +1,72 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using aspnetcore_transaction.Controllers;
using FreeSql;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace aspnetcore_transaction
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
Fsql = new FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=50;TrustServerCertificate=true")
.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");
if (e.Exception != null && e.Exception.Message.StartsWith("【主库】状态不可用,等待后台检查程序恢复方可使用。") == false) Console.WriteLine(e.Exception.Message + " === " + Fsql.Ado.MasterPool.Statistics);
};
}
public IConfiguration Configuration { get; }
public static IFreeSql Fsql { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
ThreadPool.SetMinThreads(1000, 1000);
services.AddControllersWithViews();
services.AddSingleton<IFreeSql>(Fsql);
services.AddScoped<UnitOfWorkManager>();
services.AddFreeRepository(null, typeof(Startup).Assembly);
////批量注入
//foreach (var repo in typeof(Startup).Assembly.GetTypes()
// .Where(a => a.IsAbstract == false && typeof(IBaseRepository).IsAssignableFrom(a)))
// services.AddScoped(repo);
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.Use(async (context, next) =>
{
TransactionalAttribute.SetServiceProvider(context.RequestServices);
await next();
});
app.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
app.UseDeveloperExceptionPage();
app.UseRouting();
app.UseEndpoints(a => a.MapControllers());
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
using Rougamo.Context;
namespace FreeSql
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class TransactionalAttribute : Rougamo.MoAttribute
{
public Propagation Propagation { get; set; } = Propagation.Required;
public IsolationLevel IsolationLevel { get => m_IsolationLevel.Value; set => m_IsolationLevel = value; }
IsolationLevel? m_IsolationLevel;
static AsyncLocal<IServiceProvider> m_ServiceProvider = new AsyncLocal<IServiceProvider>();
public static void SetServiceProvider(IServiceProvider serviceProvider) => m_ServiceProvider.Value = serviceProvider;
IUnitOfWork _uow;
public override void OnEntry(MethodContext context)
{
var uowManager = m_ServiceProvider.Value.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager;
_uow = uowManager.Begin(this.Propagation, this.m_IsolationLevel);
}
public override void OnExit(MethodContext context)
{
if (typeof(Task).IsAssignableFrom(context.RealReturnType))
{
((Task)context.ReturnValue).ContinueWith(t => _OnExit());
return;
}
_OnExit();
void _OnExit()
{
try
{
if (context.Exception == null) _uow.Commit();
else _uow.Rollback();
}
catch { }
finally
{
_uow.Dispose();
}
}
}
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.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="FreeSql.DbContext" Version="3.2.802" />
<PackageReference Include="FreeSql.Provider.Sqlite" Version="3.2.802" />
<PackageReference Include="Rougamo.Fody" Version="1.1.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
</ItemGroup>
</Project>

View 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="P:aspnetcore_transaction.Domain.Song.Id">
<summary>
自增
</summary>
</member>
</members>
</doc>

View File

@ -0,0 +1,36 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.ComponentModel;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 角色声明
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class AspNetRoleClaims
{
[DisplayName("ID")]
[JsonProperty, Column(IsPrimary = true, IsIdentity = true)]
public int Id { get; set; }
[DisplayName("角色ID")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string RoleId { get; set; }
[DisplayName("角色声明")]
[JsonProperty, Column(StringLength = -2)]
public string ClaimType { get; set; }
[DisplayName("值")]
[JsonProperty, Column(StringLength = -2)]
public string ClaimValue { get; set; }
[Navigate(nameof(RoleId))]
public virtual AspNetRoles AspNetRoles { get; set; }
}
}

View File

@ -0,0 +1,39 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.ComponentModel;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 角色定义
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class AspNetRoles
{
[DisplayName("ID")]
[JsonProperty, Column(StringLength = -2, IsPrimary = true, IsNullable = false)]
public string Id { get; set; }
[DisplayName("角色")]
[JsonProperty, Column(StringLength = -2)]
public string Name { get; set; }
[DisplayName("标准化名称")]
[JsonProperty, Column(StringLength = -2)]
public string NormalizedName { get; set; }
[DisplayName("并发票据")]
[JsonProperty, Column(StringLength = -2)]
public string ConcurrencyStamp { get; set; }
//导航属性
[Navigate(nameof(AspNetUserRoles.RoleId))]
[DisplayName("角色表")]
public virtual List<AspNetUserRoles> AspNetUserRoless { get; set; }
}
}

View File

@ -0,0 +1,39 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.ComponentModel;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 用户声明
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class AspNetUserClaims
{
[DisplayName("ID")]
[JsonProperty, Column(IsPrimary = true, IsIdentity = true)]
public int Id { get; set; }
[DisplayName("用户ID")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string UserId { get; set; }
[DisplayName("声明类型")]
[JsonProperty, Column(StringLength = -2)]
public string ClaimType { get; set; }
[DisplayName("值")]
[JsonProperty, Column(StringLength = -2)]
public string ClaimValue { get; set; }
/// <summary>
/// 用户
/// </summary>
[Navigate(nameof(UserId))]
public virtual AspNetUsers AspNetUsers { get; set; }
}
}

View File

@ -0,0 +1,39 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.ComponentModel;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 用户登录
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class AspNetUserLogins
{
[DisplayName("外联登录")]
[JsonProperty, Column(StringLength = -2, IsPrimary = true, IsNullable = false)]
public string LoginProvider { get; set; }
[DisplayName("用户ID")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string UserId { get; set; }
[DisplayName("外联Key")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string ProviderKey { get; set; }
[DisplayName("外联名称")]
[JsonProperty, Column(StringLength = -2)]
public string ProviderDisplayName { get; set; }
/// <summary>
/// 用户
/// </summary>
[Navigate(nameof(UserId))]
public virtual AspNetUsers AspNetUsers { get; set; }
}
}

View File

@ -0,0 +1,45 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.ComponentModel;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 角色表
/// <para>存储向哪些用户分配哪些角色</para>
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class AspNetUserRoles
{
[DisplayName("用户ID")]
[JsonProperty, Column(StringLength = -2, IsPrimary = true, IsNullable = false)]
public string UserId { get; set; }
[JsonProperty, Column(IsIgnore = true)]
[DisplayName("用户")]
public string UserName { get => roleName ?? (AspNetUserss?.UserName); set => userName = value; }
string userName;
[DisplayName("角色ID")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string RoleId { get; set; }
[JsonProperty, Column(IsIgnore = true)]
[DisplayName("角色名称")]
public string RoleName { get => roleName ?? (AspNetRoless?.Name); set => roleName = value; }
string roleName;
[DisplayName("角色定义")]
[Navigate(nameof(RoleId))]
public virtual AspNetRoles AspNetRoless { get; set; }
[DisplayName("用户表")]
[Navigate(nameof(UserId))]
public virtual AspNetUsers AspNetUserss { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.ComponentModel;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 用户令牌
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class AspNetUserTokens
{
[DisplayName("用户ID")]
[JsonProperty, Column(StringLength = -2, IsPrimary = true, IsNullable = false)]
public string UserId { get; set; }
[DisplayName("名称")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string Name { get; set; }
[DisplayName("外部登录提供程序")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string LoginProvider { get; set; }
[DisplayName("值")]
[JsonProperty, Column(StringLength = -2)]
public string Value { get; set; }
[Navigate(nameof(UserId))]
public virtual AspNetUsers AspNetUsers { get; set; }
}
}

View File

@ -0,0 +1,149 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 用户表
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class AspNetUsers
{
[DisplayName("用户ID")]
[JsonProperty, Column(StringLength = -2, IsPrimary = true, IsNullable = false)]
public string Id { get; set; }
[JsonProperty, Column(StringLength = -2)]
[DisplayName("用户名")]
public string UserName { get; set; }
[JsonProperty, Column(IsIgnore = true)]
[DisplayName("角色")]
public string RoleName { get => roleName ?? (AspNetUserRoless != null ? string.Join(",", AspNetUserRoless?.Select(a => a.RoleName ?? a.RoleId).ToList()) : ""); set => roleName = value; }
string roleName;
[JsonProperty, Column(StringLength = -2)]
public string Email { get; set; }
[DisplayName("电话")]
[JsonProperty, Column(StringLength = -2)]
public string PhoneNumber { get; set; }
[DisplayName("自定义名称")]
[JsonProperty, Column(StringLength = -2)]
public string Name { get; set; }
[DisplayName("自定义角色")]
[JsonProperty, Column(StringLength = -2)]
public string UserRole { get; set; }
[DisplayName("密码哈希")]
[JsonProperty, Column(StringLength = -2)]
public string PasswordHash { get; set; }
[DisplayName("电子邮件已确认")]
[JsonProperty]
public int EmailConfirmed { get; set; }
[DisplayName("电话号码已确认")]
[JsonProperty]
public int PhoneNumberConfirmed { get; set; }
[DisplayName("锁定结束")]
[JsonProperty, Column(StringLength = -2)]
public string LockoutEnd { get; set; }
[DisplayName("启用双因素登录")]
[JsonProperty]
public int TwoFactorEnabled { get; set; }
[DisplayName("并发票据")]
[JsonProperty, Column(StringLength = -2)]
public string ConcurrencyStamp { get; set; }
[DisplayName("防伪印章")]
[JsonProperty, Column(StringLength = -2)]
public string SecurityStamp { get; set; }
[DisplayName("标准化电子邮件")]
[JsonProperty, Column(StringLength = -2)]
public string NormalizedEmail { get; set; }
[DisplayName("标准化用户名")]
[JsonProperty, Column(StringLength = -2)]
public string NormalizedUserName { get; set; }
[DisplayName("启用锁定")]
[JsonProperty]
public int LockoutEnabled { get; set; }
[DisplayName("国家")]
[JsonProperty, Column(StringLength = -2)]
public string Country { get; set; }
[DisplayName("省")]
[JsonProperty, Column(StringLength = -2)]
public string Province { get; set; }
[DisplayName("城市")]
[JsonProperty, Column(StringLength = -2)]
public string City { get; set; }
[DisplayName("县")]
[JsonProperty, Column(StringLength = -2)]
public string County { get; set; }
[DisplayName("邮编")]
[JsonProperty, Column(StringLength = -2)]
public string Zip { get; set; }
[DisplayName("街道")]
[JsonProperty, Column(StringLength = -2)]
public string Street { get; set; }
[DisplayName("税号")]
[JsonProperty, Column(StringLength = -2)]
public string TaxNumber { get; set; }
[DisplayName("提供者")]
[JsonProperty, Column(StringLength = -2)]
public string provider { get; set; }
[DisplayName("UUID")]
[JsonProperty, Column(StringLength = -2)]
public string UUID { get; set; }
[DisplayName("生日")]
[JsonProperty, Column(StringLength = -2)]
public string DOB { get; set; }
[DisplayName("访问失败次数")]
[JsonProperty]
public int AccessFailedCount { get; set; }
//导航属性
[Navigate(nameof(AspNetUserRoles.UserId))]
[DisplayName("角色表")]
public virtual List<AspNetUserRoles> AspNetUserRoless { get; set; }
[Navigate(nameof(AspNetUserClaims.UserId))]
[DisplayName("用户声明")]
public virtual List<AspNetUserClaims> AspNetUserClaimss { get; set; }
[Navigate(nameof(AspNetUserLogins.UserId))]
[DisplayName("用户登录")]
public virtual List<AspNetUserLogins> AspNetUserLoginss { get; set; }
[JsonProperty, Column(IsIgnore = true)]
[DisplayName("1st角色")]
public string RoleName1st { get => roleName1st ?? ((AspNetUserRoless != null && AspNetUserRoless.Any()) ? AspNetUserRoless?.Select(a => a.RoleName ?? a.RoleId ?? "").First() : ""); set => roleName1st = value; }
string roleName1st;
}
}

View File

@ -0,0 +1,53 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 设备代码
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class DeviceCodes
{
[Display(Name = "用户代码")]
[JsonProperty, Column(StringLength = -2, IsPrimary = true, IsNullable = false)]
public string UserCode { get; set; }
[Display(Name = "设备代码")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string DeviceCode { get; set; }
[Display(Name = "主题编号")]
[JsonProperty, Column(StringLength = -2)]
public string SubjectId { get; set; }
[Display(Name = "会话编号")]
[JsonProperty, Column(StringLength = -2)]
public string SessionId { get; set; }
[Display(Name = "客户编号")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string ClientId { get; set; }
[Display(Name = "描述")]
[JsonProperty, Column(StringLength = -2)]
public string Description { get; set; }
[Display(Name = "创建时间")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string CreationTime { get; set; }
[Display(Name = "到期")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string Expiration { get; set; }
[DisplayName("数据")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string Data { get; set; }
}
}

View File

@ -0,0 +1,49 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.ComponentModel;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 密钥
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class Keys
{
[DisplayName("ID")]
[JsonProperty, Column(StringLength = -2, IsPrimary = true, IsNullable = false)]
public string Id { get; set; }
[DisplayName("版本")]
[JsonProperty]
public int Version { get; set; }
[DisplayName("创建")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string Created { get; set; }
[DisplayName("使用")]
[JsonProperty, Column(StringLength = -2)]
public string Use { get; set; }
[DisplayName("算法")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string Algorithm { get; set; }
[DisplayName("是X509证书")]
[JsonProperty]
public int IsX509Certificate { get; set; }
[DisplayName("数据保护")]
[JsonProperty]
public int DataProtected { get; set; }
[DisplayName("数据")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string Data { get; set; }
}
}

View File

@ -0,0 +1,57 @@
using FreeSql.DataAnnotations;
using Newtonsoft.Json;
using System.ComponentModel;
#nullable disable
namespace Densen.Models.ids
{
/// <summary>
/// 持久化保存
/// </summary>
[JsonObject(MemberSerialization.OptIn), Table(DisableSyncStructure = true)]
public partial class PersistedGrants
{
[DisplayName("键值")]
[JsonProperty, Column(StringLength = -2, IsPrimary = true, IsNullable = false)]
public string Key { get; set; }
[DisplayName("类型")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string Type { get; set; }
[DisplayName("主题编号")]
[JsonProperty, Column(StringLength = -2)]
public string SubjectId { get; set; }
[DisplayName("会话编号")]
[JsonProperty, Column(StringLength = -2)]
public string SessionId { get; set; }
[DisplayName("客户编号")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string ClientId { get; set; }
[DisplayName("描述")]
[JsonProperty, Column(StringLength = -2)]
public string Description { get; set; }
[DisplayName("创建时间")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string CreationTime { get; set; }
[DisplayName("到期")]
[JsonProperty, Column(StringLength = -2)]
public string Expiration { get; set; }
[DisplayName("消耗时间")]
[JsonProperty, Column(StringLength = -2)]
public string ConsumedTime { get; set; }
[DisplayName("数据")]
[JsonProperty, Column(StringLength = -2, IsNullable = false)]
public string Data { get; set; }
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.ComponentModel.DataAnnotations;
namespace Densen.Identity.Models
{
public class WebAppIdentityUser
{
/// <summary>
/// Full name
/// </summary>
[Display(Name = "全名")]
public string? Name { get; set; }
/// <summary>
/// Birth Date
/// </summary>
[Display(Name = "生日")]
public DateTime? DOB { get; set; }
[Display(Name = "识别码")]
public string? UUID { get; set; }
[Display(Name = "外联")]
public string? provider { get; set; }
[Display(Name = "税号")]
public string? TaxNumber { get; set; }
[Display(Name = "街道地址")]
public string? Street { get; set; }
[Display(Name = "邮编")]
public string? Zip { get; set; }
[Display(Name = "县")]
public string? County { get; set; }
[Display(Name = "城市")]
public string? City { get; set; }
[Display(Name = "省份")]
public string? Province { get; set; }
[Display(Name = "国家")]
public string? Country { get; set; }
[Display(Name = "类型")]
public string? UserRole { get; set; }
}
}

Binary file not shown.

View File

@ -0,0 +1,79 @@
using FreeSql;
using FreeSql.DataAnnotations;
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 IdentityUser1
{
[Column(IsIdentity = true)]
public int Id { get; set; }
[MaxLength(32)]
public string Username { get; set; }
[MaxLength(64), Column(InsertValueSql = "'defaultname'")]
public string Nickname { get; set; }
}
public class User1 : BaseEntity<User1, Guid>
{
public int GroupId { get; set; }
public UserGroup Group { get; set; }
public string[] Tags { 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(2000)]
public string Description { get; set; }
}
public class IdentityTable
{
[Column(IsIdentity = true, IsPrimary = true)]
public int id { get; set; }
public string name { get; set; }
}

View File

@ -0,0 +1,104 @@
using FreeSql.DataAnnotations;
using MessagePack;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
class MessagePackMapInfo
{
public Guid id { get; set; }
[MessagePackMap]
public MessagePackMap01 Info { get; set; }
}
[MessagePackObject]
public class MessagePackMap01
{
[Key(0)]
public string name { get; set; }
[Key(1)]
public string address { get;set; }
}
namespace FreeSql.DataAnnotations
{
public class MessagePackMapAttribute : Attribute { }
}
public static class FreeSqlMessagePackMapCoreExtensions
{
internal static int _isAoped = 0;
static ConcurrentDictionary<Type, bool> _dicTypes = new ConcurrentDictionary<Type, bool>();
static MethodInfo MethodMessagePackSerializerDeserialize = typeof(MessagePackSerializer).GetMethod("Deserialize", new[] { typeof(Type), typeof(ReadOnlyMemory<byte>), typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
static MethodInfo MethodMessagePackSerializerSerialize = typeof(MessagePackSerializer).GetMethod("Serialize", new[] { typeof(Type), typeof(object), typeof(MessagePackSerializerOptions), typeof(CancellationToken) });
static ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>> _dicMessagePackMapFluentApi = new ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>>();
static object _concurrentObj = new object();
public static ColumnFluent MessagePackMap(this ColumnFluent col)
{
_dicMessagePackMapFluentApi.GetOrAdd(col._entityType, et => new ConcurrentDictionary<string, bool>())
.GetOrAdd(col._property.Name, pn => true);
return col;
}
public static void UseMessagePackMap(this IFreeSql that)
{
UseMessagePackMap(that, MessagePackSerializerOptions.Standard);
}
public static void UseMessagePackMap(this IFreeSql that, MessagePackSerializerOptions settings)
{
if (Interlocked.CompareExchange(ref _isAoped, 1, 0) == 0)
{
FreeSql.Internal.Utils.GetDataReaderValueBlockExpressionSwitchTypeFullName.Add((LabelTarget returnTarget, Expression valueExp, Type type) =>
{
if (_dicTypes.ContainsKey(type))
return Expression.IfThenElse(
Expression.TypeIs(valueExp, type),
Expression.Return(returnTarget, valueExp),
Expression.Return(returnTarget, Expression.TypeAs(
Expression.Call(MethodMessagePackSerializerDeserialize,
Expression.Constant(type),
Expression.New(typeof(ReadOnlyMemory<byte>).GetConstructor(new[] { typeof(byte[]) }), Expression.Convert(valueExp, typeof(byte[]))),
Expression.Constant(settings, typeof(MessagePackSerializerOptions)),
Expression.Constant(default(CancellationToken), typeof(CancellationToken)))
, type))
);
return null;
});
}
that.Aop.ConfigEntityProperty += (s, e) =>
{
var isMessagePackMap = e.Property.GetCustomAttributes(typeof(MessagePackMapAttribute), false).Any() || _dicMessagePackMapFluentApi.TryGetValue(e.EntityType, out var tryjmfu) && tryjmfu.ContainsKey(e.Property.Name);
if (isMessagePackMap)
{
e.ModifyResult.MapType = typeof(byte[]);
e.ModifyResult.StringLength = -2;
if (_dicTypes.TryAdd(e.Property.PropertyType, true))
{
lock (_concurrentObj)
{
FreeSql.Internal.Utils.dicExecuteArrayRowReadClassOrTuple[e.Property.PropertyType] = true;
FreeSql.Internal.Utils.GetDataReaderValueBlockExpressionObjectToBytesIfThenElse.Add((LabelTarget returnTarget, Expression valueExp, Expression elseExp, Type type) =>
{
return Expression.IfThenElse(
Expression.TypeIs(valueExp, e.Property.PropertyType),
Expression.Return(returnTarget,
Expression.Call(MethodMessagePackSerializerSerialize,
Expression.Constant(e.Property.PropertyType, typeof(Type)),
Expression.Convert(valueExp, typeof(object)),
Expression.Constant(settings, typeof(MessagePackSerializerOptions)),
Expression.Constant(default(CancellationToken), typeof(CancellationToken)))
, typeof(object)),
elseExp);
});
}
}
}
};
}
}

View File

@ -0,0 +1,54 @@
using FreeSql;
using FreeSql.DataAnnotations;
using FreeSql.Internal;
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
class ModAsTableImpl : IAsTable
{
public ModAsTableImpl(IFreeSql fsql)
{
AllTables = Enumerable.Range(0, 9).Select(a => $"order_{a}").ToArray();
fsql.Aop.CommandBefore += (_, e) =>
{
e.Command.CommandText = Regex.Replace(e.Command.CommandText, @"/\*astable\([^\)]+\)*\/", "1=1");
};
}
public string[] AllTables { get; }
public string GetTableNameByColumnValue(object columnValue, bool autoExpand = false)
{
var modid = (int)columnValue;
return $"order_{(modid % 10)}";
}
public string[] GetTableNamesByColumnValueRange(object columnValue1, object columnValue2)
{
throw new NotImplementedException();
}
public IAsTableTableNameRangeResult GetTableNamesBySqlWhere(string sqlWhere, List<DbParameter> dbParams, SelectTableInfo tb, CommonUtils commonUtils)
{
var match = Regex.Match(sqlWhere, @"/\*astable\([^\)]+\)*\/");
if (match.Success == false) return new IAsTableTableNameRangeResult(AllTables, null, null);
var tables = match.Groups[1].Value.Split(',').Where(a => AllTables.Contains(a)).ToArray();
if (tables.Any() == false) return new IAsTableTableNameRangeResult(AllTables, null, null);
return new IAsTableTableNameRangeResult(tables, null, null);
}
public IAsTable SetDefaultAllTables(Func<string[], string[]> audit)
{
throw new NotImplementedException();
}
public IAsTable SetTableName(int index, string tableName)
{
throw new NotImplementedException();
}
}

File diff suppressed because one or more lines are too long

View 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; }
}
}

View 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
}
}

View 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; }
}
}

View File

@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DocumentationFile>base_entity.xml</DocumentationFile>
<WarningLevel>3</WarningLevel>
<NoWarn>1701;1702;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Confluent.Kafka" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Npgsql.NetTopologySuite" Version="6.0.4" />
<PackageReference Include="MessagePack" Version="2.4.35" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Extensions\FreeSql.Extensions.AggregateRoot\FreeSql.Extensions.AggregateRoot.csproj" />
<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="..\..\Extensions\FreeSql.Extensions.Linq\FreeSql.Extensions.Linq.csproj" />
<ProjectReference Include="..\..\FreeSql.Repository\FreeSql.Repository.csproj" />
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.ClickHouse\FreeSql.Provider.ClickHouse.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Dameng\FreeSql.Provider.Dameng.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Firebird\FreeSql.Provider.Firebird.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.MySqlConnector\FreeSql.Provider.MySqlConnector.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.QuestDb\FreeSql.Provider.QuestDb.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.SqliteCore\FreeSql.Provider.SqliteCore.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.SqlServer\FreeSql.Provider.SqlServer.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Xugu\FreeSql.Provider.Xugu.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="DmProvider">
<HintPath>..\..\Providers\FreeSql.Provider.Dameng\lib\DmProvider\netstandard2.0\DmProvider.dll</HintPath>
</Reference>
<Reference Include="XuguClient">
<HintPath>..\..\Providers\FreeSql.Provider.Xugu\lib\XuguClient\netstandard2.0\XuguClient.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,500 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>base_entity</name>
</assembly>
<members>
<member name="T:Densen.Models.ids.AspNetRoleClaims">
<summary>
角色声明
</summary>
</member>
<member name="T:Densen.Models.ids.AspNetRoles">
<summary>
角色定义
</summary>
</member>
<member name="T:Densen.Models.ids.AspNetUserClaims">
<summary>
用户声明
</summary>
</member>
<member name="P:Densen.Models.ids.AspNetUserClaims.AspNetUsers">
<summary>
用户
</summary>
</member>
<member name="T:Densen.Models.ids.AspNetUserLogins">
<summary>
用户登录
</summary>
</member>
<member name="P:Densen.Models.ids.AspNetUserLogins.AspNetUsers">
<summary>
用户
</summary>
</member>
<member name="T:Densen.Models.ids.AspNetUserRoles">
<summary>
角色表
<para>存储向哪些用户分配哪些角色</para>
</summary>
</member>
<member name="T:Densen.Models.ids.AspNetUsers">
<summary>
用户表
</summary>
</member>
<member name="T:Densen.Models.ids.AspNetUserTokens">
<summary>
用户令牌
</summary>
</member>
<member name="T:Densen.Models.ids.DeviceCodes">
<summary>
设备代码
</summary>
</member>
<member name="T:Densen.Models.ids.Keys">
<summary>
密钥
</summary>
</member>
<member name="T:Densen.Models.ids.PersistedGrants">
<summary>
持久化保存
</summary>
</member>
<member name="P:Densen.Identity.Models.WebAppIdentityUser.Name">
<summary>
Full name
</summary>
</member>
<member name="P:Densen.Identity.Models.WebAppIdentityUser.DOB">
<summary>
Birth Date
</summary>
</member>
<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:base_entity.Program.TUserImg">
<summary>
用户图片2
</summary>
</member>
<member name="P:base_entity.Program.TUserImg.Id">
<summary>
主键
</summary>
</member>
<member name="P:base_entity.Program.TUserImg.EnterpriseId">
<summary>
企业
</summary>
</member>
<member name="P:base_entity.Program.TUserImg.UserId">
<summary>
用户id
</summary>
</member>
<member name="P:base_entity.Program.TUserImg.Img">
<summary>
图片
</summary>
</member>
<member name="P:base_entity.Program.TUserImg.CId">
<summary>
创建人Id
</summary>
</member>
<member name="P:base_entity.Program.TUserImg.CName">
<summary>
创建人
</summary>
</member>
<member name="P:base_entity.Program.TUserImg.CTime">
<summary>
创建日期
</summary>
</member>
<member name="P:base_entity.Program.TUserImg.CTime2">
<summary>
创建日期2
</summary>
</member>
<member name="P:base_entity.Program.IDeleteSoft.IsDeleted">
<summary>
软删除
</summary>
</member>
<member name="P:base_entity.抖店实时销售金额表.ID">
<summary>
ID
</summary>
</member>
<member name="P:base_entity.抖店实时销售金额表.店铺名称">
<summary>
店铺名称
</summary>
</member>
<member name="P:base_entity.抖店实时销售金额表.日期">
<summary>
日期
</summary>
</member>
<member name="P:base_entity.抖店实时销售金额表.品牌名称">
<summary>
品牌名称
</summary>
</member>
<member name="P:base_entity.抖店实时销售金额表.成交金额">
<summary>
成交金额
</summary>
</member>
<member name="P:base_entity.抖店实时销售金额表.更新时间">
<summary>
更新时间
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.Id">
<summary>
主键标识
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.MchtAppId">
<summary>
商户应用Id
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.Describe">
<summary>
描述
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.Status">
<summary>
状态0、关闭 1、启用
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.IsLimitUsePoints">
<summary>
是否限制使用积分0、否 1、是
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.StartTime">
<summary>
开始时间
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.EndTime">
<summary>
结束时间
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.CreatedBy">
<summary>
创建人Id
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.CreatedTime">
<summary>
创建时间
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.UpdatedBy">
<summary>
最后编辑人Id
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.UpdatedTime">
<summary>
最后编辑时间
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.Deleted">
<summary>
是否删除0、否 1、是
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.DeletedBy">
<summary>
删除人Id
</summary>
</member>
<member name="P:base_entity.MarketingRestrictions.DeletedTime">
<summary>
删除时间
</summary>
</member>
<member name="P:base_entity.CurrentDetail.RecordDate">
<summary>
创建日期
</summary>
</member>
<member name="P:base_entity.CurrentDetail.RecordHour">
<summary>
创建小时
</summary>
</member>
<member name="P:base_entity.CurrentDetail.RecordMinute">
<summary>
根据当前分钟数规整到10分钟的倍数
例如 21分=>20分
</summary>
</member>
<member name="P:base_entity.CurrentDetail.RecordTime">
<summary>
记录时间
</summary>
</member>
<member name="P:base_entity.CurrentDetail.DeviceCode">
<summary>
设备Code
</summary>
</member>
<member name="P:base_entity.CurrentDetail.TerminalSequence">
<summary>
控制器序列号
</summary>
</member>
<member name="P:base_entity.CurrentDetail.AvgValue">
<summary>
平均值
</summary>
</member>
<member name="P:base_entity.CurrentDetail.RouteNum">
<summary>
路数
</summary>
</member>
<member name="P:base_entity.CurrentDetail.PhaseTypeId">
<summary>
相类型
</summary>
</member>
<member name="P:base_entity.ProducerModel_Kafka.Sender">
<summary>
这个可以
</summary>
</member>
<member name="P:base_entity.ProducerModel_Kafka.ID">
<summary>
ID
</summary>
</member>
<member name="P:base_entity.ProducerModel_Kafka.IP">
<summary>
IP
</summary>
</member>
<member name="P:base_entity.ProducerModel_Kafka.PConfig">
<summary>
这个不行
</summary>
</member>
<member name="P:ProjectItem.Code">
<summary>
编码
</summary>
</member>
<member name="P:ProjectItem.MaxQuantity">
<summary>
实际最大用量
</summary>
</member>
<member name="P:ProjectItem.Name">
<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>

View File

@ -0,0 +1,25 @@
using FreeSql.DataAnnotations;
using NetTopologySuite.Geometries;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace base_entity
{
partial class Program
{
public static void test_pgsql(IFreeSql fsql)
{
var ddl = fsql.CodeFirst.GetComparisonDDLStatements<gistIndex>();
}
}
[Index("sidx_zjds_geom", nameof(Geom), IndexMethod = IndexMethod.GiST)]
class gistIndex
{
public int bb { get; set; }
public LineString Geom { get; set; }
}
}

View File

@ -0,0 +1,130 @@
# 前言
尝试过 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
```csharp
BaseEntity.Initialization(fsql, null);
```
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();
}
```

View File

@ -0,0 +1,291 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using SqlSugar;
namespace FreeSql.Bechmarker
{
public class Program
{
public static void Main(string[] args)
{
//var summaryInsert = BenchmarkRunner.Run<OrmVsInsert>();
var summarySelect = BenchmarkRunner.Run<OrmVsSelect>(new BenchmarkDotNet.Configs.DebugBuildConfig
{
});
//var summaryUpdate = BenchmarkRunner.Run<OrmVsUpdate>();
Console.ReadKey();
Console.ReadKey();
}
}
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=103;TrustServerCertificate=true;Encrypt=False",
typeof(FreeSql.SqlServer.SqlServerProvider<>))
//.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();
public static SqlSugarClient sugar
{
get => new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=102;TrustServerCertificate=true;Encrypt=False",
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
});
}
}
class SongContext : DbContext
{
public DbSet<Song> Songs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=101;TrustServerCertificate=true;Encrypt=False");
//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");
}
}
[RPlotExporter, RankColumn]
public class OrmVsInsert
{
public IEnumerable<Song> songs;
[Params(1, 500)]
public int size;
[GlobalSetup]
public void Setup()
{
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), "freesql_song");
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), "sugar_song");
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), "efcore_song");
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), "dapper_song");
//测试前清空数据
Orm.fsql.Delete<Song>().Where(a => a.Id > 0).ExecuteAffrows();
Orm.sugar.Deleteable<Song>().Where(a => a.Id > 0).ExecuteCommand();
Orm.fsql.Ado.ExecuteNonQuery("delete from efcore_song");
songs = Enumerable.Range(0, size).Select(a => new Song
{
Create_time = DateTime.Now,
Is_deleted = false,
Title = $"Insert_{a}",
Url = $"Url_{a}"
});
//预热
Orm.fsql.Insert(songs.First()).ExecuteAffrows();
Orm.sugar.Insertable(songs.First()).ExecuteCommand();
using (var db = new SongContext())
{
//db.Configuration.AutoDetectChangesEnabled = false;
db.Songs.AddRange(songs.First());
db.SaveChanges();
}
}
[Benchmark]
public int FreeSqlInsert() => Orm.fsql.Insert(songs).ExecuteAffrows();
[Benchmark]
public int SqlSugarInsert() => Orm.sugar.Insertable(songs.ToArray()).ExecuteCommand();
[Benchmark]
public int EfCoreInsert()
{
using (var db = new SongContext())
{
//db.Configuration.AutoDetectChangesEnabled = false;
db.Songs.AddRange(songs.ToArray());
return db.SaveChanges();
}
}
[Benchmark]
public int DapperInsert()
{
using (var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=100;TrustServerCertificate=true;Encrypt=False"))
{
foreach (var song in songs)
{
Dapper.SqlMapper.Execute(conn, @$"insert into dapper_song(Create_time,Is_deleted,Title,Url)
values('{song.Create_time.Value.ToString("yyyy-MM-dd HH:mm:ss")}',{(song.Is_deleted == true ? 1 : 0)},'{song.Title}','{song.Url}')");
}
}
return songs.Count();
}
}
[RPlotExporter, RankColumn]
public class OrmVsUpdate
{
public List<Song> songs;
[Params(1, 500)]
public int size;
[GlobalSetup]
public void Setup()
{
songs = Orm.fsql.Select<Song>().Limit(size).ToList();
}
[Benchmark]
public int FreeSqlUpdate() => Orm.fsql.Update<Song>().SetSource(songs).ExecuteAffrows();
[Benchmark]
public int SqlSugarUpdate() => Orm.sugar.Updateable(songs).ExecuteCommand();
[Benchmark]
public int EfCoreUpdate()
{
using (var db = new SongContext())
{
//db.Configuration.AutoDetectChangesEnabled = false;
db.Songs.UpdateRange(songs.ToArray());
return db.SaveChanges();
}
}
[Benchmark]
public int DapperUpdate()
{
using (var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=100;TrustServerCertificate=true;Encrypt=False"))
{
foreach (var song in songs)
{
Dapper.SqlMapper.Execute(conn, @$"update dapper_song set
Create_time = '{song.Create_time.Value.ToString("yyyy-MM-dd HH:mm:ss")}',
Is_deleted = {(song.Is_deleted == true ? 1 : 0)},
Title = '{song.Title}',
Url = '{song.Url}'
where id = {song.Id}");
}
}
return songs.Count();
}
}
[RPlotExporter, RankColumn]
public class OrmVsSelect
{
[Params(1, 500)]
public int size;
[IterationSetup]
public void Setup2()
{
Orm.fsql.Select<Song>().Limit(1).ToList();
Orm.sugar.Queryable<Song>().Take(1).ToList();
using (var db = new SongContext())
{
db.Songs.Take(1).AsNoTracking().ToList();
}
using (var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=100;TrustServerCertificate=true;Encrypt=False"))
{
Dapper.SqlMapper.Query<Song>(conn, $"select top {1} Id,Create_time,Is_deleted,Title,Url from dapper_song").ToList();
}
}
[GlobalSetup]
public void Setup()
{
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), "freesql_song");
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), "sugar_song");
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), "efcore_song");
Orm.fsql.CodeFirst.SyncStructure(typeof(Song), "dapper_song");
//测试前清空数据
Orm.fsql.Delete<Song>().Where(a => a.Id > 0).ExecuteAffrows();
Orm.sugar.Deleteable<Song>().Where(a => a.Id > 0).ExecuteCommand();
Orm.fsql.Ado.ExecuteNonQuery("delete from efcore_song");
Orm.fsql.Ado.ExecuteNonQuery("delete from dapper_song");
var songs = Enumerable.Range(0, size).Select(a => new Song
{
Create_time = DateTime.Now,
Is_deleted = false,
Title = $"Insert_{a}",
Url = $"Url_{a}"
});
//预热
Orm.fsql.Insert(songs).ExecuteAffrows();
Orm.sugar.Insertable(songs.ToArray()).ExecuteCommand();
using (var db = new SongContext())
{
//db.Configuration.AutoDetectChangesEnabled = false;
db.Songs.AddRange(songs);
db.SaveChanges();
}
using (var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=100;TrustServerCertificate=true;Encrypt=False"))
{
foreach (var song in songs)
{
Dapper.SqlMapper.Execute(conn, @$"insert into dapper_song(Create_time,Is_deleted,Title,Url)
values('{song.Create_time.Value.ToString("yyyy-MM-dd HH:mm:ss")}',{(song.Is_deleted == true ? 1 : 0)},'{song.Title}','{song.Url}')");
}
}
}
[Benchmark]
public List<Song> FreeSqlSelect() => Orm.fsql.Select<Song>().Limit(size).ToList();
[Benchmark]
public List<Song> SqlSugarSelect() => Orm.sugar.Queryable<Song>().Take(size).ToList();
[Benchmark]
public List<Song> EfCoreSelect()
{
using (var db = new SongContext())
{
return db.Songs.Take(size).AsNoTracking().ToList();
}
}
[Benchmark]
public List<Song> DapperSelete()
{
using (var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=100;TrustServerCertificate=true;Encrypt=False"))
{
return Dapper.SqlMapper.Query<Song>(conn, $"select top {size} Id,Create_time,Is_deleted,Title,Url from dapper_song").ToList();
}
}
}
[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; }
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageReference Include="sqlSugarCore" Version="5.1.3.38" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Providers\FreeSql.Provider.SqlServerForSystem\FreeSql.Provider.SqlServerForSystem.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "5.0.0",
"commands": [
"dotnet-ef"
]
}
}
}

View File

@ -0,0 +1,251 @@
using System;
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
{
private readonly IFreeSql _orm;
private readonly SongContext _songContext;
private readonly CurdAfterLog _curdLog;
public ValuesController(SongContext songContext, IFreeSql orm1, CurdAfterLog curdLog)
{
_songContext = songContext;
_orm = orm1;
_curdLog = curdLog;
}
// GET api/values
[HttpGet]
public async 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)
{
}
}
}

View 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; }
}
}

View 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>();
}
}

View File

@ -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>

View 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/"
}
}
}

View 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;
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.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="8.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>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>dbcontext_01</name>
</assembly>
<members>
</members>
</doc>

View File

@ -0,0 +1,33 @@
using efcore_to_freesql.Entitys;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
namespace efcore_to_freesql.DBContexts
{
public class BaseDBContext : DbContext
{
public static IFreeSql Fsql { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
Fsql.CodeFirst.ConfigEntity(modelBuilder.Model); //同步配置
//配置单个
Fsql.CodeFirst.ApplyConfiguration(new SongConfiguration());
//批量量配置
//Fsql.CodeFirst.ApplyConfigurationsFromAssembly(typeof(SongConfiguration).Assembly);
Fsql.CodeFirst.SyncStructure<Song>();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(@"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10");
}
}
}

View File

@ -0,0 +1,21 @@
using efcore_to_freesql.Entitys;
using Microsoft.EntityFrameworkCore;
namespace efcore_to_freesql.DBContexts
{
public class Topic1Context : BaseDBContext
{
public DbSet<Topic1> Topic1s { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Topic1>().ToTable("topic1_sss").HasKey(a => a.Id);
modelBuilder.Entity<Topic1>().Property(a => a.Id).HasColumnName("topic1_id").ValueGeneratedOnAdd();
base.OnModelCreating(modelBuilder);
}
}
}

View File

@ -0,0 +1,21 @@
using efcore_to_freesql.Entitys;
using Microsoft.EntityFrameworkCore;
namespace efcore_to_freesql.DBContexts
{
public class Topic2Context : BaseDBContext
{
public DbSet<Topic2> Topic2s { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Topic2>().ToTable("topic2_sss");
modelBuilder.Entity<Topic2>().Property(a => a.Id).HasColumnName("topic2_id");
base.OnModelCreating(modelBuilder);
}
}
}

View 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; }
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace efcore_to_freesql.Entitys
{
public class Topic1
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime CreateTime { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace efcore_to_freesql.Entitys
{
public class Topic2
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
public DateTime CreateTime { get; set; }
}
}

View File

@ -0,0 +1,205 @@
using efcore_to_freesql.Entitys;
using FreeSql;
using FreeSql.Extensions.EfCoreFluentApi;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public static class CodeFirstExtensions
{
public static void ConfigEntity(this ICodeFirst codeFirst, IMutableModel efmodel)
{
foreach (var type in efmodel.GetEntityTypes())
{
codeFirst.ConfigEntity(type.ClrType, a =>
{
//表名
var relationalTableName = type.FindAnnotation("Relational:TableName");
if (relationalTableName != null)
a.Name(relationalTableName.Value?.ToString() ?? type.ClrType.Name);
foreach (var prop in type.GetProperties())
{
var freeProp = a.Property(prop.Name);
//列名
var relationalColumnName = prop.FindAnnotation("Relational:ColumnName");
if (relationalColumnName != null)
freeProp.Name(relationalColumnName.Value?.ToString() ?? prop.Name);
//主键
freeProp.IsPrimary(prop.IsPrimaryKey());
//自增
freeProp.IsIdentity(
prop.ValueGenerated == ValueGenerated.Never ||
prop.ValueGenerated == ValueGenerated.OnAdd ||
prop.GetAnnotations().Where(z =>
z.Name == "SqlServer:ValueGenerationStrategy" && z.Value.ToString().Contains("IdentityColumn") //sqlserver 自增
|| z.Value.ToString().Contains("IdentityColumn") //其他数据库实现未经测试
).Any()
);
//可空
freeProp.IsNullable(prop.GetAfterSaveBehavior() != PropertySaveBehavior.Throw);
//类型
var relationalColumnType = prop.FindAnnotation("Relational:ColumnType");
if (relationalColumnType != null)
{
var dbType = relationalColumnType.ToString();
if (!string.IsNullOrEmpty(dbType))
{
var maxLength = prop.FindAnnotation("MaxLength");
if (maxLength != null)
dbType += $"({maxLength})";
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>();
}
}
public class SongConfiguration : FreeSql.Extensions.EfCoreFluentApi.IEntityTypeConfiguration<Song>
{
public void Configure(EfCoreTableFluent<Song> eb)
{
eb.ToTable("tb_song_config");
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));
}
}

View 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 efcore_to_freesql
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}

View File

@ -0,0 +1,30 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:58143",
"sslPort": 44349
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"efcore_to_freesql": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/values",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using efcore_to_freesql.DBContexts;
using efcore_to_freesql.Entitys;
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.Logging;
using Microsoft.Extensions.Options;
namespace efcore_to_freesql
{
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)
.Build();
//Fsql.CodeFirst.EfCoreFluentApiTestGeneric();
//Fsql.CodeFirst.EfCoreFluentApiTestDynamic();
BaseDBContext.Fsql = Fsql;
var sql11 = Fsql.Select<Topic1>().ToSql();
//SELECT a."Id", a."Title", a."CreateTime" FROM "Topic1" a
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();
//SELECT a."Id", a."Title", a."CreateTime" FROM "Topic2" a
var sql22 = Fsql.Insert<Topic2>().AppendData(new Topic2()).ToSql();
//INSERT INTO "Topic2"("Id", "Title", "CreateTime") VALUES(@Id0, @Title0, @CreateTime0)
using (var db = new Topic1Context())
{
db.Topic1s.Add(new Topic1());
}
using (var db = new Topic2Context())
{
db.Topic2s.Add(new Topic2());
}
var sql13 = Fsql.Select<Topic1>().ToSql();
//SELECT a."topic1_id", a."Title", a."CreateTime" FROM "topic1_sss" a
var sql14 = Fsql.Insert<Topic1>().AppendData(new Topic1()).ToSql();
//INSERT INTO "topic1_sss"("Title", "CreateTime") VALUES(@Title0, @CreateTime0)
var sql23 = Fsql.Select<Topic2>().ToSql();
//SELECT a."topic2_id", a."Title", a."CreateTime" FROM "topic2_sss" a
var sql24 = Fsql.Insert<Topic2>().AppendData(new Topic2()).ToSql();
//INSERT INTO "topic2_sss"("Title", "CreateTime") VALUES(@Title0, @CreateTime0)
}
public IConfiguration Configuration { get; }
public IFreeSql Fsql { get; }
public void ConfigureServices(IServiceCollection services)
{
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());
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FreeSql.DbContext\FreeSql.DbContext.csproj" />
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
</ItemGroup>
</Project>

814
Examples/orm_vs/Program.cs Normal file
View File

@ -0,0 +1,814 @@
using Dapper;
using FreeSql.Internal;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Common;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FreeSql;
using FreeSql.Internal.CommonProvider;
namespace orm_vs
{
class Program
{
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=tedb1;Pooling=true;Max Pool Size=21;TrustServerCertificate=true")
//.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=21;AllowLoadLocalInfile=true;")
//.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=127.0.0.1;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=21")
.UseAutoSyncStructure(false)
.UseNoneCommandParameter(true)
//.UseConfigEntityFromDbFirst(true)
.Build();
static SqlSugarClient sugar
{
get
{
var db = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = "Data Source=.;Integrated Security=True;Initial Catalog=tedb1;Pooling=true;Min Pool Size=20;Max Pool Size=20;TrustServerCertificate=true",
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;AllowLoadLocalInfile=true;",
//DbType = DbType.MySql,
//ConnectionString = "Host=127.0.0.1;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=20",
//DbType = DbType.PostgreSQL,
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute
});
//db.Aop.OnLogExecuting = (sql, pars) =>
//{
// Console.WriteLine(sql);//输出sql,查看执行sql
//};
return db;
}
}
class SongContext : DbContext
{
public DbSet<Song> Songs { get; set; }
public DbSet<PatientExamination_2022> PatientExamination_2022s { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Data Source=.;Integrated Security=True;Initial Catalog=tedb1;Pooling=true;Min Pool Size=19;Max Pool Size=19;TrustServerCertificate=true");
//var connectionString = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Min Pool Size=19;Max Pool Size=19";
//optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
//optionsBuilder.UseNpgsql("Host=127.0.0.1;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=19");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
//CREATE TABLE [dbo].[PatientExamination_2022] (
// [Id] uniqueidentifier NOT NULL,
// [CreateTime] datetime NOT NULL,
// [ExamKindId] uniqueidentifier NOT NULL,
// [ExamKindName] nvarchar(255) COLLATE Chinese_PRC_CI_AS NULL,
// [PatientGuid] uniqueidentifier NOT NULL,
// [PatientName] nvarchar(255) COLLATE Chinese_PRC_CI_AS NULL,
// [AnesthesiaType] int NOT NULL,
// [DiaRoomId] uniqueidentifier NULL,
// [DiaRoomName] nvarchar(255) COLLATE Chinese_PRC_CI_AS NULL,
// [QueueIndex] int NOT NULL,
// [QueueNum] int NOT NULL,
// [OrderDateTime] datetime NOT NULL,
// [TimeType] int NOT NULL,
// [SignInTime] datetime NULL,
// [StartCheckTime] datetime NULL,
// [EndCheckTime] datetime NULL,
// [VerifyTime] datetime NULL,
// [ReportTime] datetime NULL,
// [ExaminationState] int NOT NULL
//)
[Table("PatientExamination_2022")]
class PatientExamination_2022
{
public Guid Id { get; set; }
public DateTime CreateTime { get; set; }
public Guid ExamKindId { get; set; }
public string ExamKindName { get; set; }
public Guid PatientGuid { get; set; }
public string PatientName { get; set; }
public int AnesthesiaType { get; set; }
public Guid? DiaRoomId { get; set; }
public string DiaRoomName { get; set; }
public int QueueIndex { get; set; }
public int QueueNum { get; set; }
public DateTime OrderDateTime { get; set; }
public int TimeType { get; set; }
public DateTime? SignInTime { get; set; }
public DateTime? StartCheckTime { get; set; }
public DateTime? EndCheckTime { get; set; }
public DateTime? VerifyTime { get; set; }
public DateTime? ReportTime { get; set; }
public int ExaminationState { get; set; }
}
static void TestFreeSqlSelectPatientExamination_2022()
{
var list = fsql.Select<PatientExamination_2022>().Limit(40000).ToList();
//var list = fsql.Ado.Query<PatientExamination_2022>("select top 40000 * from PatientExamination_2022");
}
static void TestEfSelectPatientExamination_2022()
{
using (var ctx = new SongContext())
{
var list = ctx.PatientExamination_2022s.Take(40000).AsNoTracking().ToList();
}
}
static void TestSqlSugarSelectPatientExamination_2022()
{
var list = sugar.Queryable<PatientExamination_2022>().Take(40000).ToList();
}
static void TestDapperSelectPatientExamination_2022()
{
using (var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=tedb1;Pooling=true;Min Pool Size=21;Max Pool Size=22"))
{
var list = conn.Query<PatientExamination_2022>("select top 40000 * from PatientExamination_2022");
}
}
static DbConnection fsqlConn = null;
static void Main(string[] args)
{
//var count = 0;
//var sws = new List<long>();
//Console.WriteLine("观察查询4万条记录内存按 Enter 进入下一次,按任易键即出程序。。。");
////while(Console.ReadKey().Key == ConsoleKey.Enter)
////using (var fcon = fsql.Ado.MasterPool.Get())
////{
// //fsqlConn = fcon.Value;
// for (var a = 0; a < 80; a++)
// {
// Stopwatch sw = Stopwatch.StartNew();
// TestFreeSqlSelectPatientExamination_2022();
// //TestEfSelectPatientExamination_2022();
// //TestSqlSugarSelectPatientExamination_2022();
// //TestDapperSelectPatientExamination_2022();
// sw.Stop();
// sws.Add(sw.ElapsedMilliseconds);
// Console.WriteLine($"第 {++count} 次查询4万条记录, {sw.ElapsedMilliseconds}ms平均 {(long)sws.Average()}ms");
// }
////}
//Console.ReadKey();
//fsql.Dispose();
//return;
//fsql.CodeFirst.SyncStructure(typeof(Song), typeof(Song_tag), typeof(Tag));
//sugar.CodeFirst.InitTables(typeof(Song), typeof(Song_tag), typeof(Tag));
//sugar创建表失败SqlSugar.SqlSugarException: Sequence contains no elements
fsql.CodeFirst.SyncStructure(typeof(Song), "freesql_song");
fsql.CodeFirst.SyncStructure(typeof(Song), "sugar_song");
fsql.CodeFirst.SyncStructure(typeof(Song), "efcore_song");
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "freesql_song_tag");
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "sugar_song_tag");
fsql.CodeFirst.SyncStructure(typeof(Song_tag), "efcore_song_tag");
fsql.CodeFirst.SyncStructure(typeof(Tag), "freesql_tag");
fsql.CodeFirst.SyncStructure(typeof(Tag), "sugar_tag");
fsql.CodeFirst.SyncStructure(typeof(Tag), "efcore_tag");
var sb = new StringBuilder();
var time = new Stopwatch();
#region ET test
////var t31 = fsql.Select<xxx>().ToList();
//fsql.Select<Song>().First();
//time.Restart();
//var t3 = fsql.Select<Song>().ToList();
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*");
//time.Restart();
//var adoarr1 = fsql.Ado.ExecuteArray("select * from freesql_song");
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteArray Entity Counts: {adoarr1.Length}; ORM: FreeSql ExecuteArray*");
//time.Restart();
//var adolist1 = new List<Song>();
//fsql.Ado.ExecuteReader(dr =>
//{
// var xim = new Song();
// dr.GetValue(0)?.GetType();
// dr.GetValue(1)?.GetType();
// dr.GetValue(2)?.GetType();
// dr.GetValue(3)?.GetType();
// dr.GetValue(4)?.GetType();
// adolist1.Add(xim);
//}, "select * from freesql_song");
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader*");
//time.Restart();
//adolist1 = new List<Song>();
//fsql.Ado.ExecuteReader(dr =>
//{
// var xim = new Song();
// var v1 = dr.GetValue(0);
// var locvalue = (object)v1;
// if (locvalue == null || locvalue == DBNull.Value) xim.Id = default;
// else
// {
// if (locvalue is int iv) xim.Id = iv;
// else
// {
// if (locvalue is string)
// {
// }
// }
// }
// v1 = dr.GetValue(1);
// locvalue = (object)v1;
// if (locvalue == null || locvalue == DBNull.Value) xim.Create_time = default;
// else
// {
// if (locvalue is DateTime dt) xim.Create_time = dt;
// else
// {
// if (locvalue is string)
// {
// }
// }
// }
// v1 = dr.GetValue(2);
// locvalue = (object)v1;
// if (locvalue == null || locvalue == DBNull.Value) xim.Is_deleted = default;
// else
// {
// if (locvalue is bool bl) xim.Is_deleted = bl;
// else
// {
// if (locvalue is string)
// {
// }
// }
// }
// v1 = dr.GetValue(3);
// locvalue = (object)v1;
// if (locvalue == null || locvalue == DBNull.Value) xim.Title = default;
// else
// {
// if (locvalue is string str) xim.Title = str;
// else
// {
// if (locvalue is string)
// {
// }
// }
// }
// v1 = dr.GetValue(4);
// locvalue = (object)v1;
// if (locvalue == null || locvalue == DBNull.Value) xim.Url = default;
// else
// {
// if (locvalue is string str) xim.Url = str;
// else
// {
// if (locvalue is string)
// {
// }
// }
// }
// adolist1.Add(xim);
//}, "select * from freesql_song");
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReaderObject Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReaderObject*");
////var type = typeof(Song);
////var myfuncParam1 = Expression.Parameter(typeof(object[]), "values");
////var retExp = Expression.Variable(type, "ret");
////var objExp = Expression.Variable(typeof(object), "obj");
////var returnTarget = Expression.Label(type);
////var myfuncBody = Expression.Block(
//// new[] { retExp, objExp },
//// Expression.Assign(retExp, type.InternalNewExpression()),
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(0))),
//// Utils.GetConvertExpression(type.GetProperty("Id").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Id")), Expression.Convert(objExp, type.GetProperty("Id").PropertyType)),
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(1))),
//// Utils.GetConvertExpression(type.GetProperty("Create_time").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Create_time")), Expression.Convert(objExp, type.GetProperty("Create_time").PropertyType)),
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(2))),
//// Utils.GetConvertExpression(type.GetProperty("Is_deleted").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Is_deleted")), Expression.Convert(objExp, type.GetProperty("Is_deleted").PropertyType)),
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(3))),
//// Utils.GetConvertExpression(type.GetProperty("Title").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Title")), Expression.Convert(objExp, type.GetProperty("Title").PropertyType)),
//// Expression.Assign(objExp, Expression.ArrayIndex(myfuncParam1, Expression.Constant(4))),
//// Utils.GetConvertExpression(type.GetProperty("Url").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Url")), Expression.Convert(objExp, type.GetProperty("Url").PropertyType)),
//// Expression.Return(returnTarget, retExp),
//// Expression.Label(returnTarget, Expression.Default(type))
////);
////var myfunc = Expression.Lambda<Func<object[], Song>>(myfuncBody, myfuncParam1).Compile();
////time.Restart();
////adolist1 = new List<Song>();
////fsql.Ado.ExecuteReader(dr =>
////{
//// var values = new object[dr.FieldCount];
//// dr.GetValues(values);
//// var xim = myfunc(values);
//// adolist1.Add(xim);
////}, "select * from freesql_song");
////time.Stop();
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReaderMyFunc Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReaderMyFunc*");
////var methodDrgv = typeof(DbDataReader).GetMethod("GetValue");
////var myfunc2Param1 = Expression.Parameter(typeof(DbDataReader), "dr");
////var myfunc2Body = Expression.Block(
//// new[] { retExp, objExp },
//// Expression.Assign(retExp, type.InternalNewExpression()),
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(0))),
//// Utils.GetConvertExpression(type.GetProperty("Id").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Id")), Expression.Convert(objExp, type.GetProperty("Id").PropertyType)),
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(1))),
//// Utils.GetConvertExpression(type.GetProperty("Create_time").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Create_time")), Expression.Convert(objExp, type.GetProperty("Create_time").PropertyType)),
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(2))),
//// Utils.GetConvertExpression(type.GetProperty("Is_deleted").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Is_deleted")), Expression.Convert(objExp, type.GetProperty("Is_deleted").PropertyType)),
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(3))),
//// Utils.GetConvertExpression(type.GetProperty("Title").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Title")), Expression.Convert(objExp, type.GetProperty("Title").PropertyType)),
//// Expression.Assign(objExp, Expression.Call(myfunc2Param1, methodDrgv, Expression.Constant(4))),
//// Utils.GetConvertExpression(type.GetProperty("Url").PropertyType, objExp),
//// Expression.Assign(Expression.MakeMemberAccess(retExp, type.GetProperty("Url")), Expression.Convert(objExp, type.GetProperty("Url").PropertyType)),
//// Expression.Return(returnTarget, retExp),
//// Expression.Label(returnTarget, Expression.Default(type))
////);
////var myfunc2 = Expression.Lambda<Func<DbDataReader, Song>>(myfunc2Body, myfunc2Param1).Compile();
////time.Restart();
////adolist1 = new List<Song>();
////fsql.Ado.ExecuteReader(dr =>
////{
//// var xim = myfunc2(dr);
//// adolist1.Add(xim);
////}, "select * from freesql_song");
////time.Stop();
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReaderMyFunc22 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReaderMyFunc22*");
//time.Restart();
//adolist1 = new List<Song>();
//fsql.Ado.ExecuteReader(dr =>
//{
// var xim = new Song();
// dr.GetFieldValue<int>(0);
// dr.GetFieldValue<DateTime>(1);
// dr.GetFieldValue<bool>(2);
// dr.GetFieldValue<string>(3);
// dr.GetFieldValue<string>(4);
// adolist1.Add(xim);
//}, "select * from freesql_song");
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader0000 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader0000*");
//time.Restart();
//adolist1 = new List<Song>();
//fsql.Ado.ExecuteReader(dr =>
//{
// var xim = new Song();
// Utils.GetDataReaderValue(typeof(int), dr.GetValue(0));
// Utils.GetDataReaderValue(typeof(DateTime), dr.GetValue(1));
// Utils.GetDataReaderValue(typeof(bool), dr.GetValue(2));
// Utils.GetDataReaderValue(typeof(string), dr.GetValue(3));
// Utils.GetDataReaderValue(typeof(string), dr.GetValue(4));
// adolist1.Add(xim);
//}, "select * from freesql_song");
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader1111 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader1111*");
////time.Restart();
////adolist1 = new List<Song>();
////fsql.Ado.ExecuteReader(dr =>
////{
//// var xim = new Song();
//// Utils.GetConvertValue(typeof(int), dr.GetValue(0));
//// Utils.GetConvertValue(typeof(DateTime), dr.GetValue(1));
//// Utils.GetConvertValue(typeof(bool), dr.GetValue(2));
//// Utils.GetConvertValue(typeof(string), dr.GetValue(3));
//// Utils.GetConvertValue(typeof(string), dr.GetValue(4));
//// adolist1.Add(xim);
////}, "select * from freesql_song");
////time.Stop();
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader11112222 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader11112222*");
//time.Restart();
//adolist1 = new List<Song>();
//fsql.Ado.ExecuteReader(dr =>
//{
// var values = new object[dr.FieldCount];
// dr.GetValues(values);
// var xim = new Song();
// xim.Id = (int)Utils.GetDataReaderValue(typeof(int), values[0]);
// xim.Create_time = (DateTime)Utils.GetDataReaderValue(typeof(DateTime), values[1]);
// xim.Is_deleted = (bool)Utils.GetDataReaderValue(typeof(bool), values[2]);
// xim.Title = (string)Utils.GetDataReaderValue(typeof(string), values[3]);
// xim.Url = (string)Utils.GetDataReaderValue(typeof(string), values[4]);
// adolist1.Add(xim);
//}, "select * from freesql_song");
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader1111 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader1111*");
////time.Restart();
////adolist1 = new List<Song>();
////fsql.Ado.ExecuteReader(dr =>
////{
//// var values = new object[dr.FieldCount];
//// dr.GetValues(values);
//// var xim = new Song();
//// xim.Id = (int)Utils.GetConvertValue(typeof(int), values[0]);
//// xim.Create_time = (DateTime)Utils.GetConvertValue(typeof(DateTime), values[1]);
//// xim.Is_deleted = (bool)Utils.GetConvertValue(typeof(bool), values[2]);
//// xim.Title = (string)Utils.GetConvertValue(typeof(string), values[3]);
//// xim.Url = (string)Utils.GetConvertValue(typeof(string), values[4]);
//// adolist1.Add(xim);
////}, "select * from freesql_song");
////time.Stop();
////sb.AppendLine($"Elapsed: {time.Elapsed}; ExecuteReader11112222 Entity Counts: {adolist1.Count}; ORM: FreeSql ExecuteReader11112222*");
//time.Restart();
//List<Song> dplist1 = null;
//using (var conn = fsql.Ado.MasterPool.Get())
//{
// dplist1 = Dapper.SqlMapper.Query<Song>(conn.Value, "select * from freesql_song").ToList();
//}
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; Query Entity Counts: {dplist1.Count}; ORM: Dapper");
//time.Restart();
//t3 = fsql.Select<Song>().ToList();
//time.Stop();
//sb.AppendLine($"Elapsed: {time.Elapsed}; ToList Entity Counts: {t3.Count}; ORM: FreeSql*");
//Console.WriteLine(sb.ToString());
//Console.ReadKey();
#endregion
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, 10, 1);
Console.Write(sb.ToString());
sb.Clear();
Update(sb, 10, 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 * from freesql_song limit {size}").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.ToString(),
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.Fastest<Song>().BulkCopy(songs.ToList());
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 Update1 {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
songs = fsql.Select<Song>().Limit(size).ToList();
sw.Restart();
for (var a = 0; a < forTime; a++)
{
fsql.Update<Song>().SetSource(songs).ExecuteSqlBulkCopy();
}
sw.Stop();
sb.AppendLine($"FreeSql BulkCopyUpdate {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
// songs = fsql.Select<Song>().Limit(size).ToList();
// sw.Restart();
// for (var a = 0; a < forTime; a++)
// {
// //fsql.Update<Song>().SetSource(songs).ExecuteAffrows();
// var iou = fsql.InsertOrUpdate<Song>() as InsertOrUpdateProvider<Song>;
// var dbsql = new StringBuilder();
// var dbparms = new List<DbParameter>();
// iou.WriteSourceSelectUnionAll(songs, dbsql, dbparms);
// var sql = $@"update freesql_song a
//inner join ( {dbsql} ) b on b.id = a.id
//set a.create_time = b.create_time, a.is_deleted = b.is_deleted, a.title = b.title, a.url = b.url";
// fsql.Ado.ExecuteNonQuery(System.Data.CommandType.Text, sql, dbparms.ToArray());
// }
// sw.Stop();
// sb.AppendLine($"FreeSql Update2(update inner join) {size}条数据,循环{forTime}次,耗时{sw.ElapsedMilliseconds}ms");
// songs = fsql.Select<Song>().Limit(size).ToList();
// sw.Restart();
// for (var a = 0; a < forTime; a++)
// {
// var isdroped = false;
// var tempTableName = $"#Temp_freesql_song";
// fsql.Ado.ExecuteNonQuery($"select * into {tempTableName} from [freesql_song] where 1=2");
// try
// {
// fsql.Insert(songs).AsTable(tempTableName).ExecuteMySqlBulkCopy();
// var sql = $@"update freesql_song a
//inner join {tempTableName} b on b.id = a.id;
//set a.create_time = b.create_time, a.is_deleted = b.is_deleted, a.title = b.title, a.url = b.url
//; drop table {tempTableName}; ";
// fsql.Ado.ExecuteNonQuery(System.Data.CommandType.Text, sql);
// isdroped = true;
// }
// finally
// {
// if (isdroped == false)
// fsql.Ado.ExecuteNonQuery($"drop table {tempTableName}");
// }
// }
// sw.Stop();
// sb.AppendLine($"FreeSql Update3(update inner join #temp) {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.Fastest<Song>().BulkUpdate(songs);
}
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 string 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; }
}
}

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageReference Include="sqlSugarCore" Version="5.1.3.38" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.MySqlConnector\FreeSql.Provider.MySqlConnector.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.PostgreSQL\FreeSql.Provider.PostgreSQL.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.SqlServer\FreeSql.Provider.SqlServer.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,264 @@
//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")
.UseConnectionString(FreeSql.DataType.Sqlite, "data source=test1.db;max pool size=5")
.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; }
}
}

View 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")]

View File

@ -0,0 +1,79 @@
<?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.Sqlite\FreeSql.Provider.Sqlite.csproj">
<Project>{559b6369-1868-4a06-a590-f80ba7b80a1b}</Project>
<Name>FreeSql.Provider.Sqlite</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>13.0.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<None Include="..\..\.editorconfig">
<Link>.editorconfig</Link>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,115 @@
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();
}
/// <summary>
/// curl -X GET "http://localhost:5000/restapi/Songs/GetPagingItems?key=FreeSql&PageNumber=2&PageSize=10" -H "accept: text/plain"
/// </summary>
/// <param name="pagingInfo"></param>
/// <returns></returns>
[HttpGet("GetPagingItems")]
public Task<List<Song>> GetPagingItems([FromQuery] string key, [FromQuery] PagingInfo pagingInfo)
{
return _songRepository.Select.WhereIf(!string.IsNullOrEmpty(key), a => a.Title.Contains(key)).Page(pagingInfo).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);
}
}
}

View 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; }
}
}

View File

@ -0,0 +1,57 @@
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace repository_01
{
public class PagingInfo : BasePagingInfo
{
/// <summary>
/// 无参构造函数
/// </summary>
public PagingInfo()
{
}
/// <summary>
/// 当前为第1页每页大小的构造函数
/// </summary>
/// <param name="pageSize"></param>
public PagingInfo(int pageSize)
{
PageNumber = 1;
PageSize = pageSize;
}
/// <summary>
/// 带当前页和每页大小的构造函数
/// </summary>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
public PagingInfo(int pageNumber, int pageSize)
{
PageNumber = pageNumber;
PageSize = pageSize;
}
/// <summary>
/// 当前有多少页【只读】
/// </summary>
public long PageCount => PageSize == 0 ? 0 : (Count + PageSize - 1) / PageSize;
/// <summary>
/// 是否有上一页【只读】
/// </summary>
public bool HasPrevious => PageNumber > 1 && PageNumber <= PageCount;
/// <summary>
/// 是否有下一页【只读】
/// </summary>
public bool HasNext => PageNumber < PageCount;
/// <summary>
/// 是否在第一页【只读】
/// </summary>
public bool IsFrist => PageNumber == 1;
/// <summary>
/// 是否在最后一页【只读】
/// </summary>
public bool IsLast => PageNumber == PageCount;
}
}

View 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>();
}
}

View 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/"
}
}
}

View 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; }
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Warning",
"Microsoft": "Warning"
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
Examples/restful/002.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
Examples/restful/003.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
Examples/restful/004.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,81 @@
using Microsoft.AspNetCore.Mvc;
using restful.Entitys;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace restful.Controllers
{
[Route("restapi/[controller]")]
public class SongsController : Controller
{
IFreeSql _fsql;
public SongsController(IFreeSql fsql)
{
_fsql = fsql;
}
[HttpGet]
public Task<List<Song>> GetItems([FromQuery] string key, [FromQuery] int page = 1, [FromQuery] int limit = 20)
{
return _fsql.Select<Song>().WhereIf(!string.IsNullOrEmpty(key), a => a.Title.Contains(key)).Page(page, limit).ToListAsync();
}
/// <summary>
/// curl -X GET "http://localhost:5000/restapi/Songs/GetPagingItems?key=FreeSql&PageNumber=2&PageSize=10" -H "accept: text/plain"
/// </summary>
/// <param name="key"></param>
/// <param name="pagingInfo"></param>
/// <returns></returns>
[HttpGet("GetPagingItems")]
public Task<List<Song>> GetPagingItems([FromQuery] string key, [FromQuery] PagingInfo pagingInfo)
{
return _fsql.Select<Song>().WhereIf(!string.IsNullOrEmpty(key), a => a.Title.Contains(key)).Page(pagingInfo).ToListAsync();
}
[HttpGet("{id}")]
public Task<Song> GetItem([FromRoute] int id)
{
return _fsql.Select<Song>().Where(a => a.Id == id).ToOneAsync();
}
public class ModelSong
{
public string title { get; set; }
}
[HttpPost, ProducesResponseType(201)]
async public Task<Song> Create([FromBody] ModelSong model)
{
var ret = await _fsql.Insert<Song>().AppendData(new Song { Title = model.title }).ExecuteInsertedAsync();
return ret.FirstOrDefault();
}
[HttpPut("{id}")]
async public Task<Song> Update([FromRoute] int id, [FromBody] ModelSong model)
{
var ret = await _fsql.Update<Song>().SetSource(new Song { Id = id, Title = model.title }).ExecuteUpdatedAsync();
return ret.FirstOrDefault();
}
[HttpPatch("{id}")]
async public Task<Song> UpdateDiy([FromRoute] int id, [FromForm] string title)
{
var up = _fsql.Update<Song>().Where(a => a.Id == id);
if (!string.IsNullOrEmpty(title)) up.Set(a => a.Title, title);
var ret = await up.ExecuteUpdatedAsync();
return ret.FirstOrDefault();
}
[HttpDelete("{id}"), ProducesResponseType(204)]
async public Task<Song> Delete([FromRoute] int id)
{
var ret = await _fsql.Delete<Song>().Where(a => a.Id == id).ExecuteDeletedAsync();
return ret.FirstOrDefault();
}
}
}

View File

@ -0,0 +1,12 @@
using FreeSql.DataAnnotations;
namespace restful.Entitys
{
public class Song
{
[Column(IsIdentity = true)]
public int Id { get; set; }
public string Title { get; set; }
}
}

View File

@ -0,0 +1,57 @@
using FreeSql.Internal.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace restful
{
public class PagingInfo : BasePagingInfo
{
/// <summary>
/// 无参构造函数
/// </summary>
public PagingInfo()
{
}
/// <summary>
/// 当前为第1页每页大小的构造函数
/// </summary>
/// <param name="pageSize"></param>
public PagingInfo(int pageSize)
{
PageNumber = 1;
PageSize = pageSize;
}
/// <summary>
/// 带当前页和每页大小的构造函数
/// </summary>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
public PagingInfo(int pageNumber, int pageSize)
{
PageNumber = pageNumber;
PageSize = pageSize;
}
/// <summary>
/// 当前有多少页【只读】
/// </summary>
public long PageCount => PageSize == 0 ? 0 : (Count + PageSize - 1) / PageSize;
/// <summary>
/// 是否有上一页【只读】
/// </summary>
public bool HasPrevious => PageNumber > 1 && PageNumber <= PageCount;
/// <summary>
/// 是否有下一页【只读】
/// </summary>
public bool HasNext => PageNumber < PageCount;
/// <summary>
/// 是否在第一页【只读】
/// </summary>
public bool IsFrist => PageNumber == 1;
/// <summary>
/// 是否在最后一页【只读】
/// </summary>
public bool IsLast => PageNumber == PageCount;
}
}

View 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 restful
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}

View File

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:49778/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"FreeSql.RESTful.Demo": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:49779/"
}
}
}

View File

@ -0,0 +1,57 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Text;
namespace restful
{
public class Startup
{
public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
{
Configuration = configuration;
Fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10")
.UseAutoSyncStructure(true)
.Build();
Fsql.Aop.CurdAfter += (s, e) =>
{
if (e.ElapsedMilliseconds > 200)
{
//记录日志
//发送短信给负责人
}
};
//Fsql.Aop.Where = (s, e) => {
// if (e.Parameters[0]?.ToString() == "1")
// e.IsCancel = true;
//};
}
public IConfiguration Configuration { get; }
public IFreeSql Fsql { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IFreeSql>(Fsql);
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
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());
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FreeSql\FreeSql.csproj" />
<ProjectReference Include="..\..\Providers\FreeSql.Provider.Sqlite\FreeSql.Provider.Sqlite.csproj" />
</ItemGroup>
</Project>

View File

View 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>

View 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>

View 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
{
}
}

Some files were not shown because too many files have changed in this diff Show More