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

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>
/// <20><>ɫ<EFBFBD><C9AB>
/// </summary>
[JsonObject(MemberSerialization.OptIn)]
public partial class Role : BaseEntity<Role>{
/// <summary>
/// <20><>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>
/// </summary>
[JsonProperty, Column(IsPrimary = true, IsIdentity = true)]
public long RoleId { get; set; }
/// <summary>
/// <20><>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>
/// </summary>
[JsonProperty, Column(DbType = "varchar(50)")]
public string RoleName { get; set; } = string.Empty;
/// <summary>
/// <20><>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>
/// </summary>
[JsonProperty, Column(DbType = "varchar(50)")]
public string RoleDesc { get; set; } = string.Empty;
///// <summary>
///// <20><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
///// </summary>
//[JsonProperty, Column(DbType = "date")]
//public DateTime CreateTime { get; set; } = DateTime.Now;
/// <summary>
/// <20><><EFBFBD><EFBFBD>
/// </summary>
[JsonProperty]
public bool IsEnable { get; set; } = true;
/// <summary>
/// <20><>ɫ<EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD>Զർ<D4B6><E0B5BC>
/// </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>
/// <20>û<EFBFBD><C3BB><EFBFBD>ɫ<EFBFBD><C9AB>ϵ<EFBFBD><CFB5>aa111
/// </summary>
[JsonObject(MemberSerialization.OptIn)]
public partial class UserRole : BaseEntity<UserRole>{
/// <summary>
/// <20><>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>1
/// </summary>
[JsonProperty]
public long RoleId { get; set; }
/// <summary>
/// <20><>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>
/// </summary>
[Navigate("RoleId")]
public Role Roles { get; set; }
/// <summary>
/// <20>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
[JsonProperty, Column(DbType = "varchar(50)")]
public string UserId { get; set; }
/// <summary>
/// <20>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>
/// </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); //ͬ<><CDAC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//<2F><><EFBFBD>õ<EFBFBD><C3B5><EFBFBD>
Fsql.CodeFirst.ApplyConfiguration(new SongConfiguration());
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//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
{
}
}

View File

@ -0,0 +1,13 @@
<wpf:FormsApplicationPage x:Class="xamarinForm.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:xamarinForm.Wpf"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
xmlns:wpf="clr-namespace:Xamarin.Forms.Platform.WPF;assembly=Xamarin.Forms.Platform.WPF">
<Grid>
</Grid>
</wpf:FormsApplicationPage>

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Xamarin.Forms;
using Xamarin.Forms.Platform.WPF;
namespace xamarinForm.Wpf
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : FormsApplicationPage
{
public MainWindow()
{
InitializeComponent();
Forms.Init();
LoadApplication(new xamarinFormApp.App());
}
}
}

View File

@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("xamarinForm.Wpf")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("xamarinForm.Wpf")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//例如,如果您在源文件中使用的是美国英语,
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace xamarinForm.Wpf.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("xamarinForm.Wpf.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,29 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace xamarinForm.Wpf.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{12EC22F5-2586-4AD3-AE03-319C2FAC0B06}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>xamarinForm.Wpf</RootNamespace>
<AssemblyName>xamarinForm.Wpf</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Xamarin.Forms.Platform.WPF">
<Version>4.8.0.1687</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\xamarinFormApp\xamarinFormApp.csproj">
<Project>{e4094717-ed1a-4174-8d86-a65d2ad1380c}</Project>
<Name>xamarinFormApp</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

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