mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +08:00
update demo
This commit is contained in:
parent
c51cffc2c2
commit
3339d96117
@ -3,6 +3,7 @@ using FreeSql.DataAnnotations;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -24,20 +25,21 @@ namespace aspnetcore_transaction.Controllers
|
|||||||
|
|
||||||
[HttpGet("1")]
|
[HttpGet("1")]
|
||||||
//[Transactional]
|
//[Transactional]
|
||||||
virtual public object Get([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
|
async public Task<object> Get([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
|
||||||
[FromServices] SongService serviceSong)
|
[FromServices] SongService serviceSong)
|
||||||
{
|
{
|
||||||
//repoSong.Insert(new Song());
|
//repoSong.Insert(new Song());
|
||||||
//repoDetail.Insert(new Detail());
|
//repoDetail.Insert(new Detail());
|
||||||
//repoSong2.Insert(new Song());
|
//repoSong2.Insert(new Song());
|
||||||
|
|
||||||
serviceSong.Test1();
|
//serviceSong.Test1();
|
||||||
|
await serviceSong.Test11();
|
||||||
return "111";
|
return "111";
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("2")]
|
[HttpGet("2")]
|
||||||
//[Transactional]
|
//[Transactional]
|
||||||
async virtual public Task<object> GetAsync([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
|
async public Task<object> GetAsync([FromServices] BaseRepository<Song> repoSong, [FromServices] BaseRepository<Detail> repoDetail, [FromServices] SongRepository repoSong2,
|
||||||
[FromServices] SongService serviceSong)
|
[FromServices] SongService serviceSong)
|
||||||
{
|
{
|
||||||
await serviceSong.Test2();
|
await serviceSong.Test2();
|
||||||
@ -61,15 +63,21 @@ namespace aspnetcore_transaction.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
||||||
public virtual void Test1()
|
public void Test1()
|
||||||
{
|
{
|
||||||
_repoSong.Insert(new Song());
|
_repoSong.Insert(new Song());
|
||||||
_repoDetail.Insert(new Detail());
|
_repoDetail.Insert(new Detail());
|
||||||
_repoSong2.Insert(new Song());
|
_repoSong2.Insert(new Song());
|
||||||
}
|
}
|
||||||
|
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
||||||
|
async public Task Test11()
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(t =>
|
||||||
|
_repoSong.InsertAsync(new Song()));
|
||||||
|
}
|
||||||
|
|
||||||
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
||||||
async public virtual Task Test2()
|
async public Task Test2()
|
||||||
{
|
{
|
||||||
await _repoSong.InsertAsync(new Song());
|
await _repoSong.InsertAsync(new Song());
|
||||||
await _repoDetail.InsertAsync(new Detail());
|
await _repoDetail.InsertAsync(new Detail());
|
||||||
@ -77,7 +85,7 @@ namespace aspnetcore_transaction.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
[Transactional(Propagation = Propagation.Nested)] //sqlite 不能嵌套事务,会锁库的
|
||||||
async public virtual Task<object> Test3()
|
async public Task<object> Test3()
|
||||||
{
|
{
|
||||||
await _repoSong.InsertAsync(new Song());
|
await _repoSong.InsertAsync(new Song());
|
||||||
await _repoDetail.InsertAsync(new Detail());
|
await _repoDetail.InsertAsync(new Detail());
|
||||||
@ -110,53 +118,4 @@ namespace aspnetcore_transaction.Controllers
|
|||||||
public int SongId { get; set; }
|
public int SongId { get; set; }
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class IdleBusExtesions
|
|
||||||
{
|
|
||||||
static AsyncLocal<string> AsyncLocalTenantId = new AsyncLocal<string>();
|
|
||||||
public static IdleBus<IFreeSql> ChangeTenant(this IdleBus<IFreeSql> ib, string tenantId)
|
|
||||||
{
|
|
||||||
AsyncLocalTenantId.Value = tenantId;
|
|
||||||
return ib;
|
|
||||||
}
|
|
||||||
public static IFreeSql Get(this IdleBus<IFreeSql> ib) => ib.Get(AsyncLocalTenantId.Value ?? "default");
|
|
||||||
public static IBaseRepository<T> GetRepository<T>(this IdleBus<IFreeSql> ib) where T : class => ib.Get().GetRepository<T>();
|
|
||||||
|
|
||||||
static void test()
|
|
||||||
{
|
|
||||||
IdleBus<IFreeSql> ib = null; //单例注入
|
|
||||||
|
|
||||||
var fsql = ib.Get(); //获取当前租户对应的 IFreeSql
|
|
||||||
|
|
||||||
var fsql00102 = ib.ChangeTenant("00102").Get(); //切换租户,后面的操作都是针对 00102
|
|
||||||
|
|
||||||
var songRepository = ib.GetRepository<Song>();
|
|
||||||
var detailRepository = ib.GetRepository<Detail>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IServiceCollection AddRepository(this IServiceCollection services, params Assembly[] assemblies)
|
|
||||||
{
|
|
||||||
services.AddScoped(typeof(IBaseRepository<>), typeof(YourDefaultRepository<>));
|
|
||||||
services.AddScoped(typeof(BaseRepository<>), typeof(YourDefaultRepository<>));
|
|
||||||
|
|
||||||
services.AddScoped(typeof(IBaseRepository<,>), typeof(YourDefaultRepository<,>));
|
|
||||||
services.AddScoped(typeof(BaseRepository<,>), typeof(YourDefaultRepository<,>));
|
|
||||||
|
|
||||||
if (assemblies?.Any() == true)
|
|
||||||
foreach (var asse in assemblies)
|
|
||||||
foreach (var repo in asse.GetTypes().Where(a => a.IsAbstract == false && typeof(IBaseRepository).IsAssignableFrom(a)))
|
|
||||||
services.AddScoped(repo);
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class YourDefaultRepository<T> : BaseRepository<T> where T : class
|
|
||||||
{
|
|
||||||
public YourDefaultRepository(IdleBus<IFreeSql> ib) : base(ib.Get(), null, null) { }
|
|
||||||
}
|
|
||||||
class YourDefaultRepository<T, TKey> : BaseRepository<T, TKey> where T : class
|
|
||||||
{
|
|
||||||
public YourDefaultRepository(IdleBus<IFreeSql> ib) : base(ib.Get(), null, null) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
3
Examples/aspnetcore_transaction/FodyWeavers.xml
Normal file
3
Examples/aspnetcore_transaction/FodyWeavers.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||||
|
<Rougamo />
|
||||||
|
</Weavers>
|
26
Examples/aspnetcore_transaction/FodyWeavers.xsd
Normal file
26
Examples/aspnetcore_transaction/FodyWeavers.xsd
Normal 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>
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -22,6 +22,7 @@ namespace aspnetcore_transaction
|
|||||||
{
|
{
|
||||||
webBuilder.UseStartup<Startup>();
|
webBuilder.UseStartup<Startup>();
|
||||||
})
|
})
|
||||||
.UseServiceProviderFactory(new FreeSql.DynamicProxyServiceProviderFactory());
|
//.UseServiceProviderFactory(new FreeSql.DynamicProxyServiceProviderFactory())
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -52,6 +52,12 @@ namespace aspnetcore_transaction
|
|||||||
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
Console.OutputEncoding = Encoding.GetEncoding("GB2312");
|
||||||
Console.InputEncoding = 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.UseHttpMethodOverride(new HttpMethodOverrideOptions { FormFieldName = "X-Http-Method-Override" });
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
@ -1,54 +1,43 @@
|
|||||||
using FreeSql;
|
using FreeSql;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Rougamo.Context;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace FreeSql
|
namespace FreeSql
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 使用事务执行,请查看 Program.cs 代码开启动态代理
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
public class TransactionalAttribute : DynamicProxyAttribute, IActionFilter
|
public class TransactionalAttribute : Rougamo.MoAttribute
|
||||||
{
|
{
|
||||||
public Propagation Propagation { get; set; } = Propagation.Required;
|
public Propagation Propagation { get; set; } = Propagation.Required;
|
||||||
public IsolationLevel IsolationLevel { get => _IsolationLevelPriv.Value; set => _IsolationLevelPriv = value; }
|
public IsolationLevel IsolationLevel { get => m_IsolationLevel.Value; set => m_IsolationLevel = value; }
|
||||||
IsolationLevel? _IsolationLevelPriv;
|
IsolationLevel? m_IsolationLevel;
|
||||||
|
|
||||||
|
static AsyncLocal<IServiceProvider> m_ServiceProvider = new AsyncLocal<IServiceProvider>();
|
||||||
|
public static void SetServiceProvider(IServiceProvider serviceProvider) =>
|
||||||
|
m_ServiceProvider.Value = serviceProvider;
|
||||||
|
|
||||||
[DynamicProxyFromServices]
|
|
||||||
#pragma warning disable IDE0044 // 添加只读修饰符
|
|
||||||
UnitOfWorkManager _uowManager;
|
|
||||||
#pragma warning restore IDE0044 // 添加只读修饰符
|
|
||||||
IUnitOfWork _uow;
|
IUnitOfWork _uow;
|
||||||
|
public override void OnEntry(MethodContext context)
|
||||||
public override Task Before(DynamicProxyBeforeArguments args) => OnBefore(_uowManager);
|
|
||||||
public override Task After(DynamicProxyAfterArguments args) => OnAfter(args.Exception);
|
|
||||||
|
|
||||||
//这里是为了 controller
|
|
||||||
public void OnActionExecuting(ActionExecutingContext context) => OnBefore(context.HttpContext.RequestServices.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager);
|
|
||||||
public void OnActionExecuted(ActionExecutedContext context) => OnAfter(context.Exception);
|
|
||||||
|
|
||||||
|
|
||||||
Task OnBefore(UnitOfWorkManager uowm)
|
|
||||||
{
|
{
|
||||||
_uow = uowm.Begin(this.Propagation, this._IsolationLevelPriv);
|
var uowManager = m_ServiceProvider.Value.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager;
|
||||||
return Task.FromResult(false);
|
_uow = uowManager.Begin(this.Propagation, this.m_IsolationLevel);
|
||||||
}
|
}
|
||||||
Task OnAfter(Exception ex)
|
public override void OnExit(MethodContext context)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (ex == null) _uow.Commit();
|
if (context.Exception == null) _uow.Commit();
|
||||||
else _uow.Rollback();
|
else _uow.Rollback();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_uow.Dispose();
|
_uow.Dispose();
|
||||||
}
|
}
|
||||||
return Task.FromResult(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
Examples/aspnetcore_transaction/TransactionalAttribute02.cs
Normal file
54
Examples/aspnetcore_transaction/TransactionalAttribute02.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
//using FreeSql;
|
||||||
|
//using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
//using System;
|
||||||
|
//using System.Collections.Generic;
|
||||||
|
//using System.Data;
|
||||||
|
//using System.Text;
|
||||||
|
//using System.Threading.Tasks;
|
||||||
|
|
||||||
|
//namespace FreeSql
|
||||||
|
//{
|
||||||
|
// /// <summary>
|
||||||
|
// /// 使用事务执行,请查看 Program.cs 代码开启动态代理
|
||||||
|
// /// </summary>
|
||||||
|
// [AttributeUsage(AttributeTargets.Method)]
|
||||||
|
// public class TransactionalAttribute : DynamicProxyAttribute, IActionFilter
|
||||||
|
// {
|
||||||
|
// public Propagation Propagation { get; set; } = Propagation.Required;
|
||||||
|
// public IsolationLevel IsolationLevel { get => _IsolationLevelPriv.Value; set => _IsolationLevelPriv = value; }
|
||||||
|
// IsolationLevel? _IsolationLevelPriv;
|
||||||
|
|
||||||
|
// [DynamicProxyFromServices]
|
||||||
|
//#pragma warning disable IDE0044 // 添加只读修饰符
|
||||||
|
// UnitOfWorkManager _uowManager;
|
||||||
|
//#pragma warning restore IDE0044 // 添加只读修饰符
|
||||||
|
// IUnitOfWork _uow;
|
||||||
|
|
||||||
|
// public override Task Before(DynamicProxyBeforeArguments args) => OnBefore(_uowManager);
|
||||||
|
// public override Task After(DynamicProxyAfterArguments args) => OnAfter(args.Exception);
|
||||||
|
|
||||||
|
// //这里是为了 controller
|
||||||
|
// public void OnActionExecuting(ActionExecutingContext context) => OnBefore(context.HttpContext.RequestServices.GetService(typeof(UnitOfWorkManager)) as UnitOfWorkManager);
|
||||||
|
// public void OnActionExecuted(ActionExecutedContext context) => OnAfter(context.Exception);
|
||||||
|
|
||||||
|
|
||||||
|
// Task OnBefore(UnitOfWorkManager uowm)
|
||||||
|
// {
|
||||||
|
// _uow = uowm.Begin(this.Propagation, this._IsolationLevelPriv);
|
||||||
|
// return Task.FromResult(false);
|
||||||
|
// }
|
||||||
|
// Task OnAfter(Exception ex)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// if (ex == null) _uow.Commit();
|
||||||
|
// else _uow.Rollback();
|
||||||
|
// }
|
||||||
|
// finally
|
||||||
|
// {
|
||||||
|
// _uow.Dispose();
|
||||||
|
// }
|
||||||
|
// return Task.FromResult(false);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
@ -11,6 +11,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Rougamo.Fody" Version="1.1.1" />
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
|
||||||
<PackageReference Include="FreeSql.DynamicProxy" Version="1.5.0" />
|
<PackageReference Include="FreeSql.DynamicProxy" Version="1.5.0" />
|
||||||
<PackageReference Include="IdleBus" Version="1.5.2" />
|
<PackageReference Include="IdleBus" Version="1.5.2" />
|
||||||
|
@ -9,10 +9,5 @@
|
|||||||
自增
|
自增
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:FreeSql.TransactionalAttribute">
|
|
||||||
<summary>
|
|
||||||
使用事务执行,请查看 Program.cs 代码开启动态代理
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
</members>
|
</members>
|
||||||
</doc>
|
</doc>
|
||||||
|
@ -800,5 +800,14 @@
|
|||||||
<param name="that"></param>
|
<param name="that"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:Microsoft.Extensions.DependencyInjection.FreeSqlRepositoryDependencyInjection.AddFreeRepository(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.Action{FreeSql.FluentDataFilter},System.Reflection.Assembly[])">
|
||||||
|
<summary>
|
||||||
|
批量注入 Repository,可以参考代码自行调整
|
||||||
|
</summary>
|
||||||
|
<param name="services"></param>
|
||||||
|
<param name="globalDataFilter"></param>
|
||||||
|
<param name="assemblies"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
</members>
|
</members>
|
||||||
</doc>
|
</doc>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user