Initial_commit_SecMPS_v2
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.BackgroundServices.mail;
|
||||
using VolPro.Core.PerformanceMonitor;
|
||||
|
||||
namespace VolPro.Core.BackgroundServices
|
||||
{
|
||||
public static class BackgroundServiceExtensions
|
||||
{
|
||||
public static IServiceCollection AddBackgroundServices(this WebApplicationBuilder builder)
|
||||
{
|
||||
// 注册邮件服务
|
||||
builder.Services.AddSingleton<IMailService, MailService>();
|
||||
// 注册邮件后台服务
|
||||
builder.Services.AddHostedService<MailBackgroundService>();
|
||||
|
||||
return builder.Services;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.BackgroundServices.mail
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件服务接口
|
||||
/// </summary>
|
||||
public interface IMailService
|
||||
{
|
||||
/// <summary>
|
||||
/// 直接发送邮件(同步发送)
|
||||
/// </summary>
|
||||
/// <param name="email">接收人邮箱,多个用逗号分隔</param>
|
||||
/// <param name="subject">主题</param>
|
||||
/// <param name="body">内容</param>
|
||||
/// <param name="isHtml">是否HTML</param>
|
||||
/// <returns></returns>
|
||||
Task SendAsync(string email, string subject, string body, bool isHtml = true);
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送邮件(加入队列)
|
||||
/// </summary>
|
||||
/// <param name="email">接收人邮箱,多个用逗号分隔</param>
|
||||
/// <param name="subject">主题</param>
|
||||
/// <param name="body">内容</param>
|
||||
/// <param name="isHtml">是否HTML</param>
|
||||
/// <returns></returns>
|
||||
Task SendQueuedAsync(string email, string subject, string body, bool isHtml = true);
|
||||
|
||||
/// <summary>
|
||||
/// 发送邮件(加入队列,同步方法)
|
||||
/// </summary>
|
||||
/// <param name="email">接收人邮箱,多个用逗号分隔</param>
|
||||
/// <param name="subject">主题</param>
|
||||
/// <param name="body">内容</param>
|
||||
/// <param name="isHtml">是否HTML</param>
|
||||
void Send(string email, string subject, string body, bool isHtml = true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Quartz.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.BackgroundServices.mail
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件后台服务,使用Channel队列处理邮件发送
|
||||
/// </summary>
|
||||
public class MailBackgroundService : BackgroundService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public MailBackgroundService(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
Console.WriteLine("发送邮件服务已启动");
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 从队列中读取邮件请求
|
||||
var mailRequest = await MailService.MailQueue.Reader.ReadAsync(stoppingToken);
|
||||
if (mailRequest.RetryCount > mailRequest.MaxRetryCount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
using (var scope = _serviceProvider.CreateScope())
|
||||
{
|
||||
var mailService = scope.ServiceProvider.GetRequiredService<IMailService>();
|
||||
|
||||
try
|
||||
{
|
||||
await mailService.SendAsync(mailRequest.MailMessage.To,
|
||||
mailRequest.MailMessage.Subject,
|
||||
mailRequest.MailMessage.Body,
|
||||
mailRequest.MailMessage.IsHtml);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mailRequest.RetryCount++;
|
||||
Console.WriteLine($"邮件发送异常:{ex.Message + ex.StackTrace}");
|
||||
Core.Services.Logger.AddAsync($"邮件发送异常:{ex.Message + ex.StackTrace}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ChannelClosedException)
|
||||
{
|
||||
// 队列已关闭,退出循环
|
||||
break;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 取消令牌触发,退出循环
|
||||
break;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 邮件队列处理出现未知错误,短暂延迟后继续处理
|
||||
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// 关闭队列写入器
|
||||
MailService.MailQueue.Writer.Complete();
|
||||
|
||||
// 等待所有待处理的邮件完成
|
||||
await base.StopAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.BackgroundServices.mail
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件请求模型,用于队列处理
|
||||
/// </summary>
|
||||
public class MailRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求ID
|
||||
/// </summary>
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// 邮件消息
|
||||
/// </summary>
|
||||
public required MailRequestMessage MailMessage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// 重试次数
|
||||
/// </summary>
|
||||
public int RetryCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 最大重试次数
|
||||
/// </summary>
|
||||
public int MaxRetryCount { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// 下次重试时间
|
||||
/// </summary>
|
||||
public DateTime? NextRetryTime { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.BackgroundServices.mail
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件消息模型
|
||||
/// </summary>
|
||||
public class MailRequestMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 收件人地址
|
||||
/// </summary>
|
||||
public string To { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 抄送人地址
|
||||
/// </summary>
|
||||
public string Cc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 密送人地址
|
||||
/// </summary>
|
||||
public string Bcc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮件主题
|
||||
/// </summary>
|
||||
public required string Subject { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邮件内容
|
||||
/// </summary>
|
||||
public required string Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为HTML格式
|
||||
/// </summary>
|
||||
public bool IsHtml { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 附件路径列表
|
||||
/// </summary>
|
||||
public List<string> Attachments { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 优先级
|
||||
/// </summary>
|
||||
public MailPriority Priority { get; set; } = MailPriority.Normal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 邮件优先级
|
||||
/// </summary>
|
||||
public enum MailPriority
|
||||
{
|
||||
Low = 0,
|
||||
Normal = 1,
|
||||
High = 2
|
||||
}
|
||||
}
|
||||
175
api_sqlsugar/VolPro.Core/BackgroundServices/mail/MailService.cs
Normal file
175
api_sqlsugar/VolPro.Core/BackgroundServices/mail/MailService.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Extensions;
|
||||
|
||||
namespace VolPro.Core.BackgroundServices.mail
|
||||
{
|
||||
/// <summary>
|
||||
/// 邮件服务实现
|
||||
/// </summary>
|
||||
public class MailService : IMailService
|
||||
{
|
||||
// 邮件队列Channel
|
||||
private static readonly Channel<MailRequest> _mailQueue;
|
||||
|
||||
// 提供静态访问Channel的方法
|
||||
public static Channel<MailRequest> MailQueue => _mailQueue;
|
||||
|
||||
// 邮件配置信息
|
||||
private static string address { get; set; }
|
||||
private static string authPwd { get; set; }
|
||||
private static string name { get; set; }
|
||||
private static string host { get; set; }
|
||||
private static int port;
|
||||
private static bool enableSsl { get; set; }
|
||||
|
||||
static MailService()
|
||||
{
|
||||
// 初始化邮件队列Channel
|
||||
_mailQueue = Channel.CreateBounded<MailRequest>(new BoundedChannelOptions(1000)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.Wait
|
||||
});
|
||||
|
||||
// 读取邮件配置
|
||||
var section = AppSetting.GetSection("Mail");
|
||||
address = section["Address"];
|
||||
authPwd = section["AuthPwd"];
|
||||
name = section["Name"];
|
||||
host = section["Host"];
|
||||
port = section["Port"].GetInt();
|
||||
enableSsl = section["EnableSsl"].GetBool();
|
||||
}
|
||||
|
||||
public MailService()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实际发送邮件的核心方法
|
||||
/// </summary>
|
||||
private async Task SendEmailCoreAsync(string emails, string subject, string body, bool isHtml = true)
|
||||
{
|
||||
// 解析多个接收人
|
||||
var recipients = new List<string>();
|
||||
if (!string.IsNullOrEmpty(emails))
|
||||
{
|
||||
foreach (var addr in emails.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
recipients.Add(addr.Trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (recipients.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建邮件消息
|
||||
using var message = new MailMessage
|
||||
{
|
||||
From = new MailAddress(address, name)
|
||||
};
|
||||
|
||||
// 添加收件人
|
||||
foreach (var recipient in recipients)
|
||||
{
|
||||
message.To.Add(recipient);
|
||||
}
|
||||
|
||||
message.Subject = subject;
|
||||
message.Body = body;
|
||||
message.IsBodyHtml = isHtml;
|
||||
|
||||
// 配置SMTP客户端
|
||||
using var smtpClient = new SmtpClient
|
||||
{
|
||||
Host = host,
|
||||
Port = port,
|
||||
EnableSsl = enableSsl,
|
||||
Credentials = new NetworkCredential(address, authPwd),
|
||||
DeliveryMethod = SmtpDeliveryMethod.Network,
|
||||
UseDefaultCredentials = false
|
||||
};
|
||||
|
||||
// 发送邮件
|
||||
await smtpClient.SendMailAsync(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送邮件(加入队列)
|
||||
/// </summary>
|
||||
private async Task SendEmailQueuedAsync(MailRequestMessage mailMessage)
|
||||
{
|
||||
var request = new MailRequest
|
||||
{
|
||||
MailMessage = mailMessage,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
await _mailQueue.Writer.WriteAsync(request);
|
||||
}
|
||||
|
||||
public void Send(string email, string subject, string body, bool isHtml = true)
|
||||
{
|
||||
if (string.IsNullOrEmpty(email))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// 支持多个接收人,用逗号分隔
|
||||
var mailMessage = new MailRequestMessage
|
||||
{
|
||||
To = email,
|
||||
Subject = subject,
|
||||
Body = body,
|
||||
IsHtml = isHtml
|
||||
};
|
||||
_mailQueue.Writer.TryWrite(new MailRequest
|
||||
{
|
||||
MailMessage = mailMessage,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 直接发送邮件(同步发送,不加入队列)
|
||||
/// </summary>
|
||||
public async Task SendAsync(string email, string subject, string body, bool isHtml = true)
|
||||
{
|
||||
await SendEmailCoreAsync(email, subject, body, isHtml);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步发送邮件(加入队列)
|
||||
/// </summary>
|
||||
public async Task SendQueuedAsync(string email, string subject, string body, bool isHtml = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(email))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mailMessage = new MailRequestMessage
|
||||
{
|
||||
To = email,
|
||||
Subject = subject,
|
||||
Body = body,
|
||||
IsHtml = isHtml
|
||||
};
|
||||
|
||||
await SendEmailQueuedAsync(mailMessage);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
api_sqlsugar/VolPro.Core/BaseInterface/IServices.cs
Normal file
10
api_sqlsugar/VolPro.Core/BaseInterface/IServices.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.BaseInterface
|
||||
{
|
||||
public interface IServices
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//using VolPro.Core.Dapper;
|
||||
//using VolPro.Core.DBManager;
|
||||
//using VolPro.Core.EFDbContext;
|
||||
//using VolPro.Core.Extensions;
|
||||
//using VolPro.Entity.DomainModels;
|
||||
//using Microsoft.AspNetCore.Mvc;
|
||||
//using Microsoft.EntityFrameworkCore;
|
||||
//using Newtonsoft.Json;
|
||||
//using System;
|
||||
//using System.Data;
|
||||
//using System.Data.SqlClient;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using System.Threading.Tasks;
|
||||
|
||||
//namespace VolPro.Core.BaseProvider.DictionaryComponent
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 组件视图,参照:https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-2.1
|
||||
// /// 与Controller命名一样必须以ViewComponent结尾
|
||||
// /// </summary>
|
||||
// public class DictionaryViewComponent : ViewComponent
|
||||
// {
|
||||
// public async Task<IViewComponentResult> InvokeAsync(string dropDownIds)
|
||||
// {
|
||||
// if (string.IsNullOrEmpty(dropDownIds))
|
||||
// return null;
|
||||
|
||||
// string[] dicNos = dropDownIds.Split(',');
|
||||
// StringBuilder stringBuilder = new StringBuilder();
|
||||
// SysDbContext context = DBServerProvider.GetEFDbContext();
|
||||
|
||||
|
||||
// var dicData = await context.Queryable<Sys_Dictionary>()
|
||||
// .LeftJoin<Sys_DictionaryList>((o, cus) => o.Dic_ID == cus.Dic_ID)
|
||||
// .Where(d => dicNos.Contains(d.DicNo))
|
||||
// .Select((d, list) => new { list.DicValue, list.DicName, d.Config, d.DbSql, list.OrderNo, d.DicNo })
|
||||
// .ToListAsync();
|
||||
// foreach (var item in dicData.GroupBy(x => x.DicNo))
|
||||
// {
|
||||
// stringBuilder.AppendLine($" var optionConfig{item.Key} = {item.Select(x => x.Config).FirstOrDefault()}");
|
||||
|
||||
// string dbSql = item.Select(s => s.DbSql).FirstOrDefault();
|
||||
|
||||
// stringBuilder.AppendLine($@" var dataSource{item.Key} = {
|
||||
// (!string.IsNullOrEmpty(dbSql)
|
||||
// ? DBServerProvider.GetSqlDapper().QueryList<object>(dbSql, null).Serialize()
|
||||
// : item.OrderByDescending(o => o.OrderNo).
|
||||
// Select(s => new { s.DicName, s.DicValue }).ToList()
|
||||
// .Serialize())
|
||||
// }.convertToValueText(optionConfig{item.Key})");
|
||||
// stringBuilder.AppendLine($" optionConfig{item.Key}.data = dataSource{item.Key};");
|
||||
// }
|
||||
// ViewBag.Dic = stringBuilder.ToString();
|
||||
// return View("~/Views/Shared/Dictionary.cshtml");
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
328
api_sqlsugar/VolPro.Core/BaseProvider/IRepository.cs
Normal file
328
api_sqlsugar/VolPro.Core/BaseProvider/IRepository.cs
Normal file
@@ -0,0 +1,328 @@
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Dapper;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Utilities;
|
||||
using VolPro.Entity.SystemModels;
|
||||
|
||||
namespace VolPro.Core.BaseProvider
|
||||
{
|
||||
public interface IRepository<TEntity> where TEntity : BaseEntity
|
||||
{
|
||||
|
||||
BaseDbContext BaseDbContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// EF DBContext
|
||||
/// </summary>
|
||||
ISqlSugarClient DbContext { get; }
|
||||
|
||||
ISqlSugarClient SqlSugarClient { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行事务。将在执行的方法带入Action
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent DbContextBeginTransaction(Func<WebResponseContent> action);
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="where">查询条件</param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
List<TEntity> Find(Expression<Func<TEntity, bool>> where, bool filterDeleted = true);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="orderBySelector">排序字段,数据格式如:
|
||||
/// orderBy = x => new Dictionary<object, bool>() {
|
||||
/// { x.BalconyName,QueryOrderBy.Asc},
|
||||
/// { x.TranCorpCode1,QueryOrderBy.Desc}
|
||||
/// };
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
TEntity FindFirst(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
|
||||
|
||||
ISugarQueryable<TEntity> WhereIF([NotNull] Expression<Func<TEntity, object>> field, string value, LinqExpressionType linqExpression = LinqExpressionType.Equal);
|
||||
|
||||
/// <summary>
|
||||
/// if判断查询
|
||||
/// </summary>
|
||||
/// 查询示例,value不为null时参与条件查询
|
||||
/// string value = null;
|
||||
/// repository.WhereIF(value!=null,x=>x.Creator==value);
|
||||
/// <param name="checkCondition"></param>
|
||||
/// <param name="predicate"></param>
|
||||
/// <returns></returns>
|
||||
ISugarQueryable<TEntity> WhereIF(bool checkCondition, Expression<Func<TEntity, bool>> predicate);
|
||||
|
||||
/// <summary>
|
||||
/// if判断查询
|
||||
/// </summary>
|
||||
/// 查询示例,value不为null时参与条件查询
|
||||
/// string value = null;
|
||||
/// repository.WhereIF<Sys_User>(value!=null,x=>x.Creator==value);
|
||||
/// <param name="checkCondition"></param>
|
||||
/// <param name="predicate"></param>
|
||||
/// <returns></returns>
|
||||
ISugarQueryable<T> WhereIF<T>(bool checkCondition, Expression<Func<T, bool>> predicate) where T : class, new();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="predicate">where条件</param>
|
||||
/// <param name="orderBy">排序字段,数据格式如:
|
||||
/// orderBy = x => new Dictionary<object, bool>() {
|
||||
/// { x.BalconyName,QueryOrderBy.Asc},
|
||||
/// { x.TranCorpCode1,QueryOrderBy.Desc}
|
||||
/// };
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
ISugarQueryable<TEntity> FindAsIQueryable(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy = null, bool filterDeleted = true);
|
||||
/// <summary>
|
||||
/// 通过条件查询数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="predicate">查询条件</param>
|
||||
/// <param name="selector">返回类型如:Find(x => x.UserName == loginInfo.userName, p => new { uname = p.UserName });</param>
|
||||
/// <returns></returns>
|
||||
List<T> Find<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 根据条件,返回查询的类
|
||||
/// </summary>
|
||||
/// <typeparam name="TFind"></typeparam>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
List<TFind> Find<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class,new();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TFind"></typeparam>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<TFind> FindAsyncFirst<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
///<param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<TEntity> FindAsyncFirst(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TFind"></typeparam>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<List<TFind>> FindAsync<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
///<param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<TEntity> FindFirstAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<List<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="selector"></param>
|
||||
///<param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<List<T>> FindAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="selector"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<T> FindFirstAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true);
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
bool Exists(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true);
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TExists"></typeparam>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
bool Exists<TExists>(Expression<Func<TExists, bool>> predicate, bool filterDeleted = true) where TExists : class, new();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TExists"></typeparam>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="filterDeleted">是否过滤逻辑删除的数据,默认过</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> ExistsAsync<TExists>(Expression<Func<TExists, bool>> predicate, bool filterDeleted = true) where TExists : class, new();
|
||||
|
||||
ISugarQueryable<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> incluedProperty) where TProperty : new();
|
||||
|
||||
|
||||
|
||||
|
||||
ISugarQueryable<TFind> IQueryablePage<TFind>(int pageIndex, int pagesize, out int rowcount, Expression<Func<TFind, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy, bool returnRowCount = true) where TFind : class, new();
|
||||
|
||||
|
||||
ISugarQueryable<TEntity> IQueryablePage(ISugarQueryable<TEntity> queryable, int pageIndex, int pagesize, out int rowcount, Dictionary<string, QueryOrderBy> orderBy, bool returnRowCount = true);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="properties">指定更新字段:x=>new {x.Name,x.Enable}</param>
|
||||
/// <param name="saveChanges">是否保存</param>
|
||||
/// <returns></returns>
|
||||
|
||||
int Update(TEntity entity, Expression<Func<TEntity, object>> properties, bool saveChanges = false);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="properties">指定更新字段:x=>new {x.Name,x.Enable}</param>
|
||||
/// <param name="saveChanges">是否保存</param>
|
||||
/// <returns></returns>
|
||||
int Update<TSource>(TSource entity, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class, new();
|
||||
|
||||
int Update<TSource>(TSource entity, bool saveChanges = false) where TSource : class, new();
|
||||
|
||||
int Update<TSource>(TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new();
|
||||
|
||||
int UpdateRange<TSource>(IEnumerable<TSource> entities, bool saveChanges = false) where TSource : class, new();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="properties">指定更新字段:x=>new {x.Name,x.Enable}</param>
|
||||
/// <param name="saveChanges">是否保存</param>
|
||||
/// <returns></returns>
|
||||
int UpdateRange<TSource>(IEnumerable<TSource> models, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class, new();
|
||||
|
||||
int UpdateRange<TSource>(IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class, new();
|
||||
|
||||
|
||||
/// <summary>
|
||||
///修改时同时对明细的添加、删除、修改
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="updateDetail">是否修改明细</param>
|
||||
/// <param name="delNotExist">是否删除明细不存在的数据</param>
|
||||
/// <param name="updateMainFields">主表指定修改字段</param>
|
||||
/// <param name="updateDetailFields">明细指定修改字段</param>
|
||||
/// <param name="saveChange">是否保存</param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent UpdateRange<Detail>(TEntity entity,
|
||||
bool updateDetail = false,
|
||||
bool delNotExist = false,
|
||||
Expression<Func<TEntity, object>> updateMainFields = null,
|
||||
Expression<Func<Detail, object>> updateDetailFields = null,
|
||||
bool saveChange = false) where Detail : class, new();
|
||||
|
||||
void Delete(TEntity model, bool saveChanges = false);
|
||||
void Delete<T>(T model, bool saveChanges = false) where T : class, new();
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
/// <param name="delList">是否将子表的数据也删除</param>
|
||||
/// <param name="saveChange">是否执行保存数据库</param>
|
||||
/// <returns></returns>
|
||||
int DeleteWithKeys(object[] keys, bool saveChange = true);
|
||||
|
||||
/// <summary>
|
||||
/// 写入数据并设置自增
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
void AddWithSetIdentity(TEntity entity);
|
||||
|
||||
void AddWithSetIdentity<T>(T entity) where T : class, new();
|
||||
|
||||
void Add(TEntity entities, bool SaveChanges = false);
|
||||
|
||||
void Add<T>(T entities, bool saveChanges = false) where T : class, new();
|
||||
|
||||
// void AddRange(IEnumerable<TEntity> entities, bool SaveChanges = false);
|
||||
|
||||
|
||||
|
||||
void AddRange<T>(List<T> entities, bool saveChanges = false)
|
||||
where T : class, new();
|
||||
|
||||
|
||||
int SaveChanges();
|
||||
|
||||
Task<int> SaveChangesAsync();
|
||||
|
||||
|
||||
|
||||
int ExecuteSqlCommand(string sql, params SugarParameter[] SugarParameters);
|
||||
|
||||
List<TEntity> FromSql(string sql, params SugarParameter[] SugarParameters);
|
||||
|
||||
/// <summary>
|
||||
/// 执行sql
|
||||
/// 使用方式 FormattableString sql=$"select * from xx where name ={xx} and pwd={xx1} ",
|
||||
/// FromSqlInterpolated内部处理sql注入的问题,直接在{xx}写对应的值即可
|
||||
/// 注意:sql必须 select * 返回所有TEntity字段,
|
||||
/// </summary>
|
||||
/// <param name="formattableString"></param>
|
||||
/// <returns></returns>
|
||||
// ISugarQueryable<TEntity> FromSqlInterpolated([System.Diagnostics.CodeAnalysis.NotNull] FormattableString sql);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 取消上下文跟踪(2021.08.22)
|
||||
/// 更新报错时,请调用此方法:The instance of entity type 'XXX' cannot be tracked because another instance with the same key value for {'XX'} is already being tracked.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
void Detached(TEntity entity);
|
||||
void DetachedRange(IEnumerable<TEntity> entities);
|
||||
}
|
||||
}
|
||||
189
api_sqlsugar/VolPro.Core/BaseProvider/IService.cs
Normal file
189
api_sqlsugar/VolPro.Core/BaseProvider/IService.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using VolPro.Core.CacheManager;
|
||||
using VolPro.Core.Utilities;
|
||||
using VolPro.Core.WorkFlow;
|
||||
using VolPro.Entity.DomainModels;
|
||||
using VolPro.Entity.SystemModels;
|
||||
|
||||
namespace VolPro.Core.BaseProvider
|
||||
{
|
||||
public interface IService<T> where T : BaseEntity
|
||||
{
|
||||
|
||||
CacheManager.ICacheService CacheContext { get; }
|
||||
Microsoft.AspNetCore.Http.HttpContext Context { get; }
|
||||
string WorkFlowTableName { get; set; }
|
||||
|
||||
ISugarQueryable<T> FindAsIQueryable(Expression<Func<T, bool>> predicate, bool filterDeleted = true);
|
||||
/// <summary>
|
||||
/// 将前端table的查询条件转换为查询ISugarQueryable
|
||||
/// </summary>
|
||||
/// <param name="options">前端查询参数</param>
|
||||
/// <param name="useTenancy">是否使用数据隔离</param>
|
||||
/// <returns></returns>
|
||||
ISugarQueryable<T> FindAsIQueryable(PageDataOptions options, bool useTenancy = true);
|
||||
|
||||
/// <summary>
|
||||
/// 查询
|
||||
/// </summary>
|
||||
/// <param name="pageData"></param>
|
||||
/// <returns></returns>
|
||||
PageGridData<T> GetPageData(PageDataOptions pageData);
|
||||
|
||||
object GetDetailPage(PageDataOptions pageData);
|
||||
|
||||
WebResponseContent Upload(List<IFormFile> files);
|
||||
|
||||
WebResponseContent DownLoadTemplate();
|
||||
|
||||
WebResponseContent Import(List<IFormFile> files);
|
||||
/// <summary>
|
||||
/// 导出
|
||||
/// </summary>
|
||||
/// <param name="pageData"></param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent Export(PageDataOptions pageData);
|
||||
|
||||
/// <summary>
|
||||
/// 新增
|
||||
/// </summary>
|
||||
/// <param name="saveDataModel">主表与子表的数据</param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent Add(SaveModel saveDataModel);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="entity">保存的实体</param>
|
||||
/// <param name="validationEntity">是否对实体进行校验</param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent AddEntity(T entity, bool validationEntity = true);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TDetail"></typeparam>
|
||||
/// <param name="entity">保存的实体</param>
|
||||
/// <param name="list">保存的明细</param>
|
||||
/// <param name="validationEntity">是否对实体进行校验</param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent Add<TDetail>(T entity, List<TDetail> list = null, bool validationEntity = true) where TDetail : class, new();
|
||||
/// <summary>
|
||||
/// 编辑
|
||||
/// </summary>
|
||||
/// <param name="saveDataModel">主表与子表的数据</param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent Update(SaveModel saveDataModel);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除数据
|
||||
/// </summary>
|
||||
/// <param name="keys">删除的主键</param>
|
||||
/// <param name="delList">是否删除对应明细(默认会删除明细)</param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent Del(object[] keys, bool delList = true);
|
||||
|
||||
WebResponseContent Audit(object[] id, int? auditStatus, string auditReason);
|
||||
|
||||
/// <summary>
|
||||
/// 撤销审批
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
/// <param name="status">1=撤销,-1终止</param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent CancelAudit(AntiData antiData, int status);
|
||||
|
||||
/// <summary>
|
||||
/// 催办
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent UrgentAudit(object[] keys);
|
||||
/// <summary>
|
||||
/// 反审
|
||||
/// </summary>
|
||||
/// <param name="antiData"></param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent AntiAudit(AntiData antiData);
|
||||
|
||||
/// <summary>
|
||||
/// 重新生成流程或者回退流程
|
||||
/// </summary>
|
||||
/// <param name="id">表数据id</param>
|
||||
/// <param name="msg">重写流程的日志信息</param>
|
||||
/// <param name="flowWriteState">重新开始或回退到上一级节点</param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent RestartWorkFlowAudit(object id, string msg, FlowWriteState flowWriteState);
|
||||
/// <summary>
|
||||
/// 提交审批数据 2023.11.12
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="flowWriteState"></param>
|
||||
/// <returns></returns>
|
||||
WebResponseContent SubmitWorkFlowAudit(object[] ids);
|
||||
bool AddProcese(T entity);
|
||||
|
||||
(string, T, bool) ApiValidate(string bizContent, Expression<Func<T, object>> expression = null);
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TInput"></typeparam>
|
||||
/// <param name="bizContent"></param>
|
||||
/// <param name="expression">对指属性验证格式如:x=>new { x.UserName,x.Value }</param>
|
||||
/// <returns>(string,TInput, bool) string:返回验证消息,TInput:bizContent序列化后的对象,bool:验证是否通过</returns>
|
||||
(string, TInput, bool) ApiValidateInput<TInput>(string bizContent, Expression<Func<TInput, object>> expression);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TInput"></typeparam>
|
||||
/// <param name="bizContent"></param>
|
||||
/// <param name="expression">对指属性验证格式如:x=>new { x.UserName,x.Value }</param>
|
||||
/// <param name="validateExpression">对指定的字段只做合法性判断比如长度是是否超长</param>
|
||||
/// <returns>(string,TInput, bool) string:返回验证消息,TInput:bizContent序列化后的对象,bool:验证是否通过</returns>
|
||||
(string, TInput, bool) ApiValidateInput<TInput>(string bizContent, Expression<Func<TInput, object>> expression, Expression<Func<TInput, object>> validateExpression);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 将数据源映射到新的数据中,List<TSource>映射到List<TResult>或TSource映射到TResult
|
||||
/// 目前只支持Dictionary或实体类型
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="resultExpression">只映射返回对象的指定字段</param>
|
||||
/// <param name="sourceExpression">只映射数据源对象的指定字段</param>
|
||||
/// 过滤条件表达式调用方式:List表达式x => new { x[0].MenuName, x[0].Menu_Id},表示指定映射MenuName,Menu_Id字段
|
||||
/// List<Sys_Menu> list = new List<Sys_Menu>();
|
||||
/// list.MapToObject<List<Sys_Menu>, List<Sys_Menu>>(x => new { x[0].MenuName, x[0].Menu_Id}, null);
|
||||
///
|
||||
///过滤条件表达式调用方式:实体表达式x => new { x.MenuName, x.Menu_Id},表示指定映射MenuName,Menu_Id字段
|
||||
/// Sys_Menu sysMenu = new Sys_Menu();
|
||||
/// sysMenu.MapToObject<Sys_Menu, Sys_Menu>(x => new { x.MenuName, x.Menu_Id}, null);
|
||||
/// <returns></returns>
|
||||
TResult MapToEntity<TSource, TResult>(TSource source, Expression<Func<TResult, object>> resultExpression,
|
||||
Expression<Func<TSource, object>> sourceExpression = null) where TResult : class;
|
||||
|
||||
/// <summary>
|
||||
/// 将一个实体的赋到另一个实体上,应用场景:
|
||||
/// 两个实体,a a1= new a();b b1= new b(); a1.P=b1.P; a1.Name=b1.Name;
|
||||
/// </summary>
|
||||
/// <typeparam name="TSource"></typeparam>
|
||||
/// <typeparam name="TResult"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="expression">指定对需要的字段赋值,格式x=>new {x.Name,x.P},返回的结果只会对Name与P赋值</param>
|
||||
void MapValueToEntity<TSource, TResult>(TSource source, TResult result, Expression<Func<TResult, object>> expression = null) where TResult : class;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
656
api_sqlsugar/VolPro.Core/BaseProvider/RepositoryBase.cs
Normal file
656
api_sqlsugar/VolPro.Core/BaseProvider/RepositoryBase.cs
Normal file
@@ -0,0 +1,656 @@
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Dapper;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.Services;
|
||||
using VolPro.Core.Utilities;
|
||||
using VolPro.Entity;
|
||||
using VolPro.Entity.SystemModels;
|
||||
|
||||
namespace VolPro.Core.BaseProvider
|
||||
{
|
||||
public abstract class RepositoryBase<TEntity> where TEntity : BaseEntity, new()
|
||||
{
|
||||
public RepositoryBase(BaseDbContext dbContext)
|
||||
{
|
||||
this.DefaultDbContext = dbContext;
|
||||
}
|
||||
|
||||
private BaseDbContext DefaultDbContext { get; set; }
|
||||
public BaseDbContext BaseDbContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return DefaultDbContext;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual ISqlSugarClient DbContext
|
||||
{
|
||||
get { return DefaultDbContext.SqlSugarClient; }
|
||||
}
|
||||
|
||||
public virtual ISqlSugarClient SqlSugarClient
|
||||
{
|
||||
get
|
||||
{
|
||||
return DefaultDbContext.SqlSugarClient;
|
||||
}
|
||||
}
|
||||
private ISugarQueryable<TEntity> DBSet
|
||||
{
|
||||
get { return BaseDbContext.Set<TEntity>(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行事务
|
||||
/// </summary>
|
||||
/// <param name="action">如果返回false则回滚事务(可自行定义规则)</param>
|
||||
/// <returns></returns>
|
||||
public virtual WebResponseContent DbContextBeginTransaction(Func<WebResponseContent> action)
|
||||
{
|
||||
if (DbContext.Ado.IsAnyTran())
|
||||
{
|
||||
return action();
|
||||
}
|
||||
WebResponseContent webResponse = new WebResponseContent();
|
||||
try
|
||||
{
|
||||
DbContext.Ado.BeginTran();
|
||||
|
||||
webResponse = action();
|
||||
if (webResponse.Status)
|
||||
{
|
||||
DbContext.Ado.CommitTran();
|
||||
}
|
||||
else
|
||||
{
|
||||
DbContext.Ado.RollbackTran();
|
||||
|
||||
}
|
||||
return webResponse;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DbContext.Ado.RollbackTran();
|
||||
string message = ex.Message + ex?.InnerException + ex?.StackTrace;
|
||||
if (HttpContext.Current.GetService<Microsoft.AspNetCore.Hosting.IWebHostEnvironment>().IsDevelopment())
|
||||
{
|
||||
return webResponse.Error(message);
|
||||
}
|
||||
Logger.Error(message);
|
||||
return webResponse.Error("处理异常");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Exists<TExists>(Expression<Func<TExists, bool>> predicate, bool filterDeleted = true) where TExists : class, new()
|
||||
{
|
||||
return BaseDbContext.Set<TExists>(filterDeleted).Any(predicate);
|
||||
}
|
||||
|
||||
public virtual Task<bool> ExistsAsync<TExists>(Expression<Func<TExists, bool>> predicate, bool filterDeleted = true) where TExists : class, new()
|
||||
{
|
||||
return BaseDbContext.Set<TExists>(filterDeleted).AnyAsync(predicate);
|
||||
}
|
||||
|
||||
public virtual bool Exists(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
|
||||
{
|
||||
var query = BaseDbContext.Set<TEntity>(filterDeleted);
|
||||
if (typeof(TEntity).GetSugarSplitTable() != null)
|
||||
{
|
||||
return query.SplitTable().Any(predicate);
|
||||
}
|
||||
return query.Any(predicate);
|
||||
}
|
||||
|
||||
public virtual Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
|
||||
{
|
||||
return BaseDbContext.Set<TEntity>(filterDeleted).AnyAsync(predicate);
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询字段不为null或者为空
|
||||
/// </summary>
|
||||
/// <param name="field">x=>new {x.字段}</param>
|
||||
/// <param name="value">查询的类</param>
|
||||
/// <param name="linqExpression">查询类型</param>
|
||||
/// <returns></returns>
|
||||
public virtual ISugarQueryable<TEntity> WhereIF([NotNull] Expression<Func<TEntity, object>> field, string value, LinqExpressionType linqExpression = LinqExpressionType.Equal)
|
||||
{
|
||||
return BaseDbContext.Set<TEntity>().WhereNotEmpty(field, value, linqExpression);
|
||||
}
|
||||
|
||||
public virtual ISugarQueryable<TEntity> WhereIF(bool checkCondition, Expression<Func<TEntity, bool>> predicate)
|
||||
{
|
||||
if (checkCondition)
|
||||
{
|
||||
return BaseDbContext.Set<TEntity>().Where(predicate);
|
||||
}
|
||||
return BaseDbContext.Set<TEntity>();
|
||||
}
|
||||
|
||||
public virtual ISugarQueryable<T> WhereIF<T>(bool checkCondition, Expression<Func<T, bool>> predicate) where T : class, new()
|
||||
{
|
||||
if (checkCondition)
|
||||
{
|
||||
return BaseDbContext.Set<T>().Where(predicate);
|
||||
}
|
||||
return BaseDbContext.Set<T>();
|
||||
}
|
||||
|
||||
|
||||
public virtual List<TFind> Find<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new()
|
||||
{
|
||||
return BaseDbContext.Set<TFind>(filterDeleted).Where(predicate).ToList();
|
||||
}
|
||||
|
||||
public virtual async Task<TFind> FindAsyncFirst<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new()
|
||||
{
|
||||
return await FindAsISugarQueryable(predicate, filterDeleted).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<TEntity> FindAsyncFirst(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
|
||||
{
|
||||
return await FindAsISugarQueryable<TEntity>(predicate, filterDeleted).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<List<TFind>> FindAsync<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class, new()
|
||||
{
|
||||
return await FindAsISugarQueryable<TFind>(predicate, filterDeleted).ToListAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<List<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
|
||||
{
|
||||
return await FindAsISugarQueryable(predicate, filterDeleted).ToListAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<TEntity> FindFirstAsync(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
|
||||
{
|
||||
return await FindAsISugarQueryable(predicate, filterDeleted).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<List<T>> FindAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true)
|
||||
{
|
||||
return await FindAsISugarQueryable(predicate, filterDeleted).Select(selector).ToListAsync();
|
||||
}
|
||||
|
||||
public virtual async Task<T> FindFirstAsync<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true)
|
||||
{
|
||||
return await FindAsISugarQueryable(predicate, filterDeleted).Select(selector).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
private ISugarQueryable<TFind> FindAsISugarQueryable<TFind>(Expression<Func<TFind, bool>> predicate, bool filterDeleted = true) where TFind : class,new()
|
||||
{
|
||||
return BaseDbContext.Set<TFind>(filterDeleted).Where(predicate);
|
||||
}
|
||||
|
||||
|
||||
public virtual List<T> Find<T>(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, T>> selector, bool filterDeleted = true)
|
||||
{
|
||||
return BaseDbContext.Set<TEntity>(filterDeleted).Where(predicate).Select(selector).ToList();
|
||||
}
|
||||
/// <summary>
|
||||
/// 单表查询
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <returns></returns>
|
||||
public virtual List<TEntity> Find(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
|
||||
{
|
||||
return FindAsISugarQueryable(predicate, filterDeleted).ToList();
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name=""></param>
|
||||
/// <param name="orderBy">排序字段</param>
|
||||
/// <returns></returns>
|
||||
public virtual TEntity FindFirst(Expression<Func<TEntity, bool>> predicate, bool filterDeleted = true)
|
||||
{
|
||||
return BaseDbContext.Set<TEntity>(filterDeleted).Where(predicate).FirstOrDefault();
|
||||
}
|
||||
|
||||
|
||||
public ISugarQueryable<TEntity> FindAsIQueryable(Expression<Func<TEntity, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy = null, bool filterDeleted = true)
|
||||
{
|
||||
//if (orderBy != null)
|
||||
// return DbContext.Set<TEntity>().Where(predicate).GetISugarQueryableOrderBy(orderBy.GetExpressionToDic());
|
||||
return DbContext.Set<TEntity>(filterDeleted).Where(predicate);
|
||||
}
|
||||
|
||||
public ISugarQueryable<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> incluedProperty) where TProperty : new()
|
||||
{
|
||||
return DbContext.Set<TEntity>().Include(incluedProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过条件查询返回指定列的数据(将TEntity映射到匿名或实体T)
|
||||
///var result = Sys_UserRepository.GetInstance.Find(x => x.UserName == loginInfo.userName, p => new { uname = p.UserName });
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pagesize"></param>
|
||||
/// <param name="rowcount"></param>
|
||||
/// <param name="predicate">查询条件</param>
|
||||
/// <param name="orderBySelector">多个排序字段key为字段,value为升序/降序</param>
|
||||
/// <returns></returns>
|
||||
public virtual ISugarQueryable<TFind> IQueryablePage<TFind>(int pageIndex, int pagesize, out int rowcount, Expression<Func<TFind, bool>> predicate, Expression<Func<TEntity, Dictionary<object, QueryOrderBy>>> orderBy, bool returnRowCount = true) where TFind : class, new()
|
||||
{
|
||||
pageIndex = pageIndex <= 0 ? 1 : pageIndex;
|
||||
pagesize = pagesize <= 0 ? 10 : pagesize;
|
||||
if (predicate == null)
|
||||
{
|
||||
predicate = x => 1 == 1;
|
||||
}
|
||||
var _db = DbContext.Set<TFind>();
|
||||
rowcount = returnRowCount ? _db.Count(predicate) : 0;
|
||||
return DbContext.Set<TFind>().Where(predicate)
|
||||
.GetISugarQueryableOrderBy(orderBy.GetExpressionToDic())
|
||||
.Skip((pageIndex - 1) * pagesize)
|
||||
.Take(pagesize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页排序
|
||||
/// </summary>
|
||||
/// <param name="queryable"></param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pagesize"></param>
|
||||
/// <param name="rowcount"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <returns></returns>
|
||||
public virtual ISugarQueryable<TEntity> IQueryablePage(ISugarQueryable<TEntity> queryable, int pageIndex, int pagesize, out int rowcount, Dictionary<string, QueryOrderBy> orderBy, bool returnRowCount = true)
|
||||
{
|
||||
pageIndex = pageIndex <= 0 ? 1 : pageIndex;
|
||||
pagesize = pagesize <= 0 ? 10 : pagesize;
|
||||
rowcount = returnRowCount ? queryable.Count() : 0;
|
||||
return queryable.GetISugarQueryableOrderBy<TEntity>(orderBy)
|
||||
.Skip((pageIndex - 1) * pagesize)
|
||||
.Take(pagesize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新表数据
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="saveChanges">是否保存</param>
|
||||
/// <param name="properties">格式 Expression<Func<entityt, object>> expTree = x => new { x.字段1, x.字段2 };</param>
|
||||
public virtual int Update(TEntity entity, Expression<Func<TEntity, object>> properties, bool saveChanges = false)
|
||||
{
|
||||
return Update<TEntity>(entity, properties, saveChanges);
|
||||
}
|
||||
|
||||
public virtual int Update<TSource>(TSource entity, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange(new List<TSource>
|
||||
{
|
||||
entity
|
||||
}, properties, saveChanges);
|
||||
}
|
||||
|
||||
|
||||
public virtual int Update<TSource>(TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(new List<TSource>() { entity }, properties, saveChanges);
|
||||
}
|
||||
public virtual int Update<TSource>(TSource entity, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(new List<TSource>() { entity }, new string[0], saveChanges);
|
||||
}
|
||||
public virtual int UpdateRange<TSource>(IEnumerable<TSource> entities, Expression<Func<TSource, object>> properties, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(entities, properties?.GetExpressionProperty(), saveChanges);
|
||||
}
|
||||
public virtual int UpdateRange<TSource>(IEnumerable<TSource> entities, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(entities, new string[0], saveChanges);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新表数据
|
||||
/// </summary>
|
||||
/// <param name="models"></param>
|
||||
/// <param name="properties">格式 Expression<Func<entityt, object>> expTree = x => new { x.字段1, x.字段2 };</param>
|
||||
public int UpdateRange<TSource>(IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return DbContext.UpdateRange(entities, properties, saveChanges);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="updateDetail">是否修改明细</param>
|
||||
/// <param name="delNotExist">是否删除明细不存在的数据</param>
|
||||
/// <param name="updateMainFields">主表指定修改字段</param>
|
||||
/// <param name="updateDetailFields">明细指定修改字段</param>
|
||||
/// <param name="saveChange">是否保存</param>
|
||||
/// <returns></returns>
|
||||
public virtual WebResponseContent UpdateRange<Detail>(TEntity entity,
|
||||
bool updateDetail = false,
|
||||
bool delNotExist = false,
|
||||
Expression<Func<TEntity, object>> updateMainFields = null,
|
||||
Expression<Func<Detail, object>> updateDetailFields = null,
|
||||
bool saveChange = false) where Detail : class, new()
|
||||
{
|
||||
WebResponseContent webResponse = new WebResponseContent();
|
||||
Update(entity, updateMainFields);
|
||||
string message = "";
|
||||
if (updateDetail)
|
||||
{
|
||||
PropertyInfo[] properties = typeof(TEntity).GetProperties();
|
||||
PropertyInfo detail = properties.Where(x => x.PropertyType.Name == "List`1").ToList().FirstOrDefault();
|
||||
if (detail != null)
|
||||
{
|
||||
PropertyInfo key = properties.GetKeyProperty();
|
||||
object obj = detail.GetValue(entity);
|
||||
Type detailType = typeof(TEntity).GetCustomAttribute<EntityAttribute>().DetailTable[0];
|
||||
var list = obj as List<Detail>;
|
||||
if (list.Count > 0)
|
||||
{
|
||||
message = UpdateDetail<Detail>(list, key.Name, key.GetValue(entity), updateDetailFields, delNotExist);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!saveChange) return webResponse.OK();
|
||||
|
||||
DbContext.SaveChanges();
|
||||
return webResponse.OK("修改成功,明细" + message, entity);
|
||||
}
|
||||
private string UpdateDetail<TDetail>(List<TDetail> list,
|
||||
string keyName,
|
||||
object keyValue,
|
||||
Expression<Func<TDetail, object>> updateDetailFields = null,
|
||||
bool delNotExist = false) where TDetail : class, new()
|
||||
{
|
||||
if (list == null) return "";
|
||||
PropertyInfo property = typeof(TDetail).GetKeyProperty();
|
||||
string detailKeyName = property.Name;
|
||||
var details = DbContext.Set<TDetail>();
|
||||
Expression<Func<TDetail, object>> selectExpression = detailKeyName.GetExpression<TDetail, object>();
|
||||
Expression<Func<TDetail, bool>> whereExpression = keyName.CreateExpression<TDetail>(keyValue, LinqExpressionType.Equal);
|
||||
//这里有问题, Expression<Func<TDetail, object>>会转换为查询所有字段20231020
|
||||
//List<object> detailKeys = details.Where(whereExpression).Select(selectExpression).ToList();
|
||||
|
||||
List<object> detailKeys = details.Where(whereExpression).ToList().Select(selectExpression.Compile()).ToList();
|
||||
//获取主键默认值
|
||||
//string keyDefaultVal = property.PropertyType==typeof(string)?"": property.PropertyType.Assembly.CreateInstance(property.PropertyType.FullName).ToString();
|
||||
string keyDefaultVal = "";
|
||||
if (property.PropertyType != typeof(string))
|
||||
keyDefaultVal = property.PropertyType.Assembly.CreateInstance(property.PropertyType.FullName).ToString();
|
||||
int addCount = 0;
|
||||
int editCount = 0;
|
||||
int delCount = 0;
|
||||
PropertyInfo mainKeyProperty = typeof(TDetail).GetProperty(keyName);
|
||||
|
||||
var detailKeyPro = typeof(TDetail).GetKeyProperty();
|
||||
IdWorker worker = null;
|
||||
bool stringKey = false;
|
||||
if (detailKeyPro.PropertyType == typeof(string))
|
||||
{
|
||||
stringKey = true;
|
||||
if (AppSetting.UseSnow)
|
||||
{
|
||||
worker = new IdWorker();
|
||||
}
|
||||
}
|
||||
List<TDetail> addList = new List<TDetail>();
|
||||
List<TDetail> updateList = new List<TDetail>();
|
||||
List<object> keys = new List<object>();
|
||||
list.ForEach(x =>
|
||||
{
|
||||
object val = property.GetValue(x) ?? "";
|
||||
//主键是默认值的为新增的数据
|
||||
if (val.ToString() == keyDefaultVal)
|
||||
{
|
||||
x.SetCreateDefaultVal();
|
||||
//设置主表的值,也可以不设置
|
||||
mainKeyProperty.SetValue(x, keyValue);
|
||||
if (stringKey)
|
||||
{
|
||||
if (worker != null)
|
||||
{
|
||||
detailKeyPro.SetValue(x, worker.NextId().ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
detailKeyPro.SetValue(x, Guid.NewGuid().ToString());
|
||||
}
|
||||
}
|
||||
// DbContext.Insertable(x).AddQueue();
|
||||
addList.Add(x);
|
||||
addCount++;
|
||||
}
|
||||
else//修改的数据
|
||||
{
|
||||
//获取所有修改的key,如果从数据库查来的key,不在修改中的key,则为删除的数据
|
||||
keys.Add(val);
|
||||
x.SetModifyDefaultVal();
|
||||
// Update<TDetail>(x, updateDetailFields);
|
||||
updateList.Add(x);
|
||||
// repository.DbContext.Entry<TDetail>(x).State = EntityState.Modified;
|
||||
editCount++;
|
||||
}
|
||||
});
|
||||
//删除
|
||||
if (delNotExist)
|
||||
{
|
||||
detailKeys.Where(x => !keys.Contains(x)).ToList().ForEach(d =>
|
||||
{
|
||||
delCount++;
|
||||
TDetail detail = Activator.CreateInstance<TDetail>();
|
||||
property.SetValue(detail, d);
|
||||
DbContext.Deleteable<TDetail>(detail).AddQueue();
|
||||
for (int i = 0; i < list.Count(); i++)
|
||||
{
|
||||
if (property.GetValue(list[i]) == d)
|
||||
{
|
||||
list.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
DbContext.Insertable<TDetail>(addList).ExecuteCommand();
|
||||
if (updateDetailFields == null)
|
||||
{
|
||||
DbContext.Updateable<TDetail>(updateList).AddQueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
DbContext.Updateable<TDetail>(updateList).UpdateColumns(updateDetailFields.GetExpressionToArray<TDetail>()).ExecuteCommand();
|
||||
}
|
||||
return $"修改[{editCount}]条,新增[{addCount}]条,删除[{delCount}]条";
|
||||
}
|
||||
|
||||
public virtual void Delete(TEntity model, bool saveChanges = false)
|
||||
{
|
||||
if (typeof(TEntity).GetSugarSplitTable() != null)
|
||||
{
|
||||
DbContext.Deleteable(model).SplitTable().ExecuteCommand();
|
||||
return;
|
||||
}
|
||||
DbContext.Deleteable(model).AddQueue();
|
||||
if (saveChanges)
|
||||
{
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Delete<T>(T model, bool saveChanges) where T : class, new()
|
||||
{
|
||||
if (typeof(T).GetSugarSplitTable() != null)
|
||||
{
|
||||
DbContext.Deleteable(model).SplitTable().ExecuteCommand();
|
||||
return;
|
||||
}
|
||||
DbContext.Deleteable(model).AddQueue();
|
||||
if (saveChanges)
|
||||
{
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 通过主键批量删除
|
||||
/// </summary>
|
||||
/// <param name="keys">主键key</param>
|
||||
/// <param name="delList">是否连明细一起删除</param>
|
||||
/// <returns></returns>
|
||||
public virtual int DeleteWithKeys(object[] keys, bool saveChange = false)
|
||||
{
|
||||
var keyPro = typeof(TEntity).GetKeyProperty();
|
||||
List<TEntity> list = new List<TEntity>();
|
||||
foreach (var key in keys.Distinct())
|
||||
{
|
||||
TEntity entity = Activator.CreateInstance<TEntity>();
|
||||
keyPro.SetValue(entity, key.ChangeType(keyPro.PropertyType));
|
||||
list.Add(entity);
|
||||
}
|
||||
if (typeof(TEntity).GetSugarSplitTable() != null)
|
||||
{
|
||||
DbContext.Deleteable(list).SplitTable().ExecuteCommand();
|
||||
return keys.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
DbContext.Deleteable(list).AddQueue();
|
||||
}
|
||||
if (saveChange)
|
||||
{
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
return keys.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入数据并设置自增
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
public virtual void AddWithSetIdentity(TEntity entity)
|
||||
{
|
||||
AddWithSetIdentity<TEntity>(entity);
|
||||
}
|
||||
public virtual void AddWithSetIdentity<T>(T entity) where T : class, new()
|
||||
{
|
||||
if (typeof(T).GetSugarSplitTable() != null)
|
||||
{
|
||||
DbContext.Insertable(entity).SplitTable().ExecuteCommand();
|
||||
return;
|
||||
}
|
||||
DbContext.Insertable(entity).ExecuteReturnEntity();
|
||||
}
|
||||
public virtual void Add(TEntity entities, bool saveChanges = false)
|
||||
{
|
||||
AddRange(new List<TEntity>() { entities }, saveChanges);
|
||||
}
|
||||
|
||||
public virtual void Add<T>(T entities, bool saveChanges = false) where T : class, new()
|
||||
{
|
||||
DbContext.Insertable(entities).AddQueue();
|
||||
if (saveChanges) DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual void AddRange(List<TEntity> entities, bool saveChanges = false)
|
||||
{
|
||||
AddRange<TEntity>(entities, saveChanges);
|
||||
}
|
||||
|
||||
public virtual void AddRange<T>(List<T> entities, bool saveChanges = false) where T : class, new()
|
||||
{
|
||||
if (AppSetting.UseSnow)
|
||||
{
|
||||
PropertyInfo keyPro = typeof(T).GetKeyProperty();
|
||||
if (keyPro.PropertyType == typeof(long))
|
||||
{
|
||||
//生成雪花id
|
||||
var idWorker = new IdWorker();
|
||||
foreach (var item in entities)
|
||||
{
|
||||
keyPro.SetValue(item, idWorker.NextId());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof(T).GetSugarSplitTable() != null)
|
||||
{
|
||||
DbContext.Insertable(entities).SplitTable().ExecuteCommand();
|
||||
return;
|
||||
}
|
||||
DbContext.Insertable(entities).AddQueue();
|
||||
if (saveChanges) DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual int SaveChanges()
|
||||
{
|
||||
return BaseDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual Task<int> SaveChangesAsync()
|
||||
{
|
||||
return BaseDbContext.SqlSugarClient.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public virtual int ExecuteSqlCommand(string sql, params SugarParameter[] SugarParameters)
|
||||
{
|
||||
return DbContext.Ado.ExecuteCommand(sql, SugarParameters);
|
||||
// return DbContext.Database.ExecuteSqlRaw(sql, SugarParameters);
|
||||
}
|
||||
|
||||
public virtual List<TEntity> FromSql(string sql, params SugarParameter[] SugarParameters)
|
||||
{
|
||||
return DbContext.Ado.SqlQuery<TEntity>(sql, SugarParameters).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行sql
|
||||
/// 使用方式 FormattableString sql=$"select * from xx where name ={xx} and pwd={xx1} ",
|
||||
/// FromSqlInterpolated内部处理sql注入的问题,直接在{xx}写对应的值即可
|
||||
/// 注意:sql必须 select * 返回所有TEntity字段,
|
||||
/// </summary>
|
||||
/// <param name="formattableString"></param>
|
||||
/// <returns></returns>
|
||||
//public virtual ISugarQueryable<TEntity> FromSqlInterpolated([NotNull] FormattableString sql)
|
||||
//{
|
||||
// //DBSet.FromSqlInterpolated(sql).Select(x => new { x,xxx}).ToList();
|
||||
// return DbContext.Ado.SqlQuery<TEntity>(sql);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 取消上下文跟踪
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
public virtual void Detached(TEntity entity)
|
||||
{
|
||||
// DbContext.Entry(entity).State = EntityState.Detached;
|
||||
}
|
||||
public virtual void DetachedRange(IEnumerable<TEntity> entities)
|
||||
{
|
||||
//foreach (var entity in entities)
|
||||
//{
|
||||
// DbContext.Entry(entity).State = EntityState.Detached;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using System.IO;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.Extensions.AutofacManager;
|
||||
|
||||
namespace VolPro.Core.BaseProvider.ServerMapPath
|
||||
{
|
||||
public interface IPathProvider : IDependency
|
||||
{
|
||||
string MapPath(string path);
|
||||
string MapPath(string path, bool rootPath);
|
||||
IWebHostEnvironment GetHostingEnvironment();
|
||||
}
|
||||
|
||||
public class PathProvider : IPathProvider
|
||||
{
|
||||
private IWebHostEnvironment _hostingEnvironment;
|
||||
|
||||
public PathProvider(IWebHostEnvironment environment)
|
||||
{
|
||||
_hostingEnvironment = environment;
|
||||
}
|
||||
public IWebHostEnvironment GetHostingEnvironment()
|
||||
{
|
||||
return _hostingEnvironment;
|
||||
}
|
||||
|
||||
public string MapPath(string path)
|
||||
{
|
||||
return MapPath(path, false);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="rootPath">获取wwwroot路径</param>
|
||||
/// <returns></returns>
|
||||
public string MapPath(string path, bool rootPath)
|
||||
{
|
||||
if (rootPath)
|
||||
{
|
||||
if (_hostingEnvironment.WebRootPath == null)
|
||||
{
|
||||
_hostingEnvironment.WebRootPath = _hostingEnvironment.ContentRootPath + "/wwwroot".ReplacePath();
|
||||
}
|
||||
return Path.Combine(_hostingEnvironment.WebRootPath, path).ReplacePath();
|
||||
}
|
||||
return Path.Combine(_hostingEnvironment.ContentRootPath, path).ReplacePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
2777
api_sqlsugar/VolPro.Core/BaseProvider/ServiceBase.cs
Normal file
2777
api_sqlsugar/VolPro.Core/BaseProvider/ServiceBase.cs
Normal file
File diff suppressed because it is too large
Load Diff
132
api_sqlsugar/VolPro.Core/CacheManager/DbCache.cs
Normal file
132
api_sqlsugar/VolPro.Core/CacheManager/DbCache.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.Utilities;
|
||||
using VolPro.Entity.DomainModels;
|
||||
|
||||
namespace VolPro.Core.CacheManager
|
||||
{
|
||||
public static class DbCache
|
||||
{
|
||||
private static List<Sys_DbService> DbServices = null;
|
||||
private static object _lock_sbcnew = new object();
|
||||
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
DbServices = DbManger.SysDbContext.Set<Sys_DbService>().Select(s => new
|
||||
{
|
||||
s.Pwd,
|
||||
s.DbIpAddress,
|
||||
s.DatabaseName,
|
||||
s.DbServiceId,
|
||||
s.GroupId,
|
||||
s.UserId,
|
||||
s.Remark,
|
||||
s.PhoneNo,
|
||||
s.DbServiceName
|
||||
})
|
||||
//.Where(x => x.DatabaseName != null && x.DbIpAddress != null && x.UserId != null && x.Pwd != null)
|
||||
.ToList()
|
||||
.Select(s => new Sys_DbService()
|
||||
{
|
||||
Pwd = s.Pwd,
|
||||
DbIpAddress = s.DbIpAddress,
|
||||
DatabaseName = s.DatabaseName,
|
||||
DbServiceName = s.DbServiceName,
|
||||
DbServiceId = s.DbServiceId,
|
||||
GroupId= s.GroupId,
|
||||
UserId = s.UserId,
|
||||
Remark = s.Remark,
|
||||
PhoneNo = s.PhoneNo
|
||||
}).ToList();
|
||||
InitConnection();
|
||||
|
||||
|
||||
}
|
||||
public static List<Sys_DbService> GetList()
|
||||
{
|
||||
return DbServices;
|
||||
}
|
||||
|
||||
public static WebResponseContent Reload(WebResponseContent webResponse)
|
||||
{
|
||||
if (webResponse.Status)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
return webResponse;
|
||||
}
|
||||
|
||||
public static void InitConnection()
|
||||
{
|
||||
foreach (var item in DbServices)
|
||||
{
|
||||
InitConnection(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static string InitConnection(Sys_DbService item, string databaseName = null)
|
||||
{
|
||||
string connectionString = GetConnectionString(item, databaseName);
|
||||
|
||||
if (databaseName == null)
|
||||
{
|
||||
DBServerProvider.SetConnection(item.DbServiceId.ToString(), connectionString);
|
||||
}
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
public static string GetConnectionString(Sys_DbService item, string databaseName = null)
|
||||
{
|
||||
string connectionString = null;
|
||||
switch (DBType.Name)
|
||||
{
|
||||
//mysql如果端口不是3306,这里也需要修改
|
||||
case "MySql":
|
||||
connectionString = @$" Data Source={item.DbIpAddress};Database={databaseName ?? item.DatabaseName};AllowLoadLocalInfile=true;User ID={item.UserId};Password={item.Pwd};allowPublicKeyRetrieval=true;pooling=true;CharSet=utf8;port=3306;sslmode=none;";
|
||||
break;
|
||||
case "PgSql":
|
||||
connectionString = $"Host={item.DbIpAddress};Port=5432;User id={item.UserId};password={item.Pwd};Database={databaseName ?? item.DatabaseName};";
|
||||
|
||||
break;
|
||||
case "MsSql":
|
||||
connectionString = @$"Data Source={item.DbIpAddress};Initial Catalog={databaseName ?? item.DatabaseName};Persist Security Info=True;User ID={item.UserId};Password={item.Pwd};Connect Timeout=500;Max Pool Size = 512;TrustServerCertificate=True;";
|
||||
|
||||
break;
|
||||
case "DM":
|
||||
// 老版本 :PORT=5236;DATABASE=DAMENG;HOST=localhost;PASSWORD=SYSDBA;USER ID=SYSDBA
|
||||
//新版本: Server=localhost; User Id=SYSDBA; PWD=SYSDBA;DATABASE=新DB
|
||||
connectionString = $" Server={item.DbIpAddress}; User Id={item.UserId}; PWD={item.Pwd};DATABASE={databaseName ?? item.DatabaseName}";
|
||||
break;
|
||||
case "Oracle":
|
||||
Console.WriteLine($"未实现数据库:{DBType.Name}");
|
||||
break;
|
||||
}
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
|
||||
public static Sys_DbService GetDbInfo(Guid dbServiceId)
|
||||
{
|
||||
return DbServices.Where(x => x.DbServiceId == dbServiceId).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static IEnumerable<Sys_DbService> GetDbInfo(Func<Sys_DbService, bool> where)
|
||||
{
|
||||
return DbServices.Where(where);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.CacheManager
|
||||
{
|
||||
public interface ICacheService : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证缓存项是否存在
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
bool Exists(string key);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// List写入head
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="val"></param>
|
||||
void LPush(string key, string val);
|
||||
|
||||
void RPush(string key, string val);
|
||||
/// <summary>
|
||||
/// List出队 lpop
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
object ListDequeue(string key);
|
||||
|
||||
/// <summary>
|
||||
/// List出队 lpop
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
T ListDequeue<T>(string key) where T : class;
|
||||
|
||||
/// <summary>
|
||||
/// 移除list中的数据,keepIndex为保留的位置到最后一个元素如list 元素为1.2.3.....100
|
||||
/// 需要移除前3个数,keepindex应该为4
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="keepIndex"></param>
|
||||
void ListRemove(string key, int keepIndex);
|
||||
|
||||
/// <summary>
|
||||
/// 添加缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <param name="value">缓存Value</param>
|
||||
/// <param name="expiresIn">缓存时长</param>
|
||||
/// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间) //new TimeSpan(0, 60, 0);</param>
|
||||
/// <returns></returns>
|
||||
bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false);
|
||||
|
||||
bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false);
|
||||
|
||||
/// <summary>
|
||||
/// 删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
bool Remove(string key);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 批量删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key集合</param>
|
||||
/// <returns></returns>
|
||||
void RemoveAll(IEnumerable<string> keys);
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
T Get<T>(string key) where T : class;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
string Get(string key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace VolPro.Core.CacheManager
|
||||
{
|
||||
public class MemoryCacheService : ICacheService
|
||||
{
|
||||
protected IMemoryCache _cache;
|
||||
public MemoryCacheService(IMemoryCache cache)
|
||||
{
|
||||
_cache = cache;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 验证缓存项是否存在
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
public bool Exists(string key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
return _cache.Get(key) != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <param name="value">缓存Value</param>
|
||||
/// <returns></returns>
|
||||
public bool Add(string key, object value)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
_cache.Set(key, value);
|
||||
return Exists(key);
|
||||
}
|
||||
|
||||
public bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false)
|
||||
{
|
||||
if (expireSeconds != -1)
|
||||
{
|
||||
_cache.Set(key,
|
||||
value,
|
||||
new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(new TimeSpan(0, 0, expireSeconds))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cache.Set(key, value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
public bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false)
|
||||
{
|
||||
return AddObject(key, value, expireSeconds, isSliding);
|
||||
}
|
||||
public void LPush(string key, string val)
|
||||
{
|
||||
}
|
||||
public void RPush(string key, string val)
|
||||
{
|
||||
}
|
||||
public T ListDequeue<T>(string key) where T : class
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public object ListDequeue(string key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public void ListRemove(string key, int keepIndex)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <param name="value">缓存Value</param>
|
||||
/// <param name="expiresSliding">滑动过期时长(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
|
||||
/// <param name="expiressAbsoulte">绝对过期时长</param>
|
||||
/// <returns></returns>
|
||||
public bool Add(string key, object value, TimeSpan expiresSliding, TimeSpan expiressAbsoulte)
|
||||
{
|
||||
_cache.Set(key, value,
|
||||
new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(expiresSliding)
|
||||
.SetAbsoluteExpiration(expiressAbsoulte)
|
||||
);
|
||||
|
||||
return Exists(key);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <param name="value">缓存Value</param>
|
||||
/// <param name="expiresIn">缓存时长</param>
|
||||
/// <param name="isSliding">是否滑动过期(如果在过期时间内有操作,则以当前时间点延长过期时间)</param>
|
||||
/// <returns></returns>
|
||||
public bool Add(string key, object value, TimeSpan expiresIn, bool isSliding = false)
|
||||
{
|
||||
if (isSliding)
|
||||
_cache.Set(key, value,
|
||||
new MemoryCacheEntryOptions()
|
||||
.SetSlidingExpiration(expiresIn)
|
||||
);
|
||||
else
|
||||
_cache.Set(key, value,
|
||||
new MemoryCacheEntryOptions()
|
||||
.SetAbsoluteExpiration(expiresIn)
|
||||
);
|
||||
|
||||
return Exists(key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
public bool Remove(string key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
_cache.Remove(key);
|
||||
|
||||
return !Exists(key);
|
||||
}
|
||||
/// <summary>
|
||||
/// 批量删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key集合</param>
|
||||
/// <returns></returns>
|
||||
public void RemoveAll(IEnumerable<string> keys)
|
||||
{
|
||||
if (keys == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(keys));
|
||||
}
|
||||
|
||||
keys.ToList().ForEach(item => _cache.Remove(item));
|
||||
}
|
||||
public string Get(string key)
|
||||
{
|
||||
return _cache.Get(key)?.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
public T Get<T>(string key) where T : class
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
return _cache.Get(key) as T;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_cache != null)
|
||||
_cache.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using CSRedis;
|
||||
using Newtonsoft.Json;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Const;
|
||||
|
||||
namespace VolPro.Core.CacheManager
|
||||
{
|
||||
public class RedisCacheService : ICacheService
|
||||
{
|
||||
public RedisCacheService()
|
||||
{
|
||||
var csredis = new CSRedisClient(AppSetting.RedisConnectionString);
|
||||
RedisHelper.Initialization(csredis);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证缓存项是否存在
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
public bool Exists(string key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
return RedisHelper.Exists(key);
|
||||
}
|
||||
|
||||
public void LPush(string key, string val)
|
||||
{
|
||||
RedisHelper.LPush(key, val);
|
||||
}
|
||||
|
||||
public void RPush(string key, string val)
|
||||
{
|
||||
RedisHelper.RPush(key, val);
|
||||
}
|
||||
|
||||
public T ListDequeue<T>(string key) where T : class
|
||||
{
|
||||
string value = RedisHelper.RPop(key);
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return null;
|
||||
return JsonConvert.DeserializeObject<T>(value);
|
||||
}
|
||||
public object ListDequeue(string key)
|
||||
{
|
||||
string value = RedisHelper.RPop(key);
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return null;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除list中的数据,keepIndex为保留的位置到最后一个元素如list 元素为1.2.3.....100
|
||||
/// 需要移除前3个数,keepindex应该为4
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="keepIndex"></param>
|
||||
public void ListRemove(string key, int keepIndex)
|
||||
{
|
||||
RedisHelper.LTrim(key, keepIndex, -1);
|
||||
}
|
||||
public bool Add(string key, string value, int expireSeconds = -1, bool isSliding = false)
|
||||
{
|
||||
return RedisHelper.Set(key, value, expireSeconds);
|
||||
}
|
||||
public bool AddObject(string key, object value, int expireSeconds = -1, bool isSliding = false)
|
||||
{
|
||||
return RedisHelper.Set(key, value, expireSeconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
public bool Remove(string key)
|
||||
{
|
||||
RedisHelper.Del(key);
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// 批量删除缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key集合</param>
|
||||
/// <returns></returns>
|
||||
public void RemoveAll(IEnumerable<string> keys)
|
||||
{
|
||||
RedisHelper.Del(keys.ToArray());
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
public T Get<T>(string key) where T : class
|
||||
{
|
||||
return RedisHelper.Get<T>(key);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取缓存
|
||||
/// </summary>
|
||||
/// <param name="key">缓存Key</param>
|
||||
/// <returns></returns>
|
||||
public string Get(string key)
|
||||
{
|
||||
return RedisHelper.Get(key);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
236
api_sqlsugar/VolPro.Core/Configuration/AppSetting.cs
Normal file
236
api_sqlsugar/VolPro.Core/Configuration/AppSetting.cs
Normal file
@@ -0,0 +1,236 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.Extensions;
|
||||
|
||||
namespace VolPro.Core.Configuration
|
||||
{
|
||||
public static class AppSetting
|
||||
{
|
||||
public static IConfiguration Configuration { get; private set; }
|
||||
|
||||
public static string DbConnectionString
|
||||
{
|
||||
get { return _connection.DbConnectionString; }
|
||||
}
|
||||
|
||||
public static string RedisConnectionString
|
||||
{
|
||||
get { return _connection.RedisConnectionString; }
|
||||
}
|
||||
|
||||
public static bool UseRedis
|
||||
{
|
||||
get { return _connection.UseRedis; }
|
||||
}
|
||||
public static bool UseSignalR
|
||||
{
|
||||
get { return _connection.UseSignalR; }
|
||||
}
|
||||
|
||||
public static bool UseSqlserver2008
|
||||
{
|
||||
get { return _connection.UseSqlserver2008; }
|
||||
}
|
||||
public static Secret Secret { get; private set; }
|
||||
|
||||
public static CreateMember CreateMember { get; private set; }
|
||||
|
||||
public static ModifyMember ModifyMember { get; private set; }
|
||||
|
||||
private static Connection _connection;
|
||||
|
||||
public static string TokenHeaderName = "Authorization";
|
||||
|
||||
/// <summary>
|
||||
/// Actions权限过滤
|
||||
/// </summary>
|
||||
public static GlobalFilter GlobalFilter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// kafka配置
|
||||
/// </summary>
|
||||
public static Kafka Kafka { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// JWT有效期(分钟=默认120)
|
||||
/// </summary>
|
||||
public static int ExpMinutes { get; private set; } = 120;
|
||||
public static string FullStaticPath { get; private set; } = null;
|
||||
public static string CurrentPath { get; private set; } = null;
|
||||
public static string DownLoadPath { get { return CurrentPath + "\\Download\\"; } }
|
||||
//使用动态分库
|
||||
public static bool UseDynamicShareDB { get; set; }
|
||||
//逻辑删除字段(对应表字段,逻辑删除只会将字段的值设置为1,默认是0)
|
||||
public static string LogicDelField { get; set; } = null;
|
||||
//表的租户字段(使用动态分库功能此字段用不上)
|
||||
public static string TenancyField { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 是否使用雪花算法(表的主键字段为bigint类型时启用雪花算法生成唯一id;)
|
||||
/// </summary>
|
||||
public static bool UseSnow { get; set; }
|
||||
|
||||
//是否使用用户权限(限制只能看到指定用户创建的数据,用户管理页面的操作列可以看到此功能,设置为1后生效)
|
||||
public static bool UserAuth { get; set; }
|
||||
|
||||
//2023.12.25所有静态文件访问授权
|
||||
public static bool FileAuth { get; set; }
|
||||
public static void Init(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
services.Configure<Secret>(configuration.GetSection("Secret"));
|
||||
services.Configure<Connection>(configuration.GetSection("Connection"));
|
||||
services.Configure<CreateMember>(configuration.GetSection("CreateMember"));
|
||||
services.Configure<ModifyMember>(configuration.GetSection("ModifyMember"));
|
||||
services.Configure<GlobalFilter>(configuration.GetSection("GlobalFilter"));
|
||||
services.Configure<Kafka>(configuration.GetSection("Kafka"));
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
IWebHostEnvironment environment = provider.GetRequiredService<IWebHostEnvironment>();
|
||||
CurrentPath = Path.Combine(environment.ContentRootPath, "").ReplacePath();
|
||||
|
||||
Secret = provider.GetRequiredService<IOptions<Secret>>().Value;
|
||||
|
||||
//设置修改或删除时需要设置为默认用户信息的字段
|
||||
CreateMember = provider.GetRequiredService<IOptions<CreateMember>>().Value ?? new CreateMember();
|
||||
ModifyMember = provider.GetRequiredService<IOptions<ModifyMember>>().Value ?? new ModifyMember();
|
||||
|
||||
GlobalFilter = provider.GetRequiredService<IOptions<GlobalFilter>>().Value ?? new GlobalFilter();
|
||||
|
||||
GlobalFilter.Actions = GlobalFilter.Actions ?? new string[0];
|
||||
Kafka = provider.GetRequiredService<IOptions<Kafka>>().Value ?? new Kafka();
|
||||
|
||||
_connection = provider.GetRequiredService<IOptions<Connection>>().Value;
|
||||
|
||||
FullStaticPath = Configuration.GetSection("VirtualPath:StaticFile").Value;
|
||||
|
||||
LogicDelField = Configuration["LogicDelField"];
|
||||
|
||||
UseSnow = Configuration["UseSnow"]?.ToString()=="1";
|
||||
UserAuth = Configuration["UserAuth"]?.ToString() == "1";
|
||||
//2023.12.25所有静态文件访问授权
|
||||
FileAuth = Configuration["FileAuth"]?.ToString() == "1";
|
||||
if (LogicDelField == "")
|
||||
{
|
||||
LogicDelField = null;
|
||||
}
|
||||
|
||||
TenancyField = Configuration["TenancyField"];
|
||||
|
||||
if (TenancyField == "")
|
||||
{
|
||||
TenancyField = null;
|
||||
}
|
||||
UseDynamicShareDB = configuration["UseDynamicShareDB"] == "1";
|
||||
|
||||
FullStaticPath = Directory.GetCurrentDirectory() + "\\wwwroot\\lang\\";
|
||||
|
||||
FullStaticPath = FullStaticPath.ReplacePath();
|
||||
Console.WriteLine(FullStaticPath);
|
||||
if (!Directory.Exists(FullStaticPath))
|
||||
{
|
||||
Directory.CreateDirectory(FullStaticPath);
|
||||
}
|
||||
|
||||
ExpMinutes = (configuration["ExpMinutes"] ?? "120").GetInt();
|
||||
|
||||
DBType.Name = _connection.DBType;
|
||||
if (string.IsNullOrEmpty(_connection.DbConnectionString))
|
||||
throw new System.Exception("未配置好数据库默认连接");
|
||||
|
||||
try
|
||||
{
|
||||
_connection.DbConnectionString = _connection.DbConnectionString.DecryptDES(Secret.DB);
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (!string.IsNullOrEmpty(_connection.RedisConnectionString))
|
||||
{
|
||||
try
|
||||
{
|
||||
_connection.RedisConnectionString = _connection.RedisConnectionString.DecryptDES(Secret.Redis);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
}
|
||||
// 多个节点name格式 :["key:key1"]
|
||||
public static string GetSettingString(string key)
|
||||
{
|
||||
return Configuration[key];
|
||||
}
|
||||
// 多个节点,通过.GetSection("key")["key1"]获取
|
||||
public static IConfigurationSection GetSection(string key)
|
||||
{
|
||||
return Configuration.GetSection(key);
|
||||
}
|
||||
}
|
||||
|
||||
public class Connection
|
||||
{
|
||||
public string DBType { get; set; }
|
||||
public bool UseSqlserver2008 { get; set; }
|
||||
public string DbConnectionString { get; set; }
|
||||
public string RedisConnectionString { get; set; }
|
||||
public bool UseRedis { get; set; }
|
||||
public bool UseSignalR { get; set; }
|
||||
}
|
||||
|
||||
public class CreateMember : TableDefaultColumns
|
||||
{
|
||||
}
|
||||
public class ModifyMember : TableDefaultColumns
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class TableDefaultColumns
|
||||
{
|
||||
public string UserIdField { get; set; }
|
||||
public string UserNameField { get; set; }
|
||||
public string DateField { get; set; }
|
||||
}
|
||||
public class GlobalFilter
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public bool Enable { get; set; }
|
||||
public string[] Actions { get; set; }
|
||||
}
|
||||
|
||||
public class Kafka
|
||||
{
|
||||
public bool UseProducer { get; set; }
|
||||
public ProducerSettings ProducerSettings { get; set; }
|
||||
public bool UseConsumer { get; set; }
|
||||
public bool IsConsumerSubscribe { get; set; }
|
||||
public ConsumerSettings ConsumerSettings { get; set; }
|
||||
public Topics Topics { get; set; }
|
||||
}
|
||||
public class ProducerSettings
|
||||
{
|
||||
public string BootstrapServers { get; set; }
|
||||
public string SaslMechanism { get; set; }
|
||||
public string SecurityProtocol { get; set; }
|
||||
public string SaslUsername { get; set; }
|
||||
public string SaslPassword { get; set; }
|
||||
}
|
||||
public class ConsumerSettings
|
||||
{
|
||||
public string BootstrapServers { get; set; }
|
||||
public string SaslMechanism { get; set; }
|
||||
public string SecurityProtocol { get; set; }
|
||||
public string SaslUsername { get; set; }
|
||||
public string SaslPassword { get; set; }
|
||||
public string GroupId { get; set; }
|
||||
}
|
||||
public class Topics
|
||||
{
|
||||
public string TestTopic { get; set; }
|
||||
}
|
||||
}
|
||||
11
api_sqlsugar/VolPro.Core/Const/ApplicationContentType.cs
Normal file
11
api_sqlsugar/VolPro.Core/Const/ApplicationContentType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace VolPro.Core.Const
|
||||
{
|
||||
public class ApplicationContentType
|
||||
{
|
||||
public const string FORM = "application/x-www-form-urlencoded; charset=utf-8";
|
||||
public const string STREAM = "application/octet-stream; charset=utf-8";
|
||||
public const string JSON = "application/json; charset=utf-8";
|
||||
public const string XML = "application/xml; charset=utf-8";
|
||||
public const string TEXT = "application/text; charset=utf-8";
|
||||
}
|
||||
}
|
||||
7
api_sqlsugar/VolPro.Core/Const/DataBaseType.cs
Normal file
7
api_sqlsugar/VolPro.Core/Const/DataBaseType.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace VolPro.Core.Const
|
||||
{
|
||||
public static class DBType
|
||||
{
|
||||
public static string Name { get; set; }
|
||||
}
|
||||
}
|
||||
32
api_sqlsugar/VolPro.Core/Const/HtmlElementType.cs
Normal file
32
api_sqlsugar/VolPro.Core/Const/HtmlElementType.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Const
|
||||
{
|
||||
public struct HtmlElementType
|
||||
{
|
||||
public const string drop = "drop";
|
||||
public const string droplist = "droplist";
|
||||
public const string select = "select";
|
||||
public const string selectlist = "selectlist";
|
||||
public const string checkbox = "checkbox";
|
||||
public const string textarea = "textarea";
|
||||
public const string thanorequal = "thanorequal";
|
||||
public const string lessorequal = "lessorequal";
|
||||
|
||||
|
||||
public const string gt = "gt";
|
||||
public const string lt = "lt";
|
||||
public const string GT = ">";
|
||||
public const string LT = "<";
|
||||
public const string like = "like";
|
||||
|
||||
public const string ThanOrEqual = ">=";
|
||||
public const string LessOrequal = "<=";
|
||||
public const string Contains = "in";
|
||||
public const string Equal = "=";
|
||||
public const string NotEqual = "!=";
|
||||
|
||||
}
|
||||
}
|
||||
36
api_sqlsugar/VolPro.Core/Const/Secret.cs
Normal file
36
api_sqlsugar/VolPro.Core/Const/Secret.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
namespace VolPro.Core.Const
|
||||
{
|
||||
/// <summary>
|
||||
/// 加密对应密钥Key
|
||||
/// </summary>
|
||||
public class Secret
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户密码加密key
|
||||
/// </summary>
|
||||
public string User { get; set; }
|
||||
/// <summary>
|
||||
/// 数据库加密key
|
||||
/// </summary>
|
||||
public string DB { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// redis加密key
|
||||
/// </summary>
|
||||
public string Redis { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// jwt加密key
|
||||
/// </summary>
|
||||
public string JWT { get; set; }
|
||||
|
||||
public string Audience { get; set; }
|
||||
public string Issuer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 导出文件加密key
|
||||
/// </summary>
|
||||
public string ExportFile = "C5ABA9E202D94C13A3CB66002BF77FAF";
|
||||
|
||||
}
|
||||
}
|
||||
28
api_sqlsugar/VolPro.Core/Const/SqlDbTypeName.cs
Normal file
28
api_sqlsugar/VolPro.Core/Const/SqlDbTypeName.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Const
|
||||
{
|
||||
public struct SqlDbTypeName
|
||||
{
|
||||
public const string NVarChar = "nvarchar";
|
||||
public const string VarChar = "varchar";
|
||||
public const string NChar = "nchar";
|
||||
public const string Char = "char";
|
||||
public const string Text = "text";
|
||||
public const string Int = "int";
|
||||
public const string BigInt = "bigint";
|
||||
public const string DateTime = "datetime";
|
||||
public const string Date = "date";
|
||||
public const string SmallDateTime = "smalldatetime";
|
||||
public const string SmallDate = "smalldate";
|
||||
public const string Float = "float";
|
||||
public const string Decimal = "decimal";
|
||||
public const string Double = "double";
|
||||
public const string Bit = "bit";
|
||||
public const string Bool = "bool";
|
||||
public const string UniqueIdentifier = "uniqueidentifier";
|
||||
|
||||
}
|
||||
}
|
||||
256
api_sqlsugar/VolPro.Core/Controllers/Basic/ApiBaseController.cs
Normal file
256
api_sqlsugar/VolPro.Core/Controllers/Basic/ApiBaseController.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.Filters;
|
||||
using VolPro.Core.Middleware;
|
||||
using VolPro.Core.Services;
|
||||
using VolPro.Core.Utilities;
|
||||
using VolPro.Entity.DomainModels;
|
||||
|
||||
namespace VolPro.Core.Controllers.Basic
|
||||
{
|
||||
[JWTAuthorize, ApiController]
|
||||
public class ApiBaseController<IServiceBase> : VolController
|
||||
{
|
||||
protected IServiceBase Service;
|
||||
private WebResponseContent _baseWebResponseContent { get; set; }
|
||||
public ApiBaseController()
|
||||
{
|
||||
}
|
||||
public ApiBaseController(IServiceBase service)
|
||||
{
|
||||
Service = service;
|
||||
}
|
||||
public ApiBaseController(string projectName, string folder, string tablename, IServiceBase service)
|
||||
{
|
||||
Service = service;
|
||||
}
|
||||
[ActionLog("查询")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Search)]
|
||||
[HttpPost, Route("GetPageData")]
|
||||
public virtual ActionResult GetPageData([FromBody] PageDataOptions loadData)
|
||||
{
|
||||
return JsonNormal(InvokeService("GetPageData", new object[] { loadData }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取明细grid分页数据
|
||||
/// </summary>
|
||||
/// <param name="loadData"></param>
|
||||
/// <returns></returns>
|
||||
[ActionLog("明细查询")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Search)]
|
||||
[HttpPost, Route("GetDetailPage")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult GetDetailPage([FromBody] PageDataOptions loadData)
|
||||
{
|
||||
return Content(InvokeService("GetDetailPage", new object[] { loadData }).Serialize());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上传文件
|
||||
/// </summary>
|
||||
/// <param name="fileInput"></param>
|
||||
/// <returns></returns>
|
||||
[ActionLog("上传文件")]
|
||||
[HttpPost, Route("Upload")]
|
||||
//[ApiActionPermission(ActionPermissionOptions.Upload)]
|
||||
[ApiActionPermission(ActionPermissionOptions.Upload| ActionPermissionOptions.Add | ActionPermissionOptions.Update)]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual IActionResult Upload(IEnumerable<IFormFile> fileInput)
|
||||
{
|
||||
return Json(InvokeService("Upload", new object[] { fileInput }));
|
||||
}
|
||||
/// <summary>
|
||||
/// 下载导入Excel模板
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[ActionLog("下载导入Excel模板")]
|
||||
[HttpGet, Route("DownLoadTemplate")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Import)]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult DownLoadTemplate()
|
||||
{
|
||||
_baseWebResponseContent = InvokeService("DownLoadTemplate", new object[] { }) as WebResponseContent;
|
||||
if (!_baseWebResponseContent.Status) return Json(_baseWebResponseContent);
|
||||
byte[] fileBytes = System.IO.File.ReadAllBytes(_baseWebResponseContent.Data.ToString());
|
||||
return File(
|
||||
fileBytes,
|
||||
System.Net.Mime.MediaTypeNames.Application.Octet,
|
||||
Path.GetFileName(_baseWebResponseContent.Data.ToString())
|
||||
);
|
||||
}
|
||||
/// <summary>
|
||||
/// 导入表数据Excel
|
||||
/// </summary>
|
||||
/// <param name="fileInput"></param>
|
||||
/// <returns></returns>
|
||||
[ActionLog("导入Excel")]
|
||||
[HttpPost, Route("Import")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Import)]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult Import(List<IFormFile> fileInput)
|
||||
{
|
||||
return Json(InvokeService("Import", new object[] { fileInput }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出文件,返回日期+文件名
|
||||
/// </summary>
|
||||
/// <param name="loadData"></param>
|
||||
/// <returns></returns>
|
||||
[ActionLog("导出Excel")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Export)]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
[HttpPost, Route("Export")]
|
||||
public virtual ActionResult Export([FromBody] PageDataOptions loadData)
|
||||
{
|
||||
var result = InvokeService("Export", new object[] { loadData }) as WebResponseContent;
|
||||
return File(
|
||||
System.IO.File.ReadAllBytes(result.Data.ToString().MapPath()),
|
||||
System.Net.Mime.MediaTypeNames.Application.Octet,
|
||||
Path.GetFileName(result.Data.ToString())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 通过key删除文件
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
/// <returns></returns>
|
||||
// [ActionLog("删除")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Delete)]
|
||||
[HttpPost, Route("Del")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult Del([FromBody] object[] keys)
|
||||
{
|
||||
_baseWebResponseContent = InvokeService("Del", new object[] { keys, true }) as WebResponseContent;
|
||||
Logger.Info(LoggerType.Del, keys.Serialize(), _baseWebResponseContent.Status ? "Ok" : _baseWebResponseContent.Message);
|
||||
return Json(_baseWebResponseContent);
|
||||
}
|
||||
/// <summary>
|
||||
/// 审核
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
/// <returns></returns>
|
||||
/// [ActionLog("审核")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Audit)]
|
||||
[HttpPost, Route("Audit")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult Audit([FromBody] object[] id, int? auditStatus, string auditReason)
|
||||
{
|
||||
_baseWebResponseContent = InvokeService("Audit", new object[] { id, auditStatus, auditReason }) as WebResponseContent;
|
||||
string msg = _baseWebResponseContent.Status ? ("Ok") : _baseWebResponseContent.Message;
|
||||
Logger.Info($"审核:{id?.Serialize() + "," + (auditStatus ?? -1) + "," + auditReason};{msg}");
|
||||
return Json(_baseWebResponseContent);
|
||||
}
|
||||
/// <summary>
|
||||
/// 撤销、中目审核
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
/// <returns></returns>
|
||||
[ApiActionPermission(Enums.ActionPermissionOptions.CancelAudit)]
|
||||
[HttpPost, Route("cancelAudit")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult CancelAudit([FromBody] AntiData antiData, int status)
|
||||
{
|
||||
var res = InvokeService("CancelAudit", new object[] { antiData, status });
|
||||
return Json(res);
|
||||
}
|
||||
/// <summary>
|
||||
/// 催办
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
/// <returns></returns>
|
||||
// [ApiActionPermission(Enums.ActionPermissionOptions.Audit)]
|
||||
[HttpPost, Route("urgentAudit")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult UrgentAudit([FromBody] object[] id)
|
||||
{
|
||||
var res = InvokeService("UrgentAudit", new object[] { id });
|
||||
return Json(res);
|
||||
}
|
||||
/// <summary>
|
||||
/// 反审核
|
||||
/// </summary>
|
||||
/// <param name="keys"></param>
|
||||
/// <returns></returns>
|
||||
/// [ActionLog("审核")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Audit)]
|
||||
[HttpPost, Route("antiAudit")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult AntiAudit([FromBody] AntiData antiData)
|
||||
{
|
||||
_baseWebResponseContent = InvokeService("AntiAudit", new object[] { antiData }) as WebResponseContent;
|
||||
string msg = _baseWebResponseContent.Status ? ("Ok") : _baseWebResponseContent.Message;
|
||||
Logger.Info($"反审核:{antiData.Serialize()};{msg}");
|
||||
return Json(_baseWebResponseContent);
|
||||
}
|
||||
/// <summary>
|
||||
/// 新增支持主子表
|
||||
/// </summary>
|
||||
/// <param name="saveDataModel"></param>
|
||||
/// <returns></returns>
|
||||
[ActionLog("新建")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Add)]
|
||||
[HttpPost, Route("Add")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult Add([FromBody] SaveModel saveModel)
|
||||
{
|
||||
_baseWebResponseContent = InvokeService("Add",
|
||||
new Type[] { typeof(SaveModel) },
|
||||
new object[] { saveModel }) as WebResponseContent;
|
||||
Logger.Info(LoggerType.Add, null, _baseWebResponseContent.Status ? "Ok" : _baseWebResponseContent.Message);
|
||||
_baseWebResponseContent.Data = _baseWebResponseContent.Data?.Serialize();
|
||||
return Json(_baseWebResponseContent);
|
||||
}
|
||||
/// <summary>
|
||||
/// 编辑支持主子表
|
||||
/// [ModelBinder(BinderType =(typeof(ModelBinder.BaseModelBinder)))]可指定绑定modelbinder
|
||||
/// </summary>
|
||||
/// <param name="saveDataModel"></param>
|
||||
/// <returns></returns>
|
||||
[ActionLog("编辑")]
|
||||
[ApiActionPermission(ActionPermissionOptions.Update)]
|
||||
[HttpPost, Route("Update")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public virtual ActionResult Update([FromBody] SaveModel saveModel)
|
||||
{
|
||||
_baseWebResponseContent = InvokeService("Update", new object[] { saveModel }) as WebResponseContent;
|
||||
Logger.Info(LoggerType.Edit, null, _baseWebResponseContent.Status ? "Ok" : _baseWebResponseContent.Message);
|
||||
_baseWebResponseContent.Data = _baseWebResponseContent.Data?.Serialize();
|
||||
return Json(_baseWebResponseContent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用service方法
|
||||
/// </summary>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
private object InvokeService(string methodName, object[] parameters)
|
||||
{
|
||||
return Service.GetType().GetMethod(methodName).Invoke(Service, parameters);
|
||||
}
|
||||
/// <summary>
|
||||
/// 调用service方法
|
||||
/// </summary>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="types">为要调用重载的方法参数类型:new Type[] { typeof(SaveDataModel)</param>
|
||||
/// <param name="parameters"></param>
|
||||
/// <returns></returns>
|
||||
private object InvokeService(string methodName, Type[] types, object[] parameters)
|
||||
{
|
||||
return Service.GetType().GetMethod(methodName, types).Invoke(Service, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Entity.DomainModels;
|
||||
|
||||
namespace VolPro.Core.Controllers.Basic
|
||||
{
|
||||
public class ReportBaseController : VolController
|
||||
{
|
||||
private ReportOption _reportOptions = null;
|
||||
protected ISqlSugarClient DbContext { get; set; }
|
||||
protected ReportOption ReportOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_reportOptions == null)
|
||||
{
|
||||
string code = HttpContext.Request.Query["code"];
|
||||
_reportOptions = DBServerProvider.DbContext.Set<Sys_ReportOptions>().Where(x => x.ReportCode == code)
|
||||
.Select(s => new ReportOption()
|
||||
{
|
||||
ReportOptionsId = s.ReportOptionsId,
|
||||
ReportCode = s.ReportCode,
|
||||
DbService = s.DbService,
|
||||
Sql = s.Options,
|
||||
ParentId = s.ParentId,
|
||||
ReportName = s.ReportName,
|
||||
ReportType = s.ReportType,
|
||||
FilePath = s.FilePath,
|
||||
|
||||
}).ToList().FirstOrDefault();
|
||||
if (_reportOptions == null)
|
||||
{
|
||||
Console.Write($"模板[{code}]不存在");
|
||||
}
|
||||
else
|
||||
{
|
||||
DbContext = DbManger.GetConnection(_reportOptions.DbService);
|
||||
}
|
||||
}
|
||||
return _reportOptions;
|
||||
}
|
||||
}
|
||||
public ReportBaseController()
|
||||
{
|
||||
|
||||
}
|
||||
protected object Data = null;
|
||||
[HttpGet, HttpPost, Route("getTemplateData")]
|
||||
public virtual IActionResult GetTemplateData(string code)
|
||||
{
|
||||
if (ReportOptions == null)
|
||||
{
|
||||
return Error("模板不存在");
|
||||
}
|
||||
string filePath = ReportOptions.FilePath.MapPath(false);
|
||||
string text = System.IO.File.ReadAllText(filePath);
|
||||
|
||||
Data = GetData(code);
|
||||
if (Data != null)
|
||||
{
|
||||
return Success(null, new { text, data = Data });
|
||||
}
|
||||
if (Data == null && !string.IsNullOrEmpty(ReportOptions.Sql))
|
||||
{
|
||||
Data = DbContext.Ado.SqlQuery<object>(ReportOptions.Sql);
|
||||
}
|
||||
return Success(null, new { text, data = new { Table = Data } });
|
||||
}
|
||||
|
||||
protected virtual object GetData(string code)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
//[HttpGet, Route("getData")]
|
||||
//public virtual async Task<IActionResult> GetData(string code)
|
||||
//{
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
public class ReportOption
|
||||
{
|
||||
|
||||
[Key]
|
||||
[Display(Name = "ReportOptionsId")]
|
||||
[Column(TypeName = "uniqueidentifier")]
|
||||
[Editable(true)]
|
||||
[Required(AllowEmptyStrings = false)]
|
||||
public Guid ReportOptionsId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///报表名称
|
||||
/// </summary>
|
||||
[Display(Name = "报表名称")]
|
||||
[MaxLength(100)]
|
||||
[Column(TypeName = "nvarchar(100)")]
|
||||
[Editable(true)]
|
||||
[Required(AllowEmptyStrings = false)]
|
||||
public string ReportName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///报表编码
|
||||
/// </summary>
|
||||
[Display(Name = "报表编码")]
|
||||
[MaxLength(100)]
|
||||
[Column(TypeName = "nvarchar(100)")]
|
||||
[Editable(true)]
|
||||
[Required(AllowEmptyStrings = false)]
|
||||
public string ReportCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///所在数据库
|
||||
/// </summary>
|
||||
[Display(Name = "所在数据库")]
|
||||
[MaxLength(100)]
|
||||
[Column(TypeName = "nvarchar(100)")]
|
||||
[Editable(true)]
|
||||
public string DbService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///报表类型
|
||||
/// </summary>
|
||||
[Display(Name = "报表类型")]
|
||||
[MaxLength(100)]
|
||||
[Column(TypeName = "varchar(100)")]
|
||||
[Editable(true)]
|
||||
public string ReportType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///父级id
|
||||
/// </summary>
|
||||
[Display(Name = "父级id")]
|
||||
[Column(TypeName = "uniqueidentifier")]
|
||||
[Editable(true)]
|
||||
public Guid? ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///模板文件
|
||||
/// </summary>
|
||||
[Display(Name = "模板文件")]
|
||||
[MaxLength(2000)]
|
||||
[Column(TypeName = "nvarchar(2000)")]
|
||||
[Editable(true)]
|
||||
[Required(AllowEmptyStrings = false)]
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///数据源sql
|
||||
/// </summary>
|
||||
[Display(Name = "数据源sql")]
|
||||
[MaxLength(2000)]
|
||||
[Column(TypeName = "nvarchar(2000)")]
|
||||
[Editable(true)]
|
||||
public string Sql { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
76
api_sqlsugar/VolPro.Core/Controllers/Basic/VolController.cs
Normal file
76
api_sqlsugar/VolPro.Core/Controllers/Basic/VolController.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using VolPro.Core.Filters;
|
||||
|
||||
namespace VolPro.Core.Controllers.Basic
|
||||
{
|
||||
[JWTAuthorize, ApiController]
|
||||
public class VolController : Controller
|
||||
{
|
||||
public VolController()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 2020.11.21增加json原格式返回数据(默认是驼峰格式)
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="serializerSettings"></param>
|
||||
/// <returns></returns>
|
||||
protected JsonResult JsonNormal(object data, JsonSerializerSettings serializerSettings = null, bool formateDate = true)
|
||||
{
|
||||
serializerSettings = serializerSettings ?? new JsonSerializerSettings();
|
||||
serializerSettings.ContractResolver = null;
|
||||
if (formateDate)
|
||||
{
|
||||
serializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||
}
|
||||
serializerSettings.Converters.Add(new LongCovert());
|
||||
return Json(data, serializerSettings);
|
||||
}
|
||||
protected IActionResult Success(string message)
|
||||
{
|
||||
return JsonNormal(new { status = true, message });
|
||||
}
|
||||
protected IActionResult Success(string message, object data)
|
||||
{
|
||||
return JsonNormal(new { status = true, message, data });
|
||||
}
|
||||
|
||||
protected IActionResult Error(string message)
|
||||
{
|
||||
return JsonNormal(new { status = false, message });
|
||||
}
|
||||
protected IActionResult Error(string message, object data)
|
||||
{
|
||||
return JsonNormal(new { status = false, message, data });
|
||||
}
|
||||
}
|
||||
public class LongCovert : JsonConverter
|
||||
{
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
if (reader.Value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
long.TryParse(reader.Value.ToString(), out long value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(long) == objectType || typeof(long?) == objectType;
|
||||
}
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNull();
|
||||
return;
|
||||
}
|
||||
serializer.Serialize(writer, value.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Controllers.DynamicController
|
||||
{
|
||||
public class AddControllerChangeProvider : IActionDescriptorChangeProvider
|
||||
{
|
||||
public static AddControllerChangeProvider Instance { get; } = new AddControllerChangeProvider();
|
||||
public CancellationTokenSource TokenSource { get; private set; }
|
||||
public bool HasChanged { get; set; }
|
||||
public IChangeToken GetChangeToken()
|
||||
{
|
||||
TokenSource = new CancellationTokenSource();
|
||||
return new CancellationChangeToken(TokenSource.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Entity.SystemModels;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Controllers.DynamicController
|
||||
{
|
||||
public class ChangeActionService : IHostedService
|
||||
{
|
||||
private readonly ApplicationPartManager Part;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
public ChangeActionService(IServiceScopeFactory scope, IWebHostEnvironment env)
|
||||
{
|
||||
Part = scope.CreateScope().ServiceProvider.GetService<ApplicationPartManager>();
|
||||
_environment = env;
|
||||
}
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
//string rootPath = (_environment.ContentRootPath + "\\plugs").ReplacePath();
|
||||
//foreach (var item in Directory.GetFiles(rootPath).Where(x => x.EndsWith(".dll")))
|
||||
//{
|
||||
// string path = ($"{item}").ReplacePath();
|
||||
// //assemblyList.Add(Assembly.LoadFile(path));
|
||||
// var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
|
||||
// var assemblyPart = new AssemblyPart(assembly);
|
||||
// Part.ApplicationParts.Add(assemblyPart);
|
||||
|
||||
//}
|
||||
|
||||
//AddControllerChangeProvider.Instance.HasChanged = true;
|
||||
//AddControllerChangeProvider.Instance.TokenSource?.Cancel();
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Dapper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.Enums;
|
||||
|
||||
namespace VolPro.Core.Dapper
|
||||
{
|
||||
public class DapperParseGuidTypeHandler
|
||||
{
|
||||
public static void InitParseGuid()
|
||||
{
|
||||
if (DBType.Name == DbCurrentType.MySql.ToString())
|
||||
{
|
||||
SqlMapper.AddTypeHandler(new DapperParseGuidTypeHandlerMySql());
|
||||
SqlMapper.RemoveTypeMap(typeof(Guid?));
|
||||
}
|
||||
else if (DBType.Name == DbCurrentType.Oracle.ToString())
|
||||
{
|
||||
SqlMapper.AddTypeHandler(new DapperParseGuidTypeHandlerOracle());
|
||||
SqlMapper.RemoveTypeMap(typeof(Guid?));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Dapper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.Enums;
|
||||
|
||||
namespace VolPro.Core.Dapper
|
||||
{
|
||||
public class DapperParseGuidTypeHandlerMySql : SqlMapper.TypeHandler<Guid?>
|
||||
{
|
||||
public override void SetValue(IDbDataParameter parameter, Guid? guid)
|
||||
{
|
||||
parameter.Value = guid.ToString();
|
||||
}
|
||||
|
||||
public override Guid? Parse(object value)
|
||||
{
|
||||
if (value == null || value.ToString() == "")
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (value.GetType() == typeof(string))
|
||||
{
|
||||
return new Guid((string)value);
|
||||
}
|
||||
return (Guid)value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using Dapper;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Dapper
|
||||
{
|
||||
|
||||
public class DapperParseGuidTypeHandlerOracle : TypeHandlerBase<Guid>
|
||||
{
|
||||
public override void SetValue(IDbDataParameter parameter, Guid value)
|
||||
{
|
||||
SetOracleDbTypeOnParameter(parameter, "Raw", 16);
|
||||
parameter.Value = value.ToByteArray();
|
||||
}
|
||||
|
||||
public override Guid Parse(object value)
|
||||
{
|
||||
if (value is byte[] bytearray)
|
||||
{
|
||||
return new Guid(bytearray);
|
||||
}
|
||||
throw new NotImplementedException($"Dont know how to convert a {value.GetType().Name} to a System.Guid.");
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class TypeHandlerBase<T> : SqlMapper.TypeHandler<T>
|
||||
{
|
||||
private class DictionaryKey
|
||||
{
|
||||
public Type ParameterType { get; set; }
|
||||
public string OracleTypeName { get; set; }
|
||||
}
|
||||
|
||||
private class DictionaryKeyComparer : IEqualityComparer<DictionaryKey>
|
||||
{
|
||||
public bool Equals(DictionaryKey x, DictionaryKey y)
|
||||
{
|
||||
if (x == null && y != null) return false;
|
||||
if (x != null && y != null) return false;
|
||||
|
||||
return x.ParameterType == y.ParameterType && x.OracleTypeName.Equals(y.OracleTypeName);
|
||||
}
|
||||
|
||||
public int GetHashCode(DictionaryKey obj)
|
||||
{
|
||||
return 17 + obj.ParameterType.GetHashCode() * 23 + obj.OracleTypeName.GetHashCode() * 31;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<DictionaryKey, Action<IDbDataParameter>> OracleDbTypeProperty =
|
||||
new ConcurrentDictionary<DictionaryKey, Action<IDbDataParameter>>(new DictionaryKeyComparer());
|
||||
|
||||
protected void SetOracleDbTypeOnParameter(IDbDataParameter parameter, string oracleTypeName, int? length = null)
|
||||
{
|
||||
var setter = OracleDbTypeProperty.GetOrAdd(new DictionaryKey { ParameterType = parameter.GetType(), OracleTypeName = oracleTypeName }, CreateSetTypeAction);
|
||||
setter(parameter);
|
||||
if (length.HasValue)
|
||||
{
|
||||
parameter.Size = length.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Action<IDbDataParameter> CreateSetTypeAction(DictionaryKey key)
|
||||
{
|
||||
Type enumType = key.ParameterType.Assembly.GetType($"{key.ParameterType.Namespace}.OracleDbType");
|
||||
var enumValue = Enum.Parse(enumType, key.OracleTypeName);
|
||||
var inputVariable = Expression.Parameter(typeof(IDbDataParameter));
|
||||
var convertExpression = Expression.Convert(inputVariable, key.ParameterType);
|
||||
|
||||
var expression = Expression.Assign(
|
||||
Expression.PropertyOrField(convertExpression, "OracleDbType"),
|
||||
Expression.Constant(enumValue));
|
||||
|
||||
return Expression.Lambda<Action<IDbDataParameter>>(expression, inputVariable).Compile();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
173
api_sqlsugar/VolPro.Core/Dapper/ISqlDapper.cs
Normal file
173
api_sqlsugar/VolPro.Core/Dapper/ISqlDapper.cs
Normal file
@@ -0,0 +1,173 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Data;
|
||||
//using System.Data.SqlClient;
|
||||
//using System.Linq.Expressions;
|
||||
//using System.Threading.Tasks;
|
||||
//using Dapper;
|
||||
|
||||
//namespace VolPro.Core.Dapper
|
||||
//{
|
||||
// public interface ISqlDapper
|
||||
// {
|
||||
// /// <summary>
|
||||
// /// 超时时间(秒)2021.05.05
|
||||
// /// </summary>
|
||||
// /// <param name="timeout"></param>
|
||||
// /// <returns></returns>
|
||||
// ISqlDapper SetTimout(int timeout);
|
||||
// void BeginTransaction(Func<ISqlDapper, bool> action, Action<Exception> error);
|
||||
// List<T> QueryList<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// Task<IEnumerable<T>> QueryListAsync<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// T QueryFirst<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class;
|
||||
|
||||
// Task<T> QueryFirstAsync<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class;
|
||||
|
||||
// Task<dynamic> QueryDynamicFirstAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// dynamic QueryDynamicFirst(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// Task<dynamic> QueryDynamicListAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// List<dynamic> QueryDynamicList(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// object ExecuteScalar(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// Task<object> ExecuteScalarAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// int ExcuteNonQuery(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// Task<int> ExcuteNonQueryAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// IDataReader ExecuteReader(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
// SqlMapper.GridReader QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// Task<(IEnumerable<T1>, IEnumerable<T2>)> QueryMultipleAsync<T1, T2>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// (List<T1>, List<T2>) QueryMultiple<T1, T2>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>)> QueryMultipleAsync<T1, T2, T3>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// (List<T1>, List<T2>, List<T3>) QueryMultiple<T1, T2, T3>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// Task<(IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// (List<dynamic>, List<dynamic>) QueryDynamicMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>)> QueryMultipleAsync<T1, T2, T3, T4>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// (List<T1>, List<T2>, List<T3>, List<T4>) QueryMultiple<T1, T2, T3, T4>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>, IEnumerable<T5>)> QueryMultipleAsync<T1, T2, T3, T4, T5>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) QueryMultiple<T1, T2, T3, T4, T5>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// Task<(IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync2(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// (List<dynamic>, List<dynamic>) QueryDynamicMultiple2(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// Task<(IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync3(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
// (List<dynamic>, List<dynamic>, List<dynamic>) QueryDynamicMultiple3(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// Task<(IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync5(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
// (List<dynamic>, List<dynamic>, List<dynamic>, List<dynamic>, List<dynamic>) QueryDynamicMultiple5(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// /// <summary>
|
||||
// ///
|
||||
// /// </summary>
|
||||
// /// <typeparam name="T"></typeparam>
|
||||
// /// <param name="entities"></param>
|
||||
// /// <param name="updateFileds">指定插入的字段</param>
|
||||
// /// <param name="beginTransaction">是否开启事务</param>
|
||||
// /// <returns></returns>
|
||||
// int Add<T>(T entity, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
|
||||
// /// <summary>
|
||||
// ///
|
||||
// /// </summary>
|
||||
// /// <typeparam name="T"></typeparam>
|
||||
// /// <param name="entities"></param>
|
||||
// /// <param name="updateFileds">指定插入的字段</param>
|
||||
// /// <param name="beginTransaction">是否开启事务</param>
|
||||
// /// <returns></returns>
|
||||
// int AddRange<T>(IEnumerable<T> entities, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
|
||||
|
||||
|
||||
// /// <summary>
|
||||
// /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开
|
||||
// /// </summary>
|
||||
// /// <typeparam name="T"></typeparam>
|
||||
// /// <param name="entity">实体必须带主键</param>
|
||||
// /// <param name="updateFileds">指定更新的字段x=new {x.a,x.b}</param>
|
||||
// /// <param name="beginTransaction">是否开启事务</param>
|
||||
// /// <returns></returns>
|
||||
// int Update<T>(T entity, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
|
||||
|
||||
// /// <summary>
|
||||
// /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开
|
||||
// /// </summary>
|
||||
// /// <typeparam name="T"></typeparam>
|
||||
// /// <param name="entity">实体必须带主键</param>
|
||||
// /// <param name="updateFileds">指定更新的字段x=new {x.a,x.b}</param>
|
||||
// /// <param name="beginTransaction">是否开启事务</param>
|
||||
// /// <returns></returns>
|
||||
// int UpdateRange<T>(IEnumerable<T> entities, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
|
||||
|
||||
// int DelWithKey<T>(params object[] keys);
|
||||
// int DelWithKey<T>(bool beginTransaction = false, params object[] keys);
|
||||
// /// <summary>
|
||||
// /// sqlserver批量写入
|
||||
// /// 使用时DataTable table表字段顺序要和数据库字段顺序一致
|
||||
// /// <summary>
|
||||
// /// mysql批量写入
|
||||
// /// </summary>
|
||||
// /// <param name="table"></param>
|
||||
// /// <param name="tableName"></param>
|
||||
// /// <param name="tmpPath">默认当前下载路径</param>
|
||||
// /// <param name="fileName">默认$"{DateTime.Now.ToString("yyyyMMddHHmmss")}.csv"</param>
|
||||
// /// <returns></returns>
|
||||
// int BulkInsert(DataTable table, string tableName, SqlBulkCopyOptions? sqlBulkCopyOptions = null, string fileName = null, string tmpPath = null);
|
||||
// /// <summary>
|
||||
// ///
|
||||
// /// </summary>
|
||||
// /// <typeparam name="T"></typeparam>
|
||||
// /// <param name="entities"></param>
|
||||
// /// <param name="tableName"></param>
|
||||
// /// <param name="columns">所包含的列</param>
|
||||
// /// <param name="sqlBulkCopyOptions"></param>
|
||||
// /// <param name="fileName"></param>
|
||||
// /// <param name="tmpPath"></param>
|
||||
// /// <returns></returns>
|
||||
// int BulkInsert<T>(List<T> entities, string tableName = null,
|
||||
// Expression<Func<T, object>> columns = null,
|
||||
// SqlBulkCopyOptions? sqlBulkCopyOptions = null);
|
||||
|
||||
// /// <summary>
|
||||
// /// 开启事务
|
||||
// /// </summary>
|
||||
// /// <returns></returns>
|
||||
// ISqlDapper BeginTrans();
|
||||
|
||||
// /// <summary>
|
||||
// /// 提交
|
||||
// /// </summary>
|
||||
// void Commit();
|
||||
|
||||
// /// <summary>
|
||||
// /// 回滚
|
||||
// /// </summary>
|
||||
// void Rollback();
|
||||
|
||||
// DataTable QueryDataTable(string sql, object dbParameter, CommandType commandType = CommandType.StoredProcedure);
|
||||
// }
|
||||
//}
|
||||
1002
api_sqlsugar/VolPro.Core/Dapper/SqlDapper.cs
Normal file
1002
api_sqlsugar/VolPro.Core/Dapper/SqlDapper.cs
Normal file
File diff suppressed because it is too large
Load Diff
46
api_sqlsugar/VolPro.Core/Dashboard/DashboardFilter.cs
Normal file
46
api_sqlsugar/VolPro.Core/Dashboard/DashboardFilter.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Dapper;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.ManageUser;
|
||||
|
||||
namespace VolPro.Core.Dashboard
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义设置工作台参数
|
||||
/// </summary>
|
||||
public class DashboardFilter : IDashboardFilterMetaData
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sql">前端配置的sql或存储过程名称</param>
|
||||
/// <param name="dbService">选择的数据库</param>
|
||||
/// <param name="isProc">是否存储过程</param>
|
||||
/// <param name="date1">查询日期1</param>
|
||||
/// <param name="date2">查询日期1</param>
|
||||
/// <param name="filterType">过滤类型:今天、近7天...近一年等</param>
|
||||
/// <returns></returns>
|
||||
public (string sql, List<SugarParameter> parameters) OnActionExecuting(string sql, List<SugarParameter> parameters, string dbService, bool isProc, DateTime? date1, DateTime? date2, string filterType)
|
||||
{
|
||||
//根据不同的类型处理不同的值
|
||||
//if (isProc)
|
||||
//{
|
||||
// if (sql == "存储过程名字")
|
||||
// {
|
||||
// sql = "";
|
||||
// }
|
||||
//}
|
||||
|
||||
////手动在后台设置参数
|
||||
////如:前端sql配置:select * from table where createId=@userId
|
||||
////在这里就可以设置参数
|
||||
//parameters.Add("@userId", UserContext.Current.UserId);
|
||||
|
||||
return (sql, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Dapper;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Dashboard
|
||||
{
|
||||
public interface IDashboardFilterMetaData
|
||||
{
|
||||
(string sql, List<SugarParameter> parameters) OnActionExecuting(string sql, List<SugarParameter> parameters, string dbService, bool isProc, DateTime? date1, DateTime? date2, string filterType);
|
||||
}
|
||||
}
|
||||
11
api_sqlsugar/VolPro.Core/DbManager/DBConnectionAttribute.cs
Normal file
11
api_sqlsugar/VolPro.Core/DbManager/DBConnectionAttribute.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.DBManager
|
||||
{
|
||||
public class DBConnectionAttribute : Attribute
|
||||
{
|
||||
public string DBName { get; set; }
|
||||
}
|
||||
}
|
||||
138
api_sqlsugar/VolPro.Core/DbManager/DBServerProvider.cs
Normal file
138
api_sqlsugar/VolPro.Core/DbManager/DBServerProvider.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Npgsql;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.Dapper;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
using MySqlConnector;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Entity.SystemModels;
|
||||
using VolPro.Entity;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Linq;
|
||||
using Oracle.ManagedDataAccess.Client;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
using SqlSugar;
|
||||
using VolPro.Core.CacheManager;
|
||||
|
||||
namespace VolPro.Core.DBManager
|
||||
{
|
||||
public partial class DBServerProvider : DbManger
|
||||
{
|
||||
////系统库
|
||||
private static readonly string DefaultConnName = nameof(SysDbContext);
|
||||
|
||||
static DBServerProvider()
|
||||
{
|
||||
}
|
||||
|
||||
public static void SetConnection(string key, string val)
|
||||
{
|
||||
DbRelativeCache.DbContextConnection[key] = val;
|
||||
|
||||
}
|
||||
public static string GetConnectionString(string key)
|
||||
{
|
||||
return DbRelativeCache.DbContextConnection[key ?? DefaultConnName];
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统库
|
||||
/// </summary>
|
||||
public static SysDbContext DbContext
|
||||
{
|
||||
get
|
||||
{
|
||||
SysDbContext dbContext = Utilities.HttpContext.Current.RequestServices.GetService(typeof(SysDbContext)) as SysDbContext;
|
||||
return dbContext;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据实体model获取对应EF
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static BaseDbContext GetEntityDbContext<TEntity>()
|
||||
{
|
||||
string dbServer = typeof(TEntity).GetTypeCustomValue<EntityAttribute>(x => x.DBServer);
|
||||
|
||||
return Utilities.HttpContext.Current.RequestServices.GetService(DbRelativeCache.GetDbContextType(dbServer)) as BaseDbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指定获取数据库
|
||||
/// </summary>
|
||||
/// <param name="dbService"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDbEntityName(string dbServer)
|
||||
{
|
||||
return DbRelativeCache.GetDbEntityType(dbServer).Name;
|
||||
}
|
||||
|
||||
|
||||
//public static ISqlSugarClient GetSqlSugarClient(string connectionKey = null)
|
||||
//{
|
||||
// return DbManger.GetConnection(connectionKey);
|
||||
//}
|
||||
/// <summary>
|
||||
/// 根据dbcontext名称获取数据库链接
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public static string GetDbConnectionString(string key)
|
||||
{
|
||||
if (DbRelativeCache.DbContextConnection.TryGetValue(key, out string connString))
|
||||
{
|
||||
return connString;
|
||||
}
|
||||
throw new Exception($"未配置[{key}]的数据库连接");
|
||||
}
|
||||
|
||||
public static string GetDbConnectionString(Type dbContext)
|
||||
{
|
||||
return GetDbConnectionString(dbContext.Name);
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取系统库的字符串连接
|
||||
/// </summary>
|
||||
public static string SysConnectingString
|
||||
{
|
||||
get { return GetDbConnectionString(DefaultConnName); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取业务库的字符串连接
|
||||
/// </summary>
|
||||
public static string ServiceConnectingString
|
||||
{
|
||||
get
|
||||
{
|
||||
//动态无限分库获取用户当前选择的数据库
|
||||
if (AppSetting.UseDynamicShareDB)
|
||||
{
|
||||
return GetDbConnectionString(UserContext.CurrentServiceId.ToString());
|
||||
}
|
||||
return GetDbConnectionString(nameof(ServiceDbContext));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 动态租户分库,获取指定数据库id的链接(2023.11.05)
|
||||
/// </summary>
|
||||
/// <param name="serviceId"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetServiceConnectingString(Guid serviceId)
|
||||
{
|
||||
return DbRelativeCache.DbContextConnection[serviceId.ToString()];
|
||||
}
|
||||
}
|
||||
}
|
||||
284
api_sqlsugar/VolPro.Core/DbManager/DbCopy/DbCopyMySql.cs
Normal file
284
api_sqlsugar/VolPro.Core/DbManager/DbCopy/DbCopyMySql.cs
Normal file
@@ -0,0 +1,284 @@
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.Services;
|
||||
using VolPro.Core.Utilities;
|
||||
|
||||
namespace VolPro.Core.DbManager.DbCopy
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// MySQL 数据库复制工具类
|
||||
/// </summary>
|
||||
public class DbCopyMysql
|
||||
{
|
||||
|
||||
public static WebResponseContent CopyDatabase(ISqlSugarClient db,ISqlSugarClient toDbContext, string sourceDatabase,
|
||||
string targetDatabase, bool includeData = true)
|
||||
{
|
||||
var result = new CopyResult();
|
||||
var logs = result.Logs;
|
||||
|
||||
try
|
||||
{
|
||||
// 验证
|
||||
if (string.IsNullOrWhiteSpace(sourceDatabase))
|
||||
throw new ArgumentException("源数据库名不能为空");
|
||||
if (string.IsNullOrWhiteSpace(targetDatabase))
|
||||
throw new ArgumentException("目标数据库名不能为空");
|
||||
if (sourceDatabase.Equals(targetDatabase, StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException("源和目标数据库不能相同");
|
||||
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] 开始复制: {sourceDatabase} -> {targetDatabase}");
|
||||
|
||||
// 检查源数据库
|
||||
if (!DbExists(db, sourceDatabase))
|
||||
throw new Exception($"源数据库 '{sourceDatabase}' 不存在");
|
||||
|
||||
// 检查目标数据库
|
||||
if (DbExists(db, targetDatabase))
|
||||
throw new Exception($"目标数据库 '{targetDatabase}' 已存在");
|
||||
|
||||
// 创建目标数据库
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] 创建目标数据库...");
|
||||
CreateDb(db, sourceDatabase, targetDatabase);
|
||||
|
||||
// 复制表
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制表...");
|
||||
CopyTables(db,toDbContext, sourceDatabase, targetDatabase, includeData, result, logs);
|
||||
|
||||
// 复制视图
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制视图...");
|
||||
result.ViewsCount = CopyViews(db,toDbContext, sourceDatabase, targetDatabase, logs);
|
||||
|
||||
// 复制存储过程
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制存储过程...");
|
||||
result.ProceduresCount = CopyRoutines(db, toDbContext, sourceDatabase, targetDatabase, "PROCEDURE", logs);
|
||||
|
||||
// 复制函数
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制函数...");
|
||||
result.FunctionsCount = CopyRoutines(db,toDbContext, sourceDatabase, targetDatabase, "FUNCTION", logs);
|
||||
|
||||
// 复制触发器
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] 复制触发器...");
|
||||
result.TriggersCount = CopyTriggers(db, sourceDatabase, targetDatabase, logs);
|
||||
|
||||
result.Success = true;
|
||||
result.Message = "复制成功";
|
||||
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] ✓ 完成! 表:{result.TablesCount} 视图:{result.ViewsCount} " +
|
||||
$"存储过程:{result.ProceduresCount} 函数:{result.FunctionsCount} 触发器:{result.TriggersCount} " +
|
||||
$"行数:{result.TotalRowsCopied} 耗时:{result.ElapsedSeconds:F2}秒");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Success = false;
|
||||
result.Message = ex.Message;
|
||||
logs.Add($"[{DateTime.Now:HH:mm:ss}] ✗ 错误: {ex.Message}");
|
||||
}
|
||||
WebResponseContent webResponse = new WebResponseContent();
|
||||
webResponse.Status = result.Success;
|
||||
webResponse.Message = result.Message;
|
||||
Logger.Info($"mysql创建数据库:{logs.Serialize()}");
|
||||
return webResponse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库列表
|
||||
/// </summary>
|
||||
public static List<string> GetDatabases(ISqlSugarClient db)
|
||||
{
|
||||
var all = db.Ado.SqlQuery<string>("SHOW DATABASES");
|
||||
var system = new[] { "information_schema", "mysql", "performance_schema", "sys" };
|
||||
return all.Where(x => !system.Contains(x.ToLower())).ToList();
|
||||
}
|
||||
|
||||
private static bool DbExists(ISqlSugarClient db, string name)
|
||||
{
|
||||
return db.Ado.GetInt(
|
||||
"SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @name",
|
||||
new { name }) > 0;
|
||||
}
|
||||
|
||||
private static void CreateDb(ISqlSugarClient db, string source, string target)
|
||||
{
|
||||
var info = db.Ado.SqlQuerySingle<dynamic>(@"
|
||||
SELECT DEFAULT_CHARACTER_SET_NAME AS Charset, DEFAULT_COLLATION_NAME AS Collation
|
||||
FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = @name", new { name = source });
|
||||
|
||||
var charset = info?.Charset ?? "utf8mb4";
|
||||
var collation = info?.Collation ?? "utf8mb4_general_ci";
|
||||
|
||||
db.Ado.ExecuteCommand($"CREATE DATABASE `{target}` CHARACTER SET {charset} COLLATE {collation}");
|
||||
}
|
||||
|
||||
private static void CopyTables(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target,
|
||||
bool includeData, CopyResult result, List<string> logs)
|
||||
{
|
||||
//db.Ado.ExecuteCommand($"USE `{source}`");
|
||||
var tables = db.Ado.SqlQuery<string>($"USE `{source}`;SHOW TABLES;");
|
||||
|
||||
db.Ado.ExecuteCommand($"USE `{target}`");
|
||||
db.Ado.ExecuteCommand("SET FOREIGN_KEY_CHECKS = 0");
|
||||
|
||||
foreach (var table in tables)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取建表语句
|
||||
//db.Ado.ExecuteCommand($"USE `{source}`");
|
||||
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE TABLE `{table}`");
|
||||
var sql = GetValue(row, "Create Table");
|
||||
if (string.IsNullOrEmpty(sql)) continue;
|
||||
|
||||
//创建表
|
||||
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
|
||||
toDbContext.Ado.ExecuteCommand(sql);
|
||||
result.TablesCount++;
|
||||
logs.Add($" ✓ {table}");
|
||||
|
||||
// 复制数据
|
||||
if (includeData)
|
||||
{
|
||||
var rows = db.Ado.ExecuteCommand(
|
||||
$"INSERT INTO `{target}`.`{table}` SELECT * FROM `{source}`.`{table}`");
|
||||
result.TotalRowsCopied += rows;
|
||||
if (rows > 0) logs.Add($" {rows} 行");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logs.Add($" ✗ {table}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
db.Ado.ExecuteCommand("SET FOREIGN_KEY_CHECKS = 1");
|
||||
}
|
||||
|
||||
private static int CopyViews(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target, List<string> logs)
|
||||
{
|
||||
var views = db.Ado.SqlQuery<string>(
|
||||
"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = @db",
|
||||
new { db = source });
|
||||
|
||||
var count = 0;
|
||||
foreach (var view in views)
|
||||
{
|
||||
try
|
||||
{
|
||||
//db.Ado.ExecuteCommand($"USE `{source}`");
|
||||
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE VIEW `{view}`;");
|
||||
//var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE VIEW `{view}`;");
|
||||
var sql = GetValue(row, "Create View");
|
||||
if (string.IsNullOrEmpty(sql)) continue;
|
||||
|
||||
sql = sql.Replace($"`{source}`.", $"`{target}`.");
|
||||
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
|
||||
|
||||
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
|
||||
toDbContext.Ado.ExecuteCommand(sql);
|
||||
count++;
|
||||
logs.Add($" ✓ {view}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logs.Add($" ✗ {view}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static int CopyRoutines(ISqlSugarClient db, ISqlSugarClient toDbContext, string source, string target,
|
||||
string type, List<string> logs)
|
||||
{
|
||||
var routines = db.Ado.SqlQuery<string>(
|
||||
"SELECT ROUTINE_NAME FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = @db AND ROUTINE_TYPE = @type",
|
||||
new { db = source, type });
|
||||
|
||||
var count = 0;
|
||||
var key = type == "PROCEDURE" ? "Create Procedure" : "Create Function";
|
||||
|
||||
foreach (var routine in routines)
|
||||
{
|
||||
try
|
||||
{
|
||||
//db.Ado.ExecuteCommand($"USE `{source}`");
|
||||
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE {type} `{routine}`;");
|
||||
// var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE {type} `{routine}`;");
|
||||
var sql = GetValue(row, key);
|
||||
if (string.IsNullOrEmpty(sql)) continue;
|
||||
|
||||
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
|
||||
|
||||
toDbContext.Ado.ExecuteCommand($"USE `{target}`");
|
||||
toDbContext.Ado.ExecuteCommand(sql);
|
||||
count++;
|
||||
logs.Add($" ✓ {routine}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logs.Add($" ✗ {routine}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static int CopyTriggers(ISqlSugarClient db, string source, string target, List<string> logs)
|
||||
{
|
||||
var triggers = db.Ado.SqlQuery<string>(
|
||||
"SELECT TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA = @db",
|
||||
new { db = source });
|
||||
|
||||
var count = 0;
|
||||
foreach (var trigger in triggers)
|
||||
{
|
||||
try
|
||||
{
|
||||
//db.Ado.ExecuteCommand($"USE `{source}`");
|
||||
var row = db.Ado.SqlQuerySingle<dynamic>($"USE `{source}`;SHOW CREATE TRIGGER `{trigger}`;");
|
||||
//var row = db.Ado.SqlQuerySingle<dynamic>($"SHOW CREATE TRIGGER `{trigger}`;");
|
||||
var sql = GetValue(row, "SQL Original Statement");
|
||||
if (string.IsNullOrEmpty(sql)) continue;
|
||||
|
||||
sql = Regex.Replace(sql, @"DEFINER=`[^`]+`@`[^`]+`\s*", "");
|
||||
|
||||
db.Ado.ExecuteCommand($"USE `{target}`");
|
||||
db.Ado.ExecuteCommand(sql);
|
||||
count++;
|
||||
logs.Add($" ✓ {trigger}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logs.Add($" ✗ {trigger}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static string GetValue(dynamic row, string key)
|
||||
{
|
||||
if (row == null) return "";
|
||||
var dict = row as IDictionary<string, object>;
|
||||
return dict?.ContainsKey(key) == true ? dict[key]?.ToString() ?? "" : "";
|
||||
}
|
||||
}
|
||||
|
||||
public class CopyResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string Message { get; set; } = "";
|
||||
public int TablesCount { get; set; }
|
||||
public int ViewsCount { get; set; }
|
||||
public int ProceduresCount { get; set; }
|
||||
public int FunctionsCount { get; set; }
|
||||
public int TriggersCount { get; set; }
|
||||
public long TotalRowsCopied { get; set; }
|
||||
public double ElapsedSeconds { get; set; }
|
||||
public List<string> Logs { get; set; } = new();
|
||||
}
|
||||
}
|
||||
42
api_sqlsugar/VolPro.Core/DbManager/DbCopy/DbCopySqlserver.cs
Normal file
42
api_sqlsugar/VolPro.Core/DbManager/DbCopy/DbCopySqlserver.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Configuration;
|
||||
|
||||
namespace VolPro.Core.DbManager.DbCopy
|
||||
{
|
||||
public class DbCopySqlserver
|
||||
{
|
||||
public static string CopyDatabase(string dbEmpty, string dbName)
|
||||
{
|
||||
string DBPath = AppSetting.GetSettingString("DBPath");
|
||||
string DBBackPath = AppSetting.GetSettingString("DBBackPath");
|
||||
|
||||
|
||||
string sql = @$"USE [master]
|
||||
CREATE DATABASE [{dbName}]
|
||||
CONTAINMENT = NONE
|
||||
ON PRIMARY
|
||||
( NAME = N'{dbName}', FILENAME = N'{DBPath}\{dbName}.mdf' , SIZE = 5120KB , FILEGROWTH = 1024KB )
|
||||
LOG ON
|
||||
( NAME = N'{dbName}_log', FILENAME = N'{DBPath}\{dbName}_log.ldf' , SIZE = 2048KB , FILEGROWTH = 10%)
|
||||
|
||||
USE [master]
|
||||
BACKUP DATABASE [{dbEmpty}] TO DISK = N'{DBBackPath}\{dbEmpty}.bak' WITH COPY_ONLY, NOFORMAT, INIT,
|
||||
NAME = N'{dbEmpty}', SKIP, NOREWIND, NOUNLOAD, STATS = 10
|
||||
--还原数据库
|
||||
DECLARE @tomdf NVARCHAR(50)=N'{DBPath}\{dbName}.mdf'
|
||||
DECLARE @tolog NVARCHAR(50)=N'{DBPath}\{dbName}.ldf'
|
||||
RESTORE DATABASE [{dbName}] FROM DISK = N'{DBBackPath}\{dbEmpty}.bak' WITH FILE = 1,
|
||||
MOVE N'{dbEmpty}' TO @tomdf, MOVE N'{dbEmpty}_log' TO @tolog, NOUNLOAD, REPLACE, STATS = 5;
|
||||
|
||||
alter database {dbName} modify file(name={dbEmpty}, newname={dbName});
|
||||
alter database {dbName} modify file(name={dbEmpty}_log, newname={dbName}_log) ";
|
||||
|
||||
return sql;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
11
api_sqlsugar/VolPro.Core/DbManager/DbName.cs
Normal file
11
api_sqlsugar/VolPro.Core/DbManager/DbName.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.DBManage
|
||||
{
|
||||
public struct DbName
|
||||
{
|
||||
public static string Default = "default";
|
||||
}
|
||||
}
|
||||
156
api_sqlsugar/VolPro.Core/DbManager/DbRelativeCache.cs
Normal file
156
api_sqlsugar/VolPro.Core/DbManager/DbRelativeCache.cs
Normal file
@@ -0,0 +1,156 @@
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Entity.SystemModels;
|
||||
|
||||
namespace VolPro.Core.DBManager
|
||||
{
|
||||
public static class DbRelativeCache
|
||||
{
|
||||
private static Dictionary<string, Type> DbContextTypes = new Dictionary<string, Type>();
|
||||
private static Dictionary<string, Type> DbEntityTypes = new Dictionary<string, Type>();
|
||||
private static Dictionary<string, string> DbTypes = new Dictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// 所有数据库链接字符串
|
||||
/// </summary>
|
||||
private static Dictionary<string, string> DbConnection = new Dictionary<string, string>();
|
||||
|
||||
public static Dictionary<string, string> DbContextConnection
|
||||
{
|
||||
get { return DbConnection; }
|
||||
}
|
||||
|
||||
static DbRelativeCache()
|
||||
{
|
||||
InitDbContextType();
|
||||
InitDbEntityType();
|
||||
}
|
||||
/// <summary>
|
||||
/// 缓存分库DbContext
|
||||
/// </summary>
|
||||
public static void InitDbContextType()
|
||||
{
|
||||
var compilationLibrary = DependencyContext
|
||||
.Default
|
||||
.RuntimeLibraries
|
||||
.Where(x => x.Name.EndsWith(".Core") && !x.Serviceable && x.Type != "package" && x.Type == "project");
|
||||
foreach (var _compilation in compilationLibrary)
|
||||
{
|
||||
//加载指定类
|
||||
foreach (var item in AssemblyLoadContext.Default
|
||||
.LoadFromAssemblyName(new AssemblyName(_compilation.Name))
|
||||
.GetTypes().Where(x => x.GetTypeInfo().BaseType != null
|
||||
&& x.BaseType == (typeof(BaseDbContext))))
|
||||
{
|
||||
DbContextTypes[item.Name] = item;
|
||||
//获取数据库链接类型,在appsettings.json中Connection属性添加xxxDbType,前缀与数据库链接一样
|
||||
//ServiceDbContext:"数据库链接字符"=>ServiceDbType:"MsSql";数据库链接类型
|
||||
|
||||
string typeName = item.Name.Replace("DbContext", "").Replace("Entity", "") + "DbType";
|
||||
string dbType = AppSetting.GetSection("Connection")[typeName];
|
||||
DbTypes[item.Name] = dbType ?? DBType.Name;
|
||||
//缓存数据库链接
|
||||
string connectionString = AppSetting.GetSection("Connection")[item.Name];
|
||||
DbConnection.TryAdd(item.Name, connectionString);
|
||||
}
|
||||
}
|
||||
//缓存系统数据库链接
|
||||
DbConnection[nameof(SysDbContext)] = AppSetting.GetSection("Connection")["DbConnectionString"];
|
||||
}
|
||||
/// <summary>
|
||||
/// 缓存分库model基类
|
||||
/// </summary>
|
||||
public static void InitDbEntityType()
|
||||
{
|
||||
var compilationLibrary = DependencyContext
|
||||
.Default
|
||||
.RuntimeLibraries
|
||||
.Where(x => x.Name.EndsWith(".Entity") && !x.Serviceable && x.Type != "package" && x.Type == "project");
|
||||
foreach (var _compilation in compilationLibrary)
|
||||
{
|
||||
//加载指定类
|
||||
foreach (var item in AssemblyLoadContext.Default
|
||||
.LoadFromAssemblyName(new AssemblyName(_compilation.Name))
|
||||
.GetTypes().Where(x => x.GetTypeInfo().BaseType != null
|
||||
&& x.BaseType == (typeof(BaseEntity))))
|
||||
{
|
||||
DbEntityTypes[item.Name] = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取数据库的链接类型。如数据库是mysql还是pgsql类型
|
||||
/// </summary>
|
||||
/// <param name="dbService"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDbType(string dbService)
|
||||
{
|
||||
if (string.IsNullOrEmpty(dbService))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
DbTypes.TryGetValue(dbService, out string value);
|
||||
return value;
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据分库名称获取dbcontext
|
||||
/// </summary>
|
||||
/// <param name="dbService"></param>
|
||||
/// <returns></returns>
|
||||
public static Type GetDbContextType(string dbService)
|
||||
{
|
||||
return DbContextTypes[dbService];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据分库名称获取分库model基类
|
||||
/// </summary>
|
||||
/// <param name="dbService"></param>
|
||||
/// <returns></returns>
|
||||
public static Type GetDbEntityType(string dbService)
|
||||
{
|
||||
Type dbContextType = DbContextTypes[dbService];
|
||||
string name = dbContextType.Name.Replace("DbContext", "");
|
||||
return DbEntityTypes[$"{name}Entity"];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据dbtype获取数据库链接
|
||||
/// </summary>
|
||||
/// <param name="dbContextType"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDbConnectionString(Type dbContextType)
|
||||
{
|
||||
return GetDbConnectionString(dbContextType.GetType().Name);
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据dbtype获取数据库链接
|
||||
/// </summary>
|
||||
/// <param name="dbContextType"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDbConnectionString(string dbContextType)
|
||||
{
|
||||
if (dbContextType == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
DbConnection.TryGetValue(dbContextType, out string value);
|
||||
if (dbContextType == nameof(ServiceDbContext))
|
||||
{
|
||||
if (AppSetting.UseDynamicShareDB)
|
||||
{
|
||||
return DBServerProvider.GetDbConnectionString(UserContext.CurrentServiceId.ToString());
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Dapper;
|
||||
using VolPro.Core.Enums;
|
||||
|
||||
namespace VolPro.Core.DBManager
|
||||
{
|
||||
public partial class DBServerProvider
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
158
api_sqlsugar/VolPro.Core/DbSqlSugar/DbManger.cs
Normal file
158
api_sqlsugar/VolPro.Core/DbSqlSugar/DbManger.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.Extensions.AutofacManager;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Core.Utilities;
|
||||
using VolPro.Entity;
|
||||
|
||||
namespace VolPro.Core.DbSqlSugar
|
||||
{
|
||||
public class DbManger
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取业务库对象(租户动态分库)
|
||||
/// </summary>
|
||||
public static ISqlSugarClient ServiceDb
|
||||
{
|
||||
get
|
||||
{
|
||||
var configId = UserContext.CurrentServiceId;
|
||||
if (!Db.IsAnyConnection(configId))
|
||||
{ //用非默认ConfigId进行测试
|
||||
Db.AddConnection(new ConnectionConfig()
|
||||
{
|
||||
ConfigId = configId,
|
||||
ConnectionString = DBServerProvider.ServiceConnectingString,
|
||||
// //2024.01.22增加分库使用不同类型的数据库
|
||||
DbType = SqlSugarDbType.GetType(typeof(ServiceDbContext).Name),// SqlSugar.DbType.SqlServer,
|
||||
IsAutoCloseConnection = true,
|
||||
//https://www.donet5.com/Home/Doc?typeId=1182
|
||||
ConfigureExternalServices = new ConfigureExternalServices()
|
||||
{
|
||||
EntityService = (property, column) =>
|
||||
{
|
||||
if (GetDbType() == DbType.Dm)
|
||||
{
|
||||
var attributes = property.GetCustomAttributes(true);//get all attributes
|
||||
column.DbColumnName = column.DbColumnName.ToUpper();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
var result = Db.GetConnection(configId);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 动态租户分库,获取指定数据库id的链接(2023.11.05)
|
||||
/// </summary>
|
||||
|
||||
public static ISqlSugarClient GetServiceDb(Guid serviceId)
|
||||
{
|
||||
string configId = serviceId.ToString();
|
||||
if (!Db.IsAnyConnection(configId))
|
||||
{ //用非默认ConfigId进行测试
|
||||
Db.AddConnection(new ConnectionConfig()
|
||||
{
|
||||
ConfigId = configId,
|
||||
ConnectionString = DBServerProvider.GetServiceConnectingString(serviceId),
|
||||
DbType = SqlSugarDbType.GetType(typeof(ServiceDbContext).Name),// SqlSugar.DbType.SqlServer,
|
||||
IsAutoCloseConnection = true,
|
||||
//https://www.donet5.com/Home/Doc?typeId=1182
|
||||
ConfigureExternalServices = new ConfigureExternalServices()
|
||||
{
|
||||
EntityService = (property, column) =>
|
||||
{
|
||||
if (GetDbType() == DbType.Dm)
|
||||
{
|
||||
//var attributes = property.GetCustomAttributes(true);//get all attributes
|
||||
column.DbColumnName = property.Name.ToUpper();// column.DbColumnName.ToUpper();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
var result = Db.GetConnection(configId);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统库:后台异步使用
|
||||
/// </summary>
|
||||
public static SqlSugarScope SysDbContext = new SqlSugarScope(
|
||||
SqlSugarRegister.GetSysConnectionConfig(),
|
||||
db =>
|
||||
{
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
Console.WriteLine(sql);//输出sql,查看执行sql 性能无影响
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// 根据dbcontext获取链接,
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dbContextName">
|
||||
///获取系统库 DbManger.GetSqlSugarClient(typeof(SysDbContext).Name)
|
||||
///获取业务库 DbManger.GetSqlSugarClient(typeof(ServiceDbContext).Name)
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public static ISqlSugarClient GetSqlSugarClient(string dbContextName = null)
|
||||
{
|
||||
return GetConnection(dbContextName);
|
||||
}
|
||||
public static ISqlSugarClient GetConnection(string dbContextName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(dbContextName) || typeof(SysDbContext).Name == dbContextName)
|
||||
{
|
||||
return SysDbContext;
|
||||
}
|
||||
else if (typeof(ServiceDbContext).Name == dbContextName && AppSetting.UseDynamicShareDB)
|
||||
{
|
||||
return ServiceDb;
|
||||
}
|
||||
//其他配置文件里面的自定义数据库链接名称
|
||||
return Db.GetConnection(dbContextName);
|
||||
}
|
||||
|
||||
public static SqlSugarScope Db
|
||||
{
|
||||
get
|
||||
{
|
||||
var obj = AutofacContainerModule.GetService<ISqlSugarClient>();
|
||||
return (SqlSugarScope)obj;
|
||||
}
|
||||
}
|
||||
|
||||
public static DbType GetDbType()
|
||||
{
|
||||
return SqlSugarDbType.GetType();
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据model获取指定dbcontext对象2023.12.17
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static BaseDbContext GetDbContext<TEntity>()
|
||||
{
|
||||
string dbServer = typeof(TEntity).GetTypeCustomValue<EntityAttribute>(x => x.DBServer);
|
||||
|
||||
return HttpContext.Current.RequestServices.GetService(DbRelativeCache.GetDbContextType(dbServer)) as BaseDbContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
69
api_sqlsugar/VolPro.Core/DbSqlSugar/SqlSugarDbType.cs
Normal file
69
api_sqlsugar/VolPro.Core/DbSqlSugar/SqlSugarDbType.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.DBManager;
|
||||
|
||||
namespace VolPro.Core.DbSqlSugar
|
||||
{
|
||||
public static class SqlSugarDbType
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据配置文件中指定的xxDbType获取对应的数据库类型
|
||||
/// </summary>
|
||||
/// <param name="dbContextName"></param>
|
||||
/// <returns></returns>
|
||||
public static DbType GetType(string dbContextName = null)
|
||||
{
|
||||
string _dbType = null;
|
||||
if (!string.IsNullOrEmpty(dbContextName))
|
||||
{
|
||||
if (dbContextName != DBType.Name)
|
||||
{
|
||||
//获取指定的数据库类型
|
||||
_dbType = DbRelativeCache.GetDbType(dbContextName)?.ToLower();
|
||||
}
|
||||
}
|
||||
if (_dbType == null)
|
||||
{
|
||||
_dbType = DBType.Name?.ToString()?.ToLower();
|
||||
}
|
||||
|
||||
DbType dbType = DbType.SqlServer;
|
||||
//配置连接不同的数据库类型,比如同时使用mysql、sqlserver、pgsql数据库
|
||||
switch (_dbType)
|
||||
{
|
||||
//case "mssql":
|
||||
// dbType = DbType.SqlServer;
|
||||
// break;
|
||||
case "mysql":
|
||||
dbType = DbType.MySql;
|
||||
break;
|
||||
case "oracle":
|
||||
dbType = DbType.Oracle;
|
||||
break;
|
||||
case "pgsql":
|
||||
dbType = DbType.PostgreSQL;
|
||||
break;
|
||||
case "kdbndp":
|
||||
dbType = DbType.Kdbndp;
|
||||
break;
|
||||
case "gaussdb":
|
||||
dbType = DbType.GaussDB;
|
||||
break;
|
||||
case "oceanbase":
|
||||
dbType = DbType.OceanBase;
|
||||
break;
|
||||
case "dm":
|
||||
dbType = DbType.Dm;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return dbType;
|
||||
}
|
||||
}
|
||||
}
|
||||
243
api_sqlsugar/VolPro.Core/DbSqlSugar/SqlSugarExtension.cs
Normal file
243
api_sqlsugar/VolPro.Core/DbSqlSugar/SqlSugarExtension.cs
Normal file
@@ -0,0 +1,243 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.BaseProvider;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.UserManager;
|
||||
|
||||
namespace VolPro.Core.DbSqlSugar
|
||||
{
|
||||
public static class SqlSugarExtension
|
||||
{
|
||||
|
||||
public static int Add<T>(this BaseDbContext dbContext, T table, bool saveChange = false) where T : class, new()
|
||||
{
|
||||
dbContext.SqlSugarClient.Insertable(table).AddQueue();
|
||||
if (saveChange)
|
||||
{
|
||||
return dbContext.SqlSugarClient.SaveQueues();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static int Add<T>(this ISqlSugarClient sqlSugarClient, T table, bool saveChange = false) where T : class, new()
|
||||
{
|
||||
sqlSugarClient.Insertable(table).AddQueue();
|
||||
if (saveChange)
|
||||
{
|
||||
return sqlSugarClient.SaveQueues();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static async Task<int> AddAsync<T>(this BaseDbContext dbContext, T list, bool saveChange = false) where T : class, new()
|
||||
{
|
||||
dbContext.SqlSugarClient.Insertable(list).AddQueue();
|
||||
if (saveChange)
|
||||
{
|
||||
return await dbContext.SqlSugarClient.SaveQueuesAsync();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static int AddRange<T>(this BaseDbContext dbContext, List<T> list, bool saveChange = false) where T : class, new()
|
||||
{
|
||||
if (typeof(T).GetSugarSplitTable() != null)
|
||||
{
|
||||
dbContext.SqlSugarClient.Insertable(list).SplitTable().ExecuteCommand();
|
||||
return list.Count;
|
||||
}
|
||||
dbContext.SqlSugarClient.Insertable(list).AddQueue();
|
||||
if (saveChange)
|
||||
{
|
||||
return dbContext.SqlSugarClient.SaveQueues();
|
||||
}
|
||||
return list.Count;
|
||||
}
|
||||
|
||||
public static async Task<int> AddRangeAsync<T>(this BaseDbContext dbContext, List<T> list, bool saveChange = false) where T : class, new()
|
||||
{
|
||||
if (typeof(T).GetSugarSplitTable() != null)
|
||||
{
|
||||
await dbContext.SqlSugarClient.Insertable(list).SplitTable().ExecuteCommandAsync();
|
||||
return list.Count;
|
||||
}
|
||||
dbContext.SqlSugarClient.Insertable(list).AddQueue();
|
||||
if (saveChange)
|
||||
{
|
||||
return await dbContext.SqlSugarClient.SaveQueuesAsync();
|
||||
}
|
||||
return list.Count;
|
||||
}
|
||||
public static int Update<TSource>(this BaseDbContext dbContext, TSource entity, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(dbContext, new List<TSource>() { entity }, new string[] { }, saveChanges);
|
||||
}
|
||||
public static int Update<TSource>(this BaseDbContext dbContext, TSource entity, Expression<Func<TSource, object>> updateMainFields, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(dbContext, new List<TSource>() { entity }, updateMainFields.GetExpressionProperty(), saveChanges);
|
||||
}
|
||||
|
||||
public static int Update<TSource>(this BaseDbContext dbContext, TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(dbContext, new List<TSource>() { entity }, properties, saveChanges);
|
||||
}
|
||||
public static int UpdateRange<TSource>(this BaseDbContext dbContext, IEnumerable<TSource> entities, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(dbContext, entities, new string[] { }, saveChanges);
|
||||
}
|
||||
public static int UpdateRange<TSource>(this BaseDbContext dbContext, IEnumerable<TSource> entities, Expression<Func<TSource, object>> updateMainFields, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return UpdateRange<TSource>(dbContext, entities, updateMainFields.GetExpressionProperty(), saveChanges);
|
||||
}
|
||||
public static int UpdateRange<TSource>(this BaseDbContext dbContext, IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return dbContext.SqlSugarClient.UpdateRange<TSource>(entities, properties, saveChanges);
|
||||
}
|
||||
public static int Update<TSource>(this ISqlSugarClient sqlSugarClient, TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
return sqlSugarClient.UpdateRange<TSource>(new List<TSource>() { entity }, properties, saveChanges);
|
||||
}
|
||||
|
||||
//public static int Update<TSource>(this SqlSugarScope sqlSugarScope, TSource entity, string[] properties, bool saveChanges = false) where TSource : class, new()
|
||||
//{
|
||||
// return sqlSugarScope.UpdateRange<TSource>(new List<TSource>() { entity }, properties, saveChanges);
|
||||
//}
|
||||
|
||||
public static int UpdateRange<TSource>(this ISqlSugarClient sqlSugarClient, IEnumerable<TSource> entities, string[] properties, bool saveChanges = false) where TSource : class, new()
|
||||
{
|
||||
if (entities.Count() == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (properties != null && properties.Length > 0)
|
||||
{
|
||||
PropertyInfo[] entityProperty = typeof(TSource).GetProperties();
|
||||
string keyName = entityProperty.GetKeyName();
|
||||
if (properties.Contains(keyName))
|
||||
{
|
||||
properties = properties.Where(x => x != keyName).ToArray();
|
||||
}
|
||||
properties = properties.Where(x => entityProperty.Select(s => s.Name).Contains(x)).ToArray();
|
||||
}
|
||||
bool splitTable = typeof(TSource).GetSugarSplitTable() != null;
|
||||
IUpdateable<TSource> updateable = null;
|
||||
if (properties == null || properties.Length == 0)
|
||||
{
|
||||
updateable = sqlSugarClient.Updateable<TSource>(entities.ToList());//.AddQueue();
|
||||
}
|
||||
else
|
||||
{
|
||||
updateable = sqlSugarClient.Updateable<TSource>(entities.ToList()).UpdateColumns(properties);//.AddQueue();
|
||||
}
|
||||
if (splitTable)
|
||||
{
|
||||
updateable.SplitTable().ExecuteCommand();
|
||||
return entities.Count();
|
||||
}
|
||||
updateable.AddQueue();
|
||||
if (!saveChanges)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return sqlSugarClient.SaveQueues();
|
||||
}
|
||||
|
||||
|
||||
public static Task<T> FirstOrDefaultAsync<T>(this ISugarQueryable<T> queryable)
|
||||
{
|
||||
return queryable.FirstAsync();
|
||||
}
|
||||
|
||||
public static T FirstOrDefault<T>(this ISugarQueryable<T> queryable)
|
||||
{
|
||||
return queryable.First();
|
||||
}
|
||||
|
||||
public static ISugarQueryable<T> Include<T, TProperty>(this ISugarQueryable<T> queryable, Expression<Func<T, TProperty>> incluedProperty) where T : new() where TProperty : new()
|
||||
{
|
||||
return queryable.Includes(incluedProperty);
|
||||
}
|
||||
|
||||
public static T First<T>(this ISugarQueryable<T> queryable)
|
||||
{
|
||||
return queryable.First();
|
||||
}
|
||||
|
||||
public static ISugarQueryable<T> ThenByDescending<T>(this ISugarQueryable<T> queryable, Expression<Func<T, object>> expression)
|
||||
{
|
||||
return queryable.OrderByDescending(expression);
|
||||
}
|
||||
|
||||
|
||||
public static int SaveChanges(this ISqlSugarClient sqlSugarClient)
|
||||
{
|
||||
return sqlSugarClient.SaveQueues();
|
||||
}
|
||||
|
||||
public static async Task<int> SaveChangesAsync(this ISqlSugarClient sqlSugarClient)
|
||||
{
|
||||
return await sqlSugarClient.SaveQueuesAsync();
|
||||
}
|
||||
/// <summary>
|
||||
/// 代码生成器自定义sql关联查询
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <returns></returns>
|
||||
public static ISugarQueryable<TEntity> SetDbSql<TEntity>(this ISqlSugarClient sqlSugarClient, bool filterDeleted = false) where TEntity : class,new()
|
||||
{
|
||||
string sql = TableColumnContext.TableInfo
|
||||
.Where(x => x.TableName == typeof(TEntity).Name)
|
||||
.Select(s => s.DbSql).FirstOrDefault();
|
||||
var query =!string.IsNullOrEmpty(sql)
|
||||
? sqlSugarClient.SqlQueryable<TEntity>(sql)
|
||||
:sqlSugarClient.Queryable<TEntity>();
|
||||
if (filterDeleted && !string.IsNullOrEmpty(AppSetting.LogicDelField))
|
||||
{
|
||||
if (typeof(TEntity).GetProperty(AppSetting.LogicDelField) != null)
|
||||
{
|
||||
var expression = AppSetting.LogicDelField.CreateExpression<TEntity>((int)DelStatus.正常, LinqExpressionType.Equal);
|
||||
return query.Where(expression);
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
public static ISugarQueryable<TEntity> Set<TEntity>(this ISqlSugarClient sqlSugarClient, bool filterDeleted = false) where TEntity : class, new()
|
||||
{
|
||||
return SetDbSql<TEntity>(sqlSugarClient, filterDeleted);
|
||||
}
|
||||
|
||||
public static List<T> QueryList<T>(this ISqlSugarClient sqlSugarClient, string sql, object parameters)
|
||||
{
|
||||
return sqlSugarClient.Ado.SqlQuery<T>(sql, parameters);
|
||||
}
|
||||
public static object ExecuteScalar(this ISqlSugarClient sqlSugarClient, string sql, object parameters)
|
||||
{
|
||||
return sqlSugarClient.Ado.GetScalar(sql, parameters);
|
||||
}
|
||||
public static int ExcuteNonQuery(this ISqlSugarClient sqlSugarClient, string sql, object parameters)
|
||||
{
|
||||
return sqlSugarClient.Ado.ExecuteCommand(sql, parameters);
|
||||
}
|
||||
public static ISqlSugarClient SetTimout(this ISqlSugarClient sqlSugarClient, int time)
|
||||
{
|
||||
// sqlSugarClient.Ado.CommandTimeOut = time;
|
||||
return sqlSugarClient;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
154
api_sqlsugar/VolPro.Core/DbSqlSugar/SqlSugarRegister.cs
Normal file
154
api_sqlsugar/VolPro.Core/DbSqlSugar/SqlSugarRegister.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
|
||||
namespace VolPro.Core.DbSqlSugar
|
||||
{
|
||||
public static class SqlSugarRegister
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
///系统库链接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ConnectionConfig GetSysConnectionConfig()
|
||||
{
|
||||
var dbType = DbManger.GetDbType();
|
||||
|
||||
return new ConnectionConfig()
|
||||
{
|
||||
DbType = dbType,// SqlSugar.DbType.SqlServer,
|
||||
ConnectionString = DBServerProvider.SysConnectingString,
|
||||
IsAutoCloseConnection = true,
|
||||
ConfigId = "default",
|
||||
MoreSettings = new ConnMoreSettings()
|
||||
{
|
||||
PgSqlIsAutoToLower = false,
|
||||
IsAutoToUpper = false,
|
||||
// DatabaseModel = DbType.PostgreSQL
|
||||
},
|
||||
ConfigureExternalServices = GetConfigureExternalServices()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 模板空库(租户动态分才使用)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static ConnectionConfig GetEmptyConnectionConfig()
|
||||
{
|
||||
//Console.WriteLine(AppSetting.GetSection("Connection")["EmptyDbContext"]);
|
||||
var dbType = DbManger.GetDbType();
|
||||
//模板空库(租户动态分才使用)
|
||||
return new ConnectionConfig()
|
||||
{
|
||||
DbType = dbType,// SqlSugar.DbType.SqlServer,
|
||||
ConnectionString = AppSetting.GetSection("Connection")["EmptyDbContext"],
|
||||
IsAutoCloseConnection = true,
|
||||
ConfigId = "EmptyDbContext",
|
||||
MoreSettings = new ConnMoreSettings()
|
||||
{
|
||||
PgSqlIsAutoToLower = false,
|
||||
IsAutoToUpper = false
|
||||
},
|
||||
ConfigureExternalServices = GetConfigureExternalServices()
|
||||
};
|
||||
}
|
||||
|
||||
public static IServiceCollection UseSqlSugar(this IServiceCollection services)
|
||||
{
|
||||
StaticConfig.DynamicExpressionParserType = typeof(DynamicExpressionParser);
|
||||
services.AddHttpContextAccessor();
|
||||
|
||||
var dbType = DbManger.GetDbType();
|
||||
|
||||
//缓存所有配置文件的中的数据库链接
|
||||
var configs = DbRelativeCache.DbContextConnection
|
||||
.Where(x => x.Key.EndsWith("DbContext") || x.Key == "default").Select(s => new ConnectionConfig()
|
||||
{
|
||||
//2024.01.22增加分库使用不同类型的数据库
|
||||
DbType = SqlSugarDbType.GetType(s.Key),// SqlSugar.DbType.SqlServer,
|
||||
ConnectionString = s.Value,
|
||||
IsAutoCloseConnection = true,
|
||||
ConfigId = s.Key,
|
||||
MoreSettings = new ConnMoreSettings()
|
||||
{
|
||||
PgSqlIsAutoToLower = false,
|
||||
IsAutoToUpper = false
|
||||
},
|
||||
//https://www.donet5.com/Home/Doc?typeId=1182
|
||||
ConfigureExternalServices = GetConfigureExternalServices()
|
||||
}).ToList();
|
||||
|
||||
configs.Add(GetEmptyConnectionConfig());
|
||||
services.AddSingleton<ISqlSugarClient>(s =>
|
||||
{
|
||||
var sysConfig = GetSysConnectionConfig();
|
||||
SqlSugarScope sqlSugar = new SqlSugarScope(
|
||||
configs,
|
||||
db =>
|
||||
{
|
||||
//业务库日志
|
||||
foreach (var item in configs.Where(x => x.ConfigId?.ToString() != "SysDbContext"))
|
||||
{
|
||||
string id = item.ConfigId.ToString();
|
||||
if (db.GetConnection(id) != null)
|
||||
{
|
||||
db.GetConnection(id).Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
Console.WriteLine(sql);
|
||||
};
|
||||
}
|
||||
};
|
||||
//单例参数配置,所有上下文生效
|
||||
db.Aop.OnLogExecuting = (sql, pars) =>
|
||||
{
|
||||
Console.WriteLine(sql);
|
||||
};
|
||||
|
||||
});
|
||||
return sqlSugar;
|
||||
});
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置字段全大写
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static ConfigureExternalServices GetConfigureExternalServices()
|
||||
{
|
||||
//https://www.donet5.com/Home/Doc?typeId=1182
|
||||
return new ConfigureExternalServices()
|
||||
{
|
||||
EntityService = (property, column) =>
|
||||
{
|
||||
if (DBType.Name == "DM")
|
||||
{
|
||||
// var attributes = property.GetCustomAttributes(true);//get all attributes
|
||||
column.DbColumnName = property.Name.ToUpper();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
160
api_sqlsugar/VolPro.Core/EFDbContext/BaseDbContext.cs
Normal file
160
api_sqlsugar/VolPro.Core/EFDbContext/BaseDbContext.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Extensions;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.BaseProvider;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
using SqlSugar;
|
||||
|
||||
namespace VolPro.Core.EFDbContext
|
||||
{
|
||||
public abstract class BaseDbContext : DbContext
|
||||
{
|
||||
|
||||
|
||||
public ISqlSugarClient SqlSugarClient { get; set; }
|
||||
|
||||
public bool QueryTracking
|
||||
{
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
public BaseDbContext():base() { }
|
||||
|
||||
public ISugarQueryable<TEntity> Set<TEntity>(bool filterDeleted=false) where TEntity : class, new()
|
||||
{
|
||||
return SqlSugarClient.Set<TEntity>(filterDeleted);
|
||||
}
|
||||
|
||||
public int SaveChanges()
|
||||
{
|
||||
return SqlSugarClient.SaveQueues();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected void UseDbType(DbContextOptionsBuilder optionsBuilder, string connectionString)
|
||||
{
|
||||
//if (DBType.Name == DbCurrentType.MsSql.ToString())
|
||||
//{
|
||||
// if (AppSetting.UseSqlserver2008)
|
||||
// {
|
||||
// optionsBuilder.ReplaceService<IQueryTranslationPostprocessorFactory, SqlServer2008QueryTranslationPostprocessorFactory>();
|
||||
// }
|
||||
// optionsBuilder.UseSqlServer(connectionString);
|
||||
//}
|
||||
//else if (DBType.Name == DbCurrentType.MySql.ToString())
|
||||
//{
|
||||
// optionsBuilder.UseMySql(connectionString, new MySqlServerVersion(new Version(8, 0, 11)));
|
||||
//}
|
||||
//else if (DBType.Name == DbCurrentType.PgSql.ToString())
|
||||
//{
|
||||
// optionsBuilder.UseNpgsql(connectionString);
|
||||
//}
|
||||
//else if (DBType.Name == DbCurrentType.Oracle.ToString())
|
||||
//{
|
||||
// optionsBuilder.UseOracle(connectionString, b => b.UseOracleSQLCompatibility("11"));
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// throw new Exception("数据库未实现");
|
||||
// // optionsBuilder.UseSqlServer(connectionString);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
//protected void OnModelCreating(ModelBuilder modelBuilder, Type type)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// //获取所有类库
|
||||
// var compilationLibrary = DependencyContext
|
||||
// .Default
|
||||
// .CompileLibraries
|
||||
// .Where(x => !x.Serviceable && x.Type != "package" && x.Type == "project");
|
||||
// foreach (var _compilation in compilationLibrary)
|
||||
// {
|
||||
// //加载指定类
|
||||
// AssemblyLoadContext.Default
|
||||
// .LoadFromAssemblyName(new AssemblyName(_compilation.Name))
|
||||
// .GetTypes().Where(x => x.GetTypeInfo().BaseType != null
|
||||
// && x.BaseType == (type)).ToList()
|
||||
// .ForEach(t => { modelBuilder.Entity(t); });
|
||||
// }
|
||||
|
||||
// //Oracle数据库指定表名与列名全部大写
|
||||
// if (DBType.Name == DbCurrentType.Oracle.ToString())
|
||||
// {
|
||||
// foreach (var entity in modelBuilder.Model.GetEntityTypes())
|
||||
// {
|
||||
// string tableName = entity.GetTableName().ToUpper();
|
||||
// if (tableName.StartsWith("SYS_") || tableName.StartsWith("DEMO_"))
|
||||
// {
|
||||
// entity.SetTableName(entity.GetTableName().ToUpper());
|
||||
// foreach (var property in entity.GetProperties())
|
||||
// {
|
||||
// property.SetColumnName(property.Name.ToUpper());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// //重置系统表名小写,如果是mysql数据库,创建的表名都是小写的,请取消此注释
|
||||
// //foreach (var entity in modelBuilder.Model.GetEntityTypes())
|
||||
// //{
|
||||
// //
|
||||
// // if (entity.GetTableName().StartsWith("Sys_"))
|
||||
// // {
|
||||
// // Console.WriteLine(entity.GetTableName());
|
||||
// // entity.SetTableName(entity.GetTableName().ToLower());
|
||||
// // }
|
||||
// // //// 重置所有列名
|
||||
// // //foreach (var property in entity.GetProperties())
|
||||
// // //{
|
||||
// // // //StoreObjectIdentifier
|
||||
// // // property.SetColumnName(property.Name);
|
||||
// // //}
|
||||
// //}
|
||||
|
||||
// //插件式开发
|
||||
// //try
|
||||
// //{
|
||||
// // string rootPath = (AppSetting.CurrentPath + "\\plugs").ReplacePath();
|
||||
// // foreach (var item in Directory.GetFiles(rootPath).Where(x => x.EndsWith(".dll")))
|
||||
// // {
|
||||
// // string path = ($"{item}").ReplacePath();
|
||||
// // Assembly.LoadFile(path).GetTypes().Where(x => x.GetTypeInfo().BaseType != null
|
||||
// // && x.BaseType == (type)).ToList()
|
||||
// // .ForEach(t => {
|
||||
// // Console.Write(t.Name);
|
||||
// // modelBuilder.Entity(t);
|
||||
|
||||
// // });
|
||||
// // }
|
||||
// //}
|
||||
// //catch (Exception ex)
|
||||
// //{
|
||||
// // Console.WriteLine($"EF解析类库异常:{ex.Message + ex.StackTrace}");
|
||||
// //}
|
||||
|
||||
// base.OnModelCreating(modelBuilder);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// string mapPath = ($"Log/").MapPath();
|
||||
// Utilities.FileHelper.WriteFile(mapPath, $"syslog_{DateTime.Now.ToString("yyyyMMddHHmmss")}.txt", ex.Message + ex.StackTrace + ex.Source);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
16
api_sqlsugar/VolPro.Core/EFDbContext/DbContext.cs
Normal file
16
api_sqlsugar/VolPro.Core/EFDbContext/DbContext.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.EFDbContext
|
||||
{
|
||||
public abstract class DbContext//: SqlSugarProvider
|
||||
{
|
||||
//public DbContext(ConnectionConfig connection):base(connection)
|
||||
//{
|
||||
//}
|
||||
}
|
||||
}
|
||||
34
api_sqlsugar/VolPro.Core/EFDbContext/EFLoggerProvider.cs
Normal file
34
api_sqlsugar/VolPro.Core/EFDbContext/EFLoggerProvider.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using VolPro.Core.Utilities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.EFDbContext
|
||||
{
|
||||
public class EFLoggerProvider : ILoggerProvider
|
||||
{
|
||||
public ILogger CreateLogger(string categoryName) => new EFLogger(categoryName);
|
||||
public void Dispose() { }
|
||||
}
|
||||
public class EFLogger : ILogger
|
||||
{
|
||||
private readonly string categoryName;
|
||||
|
||||
public EFLogger(string categoryName) => this.categoryName = categoryName;
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel) => true;
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
//ef core执行数据库查询时的categoryName为Microsoft.EntityFrameworkCore.Database.Command,日志级别为Information
|
||||
if (categoryName == "Microsoft.EntityFrameworkCore.Database.Command"
|
||||
&& logLevel == LogLevel.Information)
|
||||
{
|
||||
var logContent = formatter(state, exception);
|
||||
Console.WriteLine(logContent);
|
||||
}
|
||||
}
|
||||
public IDisposable BeginScope<TState>(TState state) => null;
|
||||
}
|
||||
}
|
||||
30
api_sqlsugar/VolPro.Core/EFDbContext/ServiceDbContext.cs
Normal file
30
api_sqlsugar/VolPro.Core/EFDbContext/ServiceDbContext.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.Extensions.AutofacManager;
|
||||
using VolPro.Entity.SystemModels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SqlSugar;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
|
||||
namespace VolPro.Core.EFDbContext
|
||||
{
|
||||
public class ServiceDbContext : BaseDbContext, IDependency
|
||||
{
|
||||
private string dbServiceId { get; set; }
|
||||
|
||||
public ServiceDbContext() : base()
|
||||
{
|
||||
this.dbServiceId = dbServiceId;
|
||||
base.SqlSugarClient = DbManger.ServiceDb;
|
||||
}
|
||||
|
||||
|
||||
public ServiceDbContext(string dbServiceId) : base()
|
||||
{
|
||||
this.dbServiceId = dbServiceId;
|
||||
base.SqlSugarClient = DbManger.ServiceDb;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
api_sqlsugar/VolPro.Core/EFDbContext/SysDbContext.cs
Normal file
19
api_sqlsugar/VolPro.Core/EFDbContext/SysDbContext.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using VolPro.Core.Extensions.AutofacManager;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Entity.SystemModels;
|
||||
using System.Reflection.Emit;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
|
||||
namespace VolPro.Core.EFDbContext
|
||||
{
|
||||
public class SysDbContext : BaseDbContext, IDependency
|
||||
{
|
||||
public SysDbContext() : base() {
|
||||
base.SqlSugarClient = DbManger.SysDbContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
api_sqlsugar/VolPro.Core/EFDbContext/TestDbContext.cs
Normal file
19
api_sqlsugar/VolPro.Core/EFDbContext/TestDbContext.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.Extensions.AutofacManager;
|
||||
using VolPro.Entity.SystemModels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
|
||||
namespace VolPro.Core.EFDbContext
|
||||
{
|
||||
public class TestDbContext : BaseDbContext, IDependency
|
||||
{
|
||||
|
||||
public TestDbContext() : base() {
|
||||
base.SqlSugarClient = DbManger.GetConnection(nameof(TestDbContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
19
api_sqlsugar/VolPro.Core/EFDbContext/自定义DbContext.cs
Normal file
19
api_sqlsugar/VolPro.Core/EFDbContext/自定义DbContext.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.Extensions.AutofacManager;
|
||||
using VolPro.Entity.SystemModels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
|
||||
namespace VolPro.Core.EFDbContext
|
||||
{
|
||||
public class 自定义DbContext : BaseDbContext, IDependency
|
||||
{
|
||||
public 自定义DbContext() : base()
|
||||
{
|
||||
base.SqlSugarClient = DbManger.GetConnection(nameof(自定义DbContext));
|
||||
}
|
||||
}
|
||||
}
|
||||
21
api_sqlsugar/VolPro.Core/Enums/ActionPermissionOptions.cs
Normal file
21
api_sqlsugar/VolPro.Core/Enums/ActionPermissionOptions.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
[Flags]
|
||||
public enum ActionPermissionOptions
|
||||
{
|
||||
//注意添加的枚举值一定要是前面的值倍数,即x2
|
||||
Add = 1,
|
||||
Update = 2,
|
||||
Search = 4,
|
||||
Export = 8,
|
||||
Delete = 16,
|
||||
Audit = 32,
|
||||
Upload = 64,//上传文件
|
||||
Import = 128, //导入表数据Excel
|
||||
CancelAudit = 256//撤销审批
|
||||
}
|
||||
}
|
||||
59
api_sqlsugar/VolPro.Core/Enums/ApiMessage.cs
Normal file
59
api_sqlsugar/VolPro.Core/Enums/ApiMessage.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public struct ApiMessage
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 参数有误
|
||||
/// </summary>
|
||||
public const string ParameterError = "请求参数不正确!";
|
||||
/// <summary>
|
||||
/// 没有配置好输入参数
|
||||
/// </summary>
|
||||
public const string NotInputEntity = "没有配置好输入参数!";
|
||||
/// <summary>
|
||||
/// token丢失
|
||||
/// </summary>
|
||||
public const string TokenLose = "token丢失!";
|
||||
|
||||
/// <summary>
|
||||
/// 版本号不能为空
|
||||
/// </summary>
|
||||
|
||||
public const string VersionEmpty = "版本号不能为空!";
|
||||
/// <summary>
|
||||
/// content不能为空
|
||||
/// </summary>
|
||||
|
||||
public const string ContentEmpty = "biz_content不能为空!";
|
||||
/// <summary>
|
||||
/// content不能为空
|
||||
/// </summary>
|
||||
public const string TokenError = "token不正确";
|
||||
|
||||
public const string AccountLocked = "帐号已被锁定!";
|
||||
|
||||
public const string PhoneNoInvalid = "输入的不是手机号";
|
||||
|
||||
|
||||
public const string PINTypeNotRange= "获取验证的类型不正确";
|
||||
public const string OperToBusy = "操作太频繁,请稍后再试";
|
||||
|
||||
public const string SendSTKError = "短信发送异常,请稍后再试";
|
||||
public const string SendSTKSuccess = "短信发送成功";
|
||||
public const string STKNotSend = "请先获取验证码";
|
||||
public const string AccountExists = "手机号已经被注册";
|
||||
|
||||
public const string AccountNotExists = "手机号没有注册";
|
||||
|
||||
public const string PINExpire = "验证码已过期,请重新获取";
|
||||
|
||||
public const string PINError = "验证码不正确";
|
||||
|
||||
public const string ParameterEmpty = "参数不能为空";
|
||||
}
|
||||
}
|
||||
14
api_sqlsugar/VolPro.Core/Enums/ApiStatutsCode.cs
Normal file
14
api_sqlsugar/VolPro.Core/Enums/ApiStatutsCode.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum ApiStatutsCode
|
||||
{
|
||||
False = 0,
|
||||
Ok = 1,
|
||||
TokenExpire = 2
|
||||
|
||||
}
|
||||
}
|
||||
19
api_sqlsugar/VolPro.Core/Enums/AuthData.cs
Normal file
19
api_sqlsugar/VolPro.Core/Enums/AuthData.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum AuthData
|
||||
{
|
||||
全部 = 1,
|
||||
本组织与本角色以及下数据 = 10,
|
||||
本组织及下数据 = 20,
|
||||
本组织数据 = 30,
|
||||
本角色以及下数据 = 40,
|
||||
本角色数据 = 50,
|
||||
仅自己数据 = 60
|
||||
}
|
||||
}
|
||||
22
api_sqlsugar/VolPro.Core/Enums/CPrefix.cs
Normal file
22
api_sqlsugar/VolPro.Core/Enums/CPrefix.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum CPrefix
|
||||
{
|
||||
Role = 0,
|
||||
//UserIDkey
|
||||
UID = 1,
|
||||
/// <summary>
|
||||
/// 头像KEY
|
||||
/// </summary>
|
||||
HDImg = 2,
|
||||
Token = 3,
|
||||
CityList
|
||||
|
||||
}
|
||||
}
|
||||
17
api_sqlsugar/VolPro.Core/Enums/DbCurrentType.cs
Normal file
17
api_sqlsugar/VolPro.Core/Enums/DbCurrentType.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum DbCurrentType
|
||||
{
|
||||
Default = 0,
|
||||
MySql = 1,
|
||||
MsSql = 2,//2020.08.08修改sqlserver拼写
|
||||
PgSql = 3,
|
||||
Kdbndp,//人大金仓
|
||||
Oracle, //2022.12.26
|
||||
DM, //2024.02.27
|
||||
}
|
||||
}
|
||||
30
api_sqlsugar/VolPro.Core/Enums/LinqExpressionType.cs
Normal file
30
api_sqlsugar/VolPro.Core/Enums/LinqExpressionType.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum LinqExpressionType
|
||||
{
|
||||
Equal = 0,//=
|
||||
NotEqual = 1,//!=
|
||||
GreaterThan,//>
|
||||
LessThan,//<
|
||||
ThanOrEqual,//>=
|
||||
LessThanOrEqual,//<=
|
||||
In,
|
||||
NotIn,
|
||||
Contains,//Contains
|
||||
Like,//Contains
|
||||
LikeStart,
|
||||
LikeEnd,
|
||||
NotLike,
|
||||
NotContains,//NotContains
|
||||
Null,
|
||||
NotNull,
|
||||
Empty,
|
||||
NotEmpty,
|
||||
NullOrEmpty,
|
||||
NotNullOrEmpty
|
||||
}
|
||||
}
|
||||
54
api_sqlsugar/VolPro.Core/Enums/LoggerType.cs
Normal file
54
api_sqlsugar/VolPro.Core/Enums/LoggerType.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum LoggerType
|
||||
{
|
||||
System = 0,
|
||||
Info,
|
||||
Success,
|
||||
Error,
|
||||
Authorzie,
|
||||
Global,
|
||||
Login,
|
||||
Exception,
|
||||
ApiException,
|
||||
HandleError,
|
||||
OnActionExecuted,
|
||||
GetUserInfo,
|
||||
Edit,
|
||||
Search,
|
||||
Add,
|
||||
Del,
|
||||
AppHome,
|
||||
ApiLogin,
|
||||
ApiPINLogin,
|
||||
ApiRegister,
|
||||
ApiModifyPwd,
|
||||
ApiSendPIN,
|
||||
ApiAuthorize,
|
||||
Ask,
|
||||
JoinMeeting,
|
||||
JoinUs,
|
||||
EditUserInfo,
|
||||
Sell,
|
||||
Buy,
|
||||
ReportPrice,
|
||||
Reply,
|
||||
TechData,
|
||||
TechSecondData,
|
||||
DelPublicQuestion,
|
||||
DelexpertQuestion,
|
||||
CreateTokenError,
|
||||
IPhoneTest,
|
||||
SDKSuccess,
|
||||
SDKSendError,
|
||||
ExpertAuthority,
|
||||
ParEmpty,
|
||||
NoToken,
|
||||
ReplaceToeken,
|
||||
KafkaException
|
||||
}
|
||||
}
|
||||
29
api_sqlsugar/VolPro.Core/Enums/NotificationType.cs
Normal file
29
api_sqlsugar/VolPro.Core/Enums/NotificationType.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// 通知类型
|
||||
/// </summary>
|
||||
public enum NotificationType
|
||||
{
|
||||
审批 = 1,
|
||||
通知 = 2,
|
||||
系统 = 3,
|
||||
抄送
|
||||
}
|
||||
/// <summary>
|
||||
/// 通知对象类型
|
||||
/// </summary>
|
||||
public enum NotificationTarget
|
||||
{
|
||||
用户 = 1,
|
||||
角色 = 2,
|
||||
部门 = 3,
|
||||
岗位 = 4
|
||||
}
|
||||
}
|
||||
12
api_sqlsugar/VolPro.Core/Enums/QueryOrderBy.cs
Normal file
12
api_sqlsugar/VolPro.Core/Enums/QueryOrderBy.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum QueryOrderBy
|
||||
{
|
||||
Desc=1,
|
||||
Asc=2
|
||||
}
|
||||
}
|
||||
31
api_sqlsugar/VolPro.Core/Enums/ResponseType.cs
Normal file
31
api_sqlsugar/VolPro.Core/Enums/ResponseType.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum ResponseType
|
||||
{
|
||||
ServerError = 1,
|
||||
LoginExpiration = 302,
|
||||
ParametersLack = 303,
|
||||
TokenExpiration,
|
||||
PINError,
|
||||
NoPermissions,
|
||||
NoRolePermissions,
|
||||
LoginError,
|
||||
AccountLocked,
|
||||
LoginSuccess,
|
||||
SaveSuccess,
|
||||
AuditSuccess,
|
||||
OperSuccess,
|
||||
RegisterSuccess,
|
||||
ModifyPwdSuccess,
|
||||
EidtSuccess,
|
||||
DelSuccess,
|
||||
NoKey,
|
||||
NoKeyDel,
|
||||
KeyError,
|
||||
Other
|
||||
}
|
||||
}
|
||||
14
api_sqlsugar/VolPro.Core/Enums/UserAgent.cs
Normal file
14
api_sqlsugar/VolPro.Core/Enums/UserAgent.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Enums
|
||||
{
|
||||
public enum UserAgent
|
||||
{
|
||||
IOS = 0,
|
||||
Android = 1,
|
||||
Windows = 2,
|
||||
Linux
|
||||
}
|
||||
}
|
||||
44
api_sqlsugar/VolPro.Core/Extensions/AuthorizationResponse.cs
Normal file
44
api_sqlsugar/VolPro.Core/Extensions/AuthorizationResponse.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net;
|
||||
using System.Security.Claims;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Services;
|
||||
using VolPro.Core.Utilities;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class AuthorizationResponse
|
||||
{
|
||||
public static AuthorizationFilterContext FilterResult(
|
||||
this AuthorizationFilterContext context,
|
||||
HttpStatusCode statusCode,
|
||||
string message = null)
|
||||
{
|
||||
context.Result = new ContentResult()
|
||||
{
|
||||
Content = new { message, status = false, code = (int)statusCode }.Serialize(),
|
||||
ContentType = "application/json",
|
||||
StatusCode = (int)statusCode
|
||||
};
|
||||
Logger.Info(LoggerType.ApiAuthorize, message);
|
||||
return context;
|
||||
}
|
||||
public static AuthorizationFilterContext Unauthorized(this AuthorizationFilterContext context, string message = null)
|
||||
{
|
||||
return context.FilterResult(HttpStatusCode.Unauthorized, message);
|
||||
}
|
||||
//不通过JWT验证的,直接将用户信息缓存起来
|
||||
public static void AddIdentity(this AuthorizationFilterContext context, int? userId=null)
|
||||
{
|
||||
int _userId = userId ?? JwtHelper.GetUserId(context.HttpContext.Request.Headers[AppSetting.TokenHeaderName]);
|
||||
if (_userId <= 0) return;
|
||||
//将用户Id缓存到上下文(或者自定一个对象,通过DI以AddScoped方式注入上下文来管理用户信息)
|
||||
var claims = new Claim[] { new Claim(JwtRegisteredClaimNames.Jti, _userId.ToString()) };
|
||||
context.HttpContext.User.AddIdentity(new ClaimsIdentity(claims));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using VolPro.Core.Extensions;
|
||||
using System;
|
||||
using VolPro.Core.Configuration;
|
||||
|
||||
namespace VolPro.Core.Extensions.AutofacManager
|
||||
{
|
||||
public class AutofacContainerModule
|
||||
{
|
||||
public static TService GetService<TService>() where TService:class
|
||||
{
|
||||
return typeof(TService).GetService() as TService;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
using Autofac;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using VolPro.Core.CacheManager;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.Dapper;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.EFDbContext;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions.AutofacManager;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Core.ObjectActionValidator;
|
||||
using VolPro.Core.Services;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class AutofacContainerModuleExtension
|
||||
{
|
||||
// private static bool _isMysql = false;
|
||||
public static IServiceCollection AddModule(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
//services.AddSession();
|
||||
//services.AddMemoryCache();
|
||||
//初始化配置文件
|
||||
AppSetting.Init(services, configuration);
|
||||
Type baseType = typeof(IDependency);
|
||||
var compilationLibrary = DependencyContext.Default
|
||||
.RuntimeLibraries
|
||||
.Where(x => !x.Serviceable
|
||||
&& x.Type == "project")
|
||||
.ToList();
|
||||
var count1 = compilationLibrary.Count;
|
||||
List<Assembly> assemblyList = new List<Assembly>();
|
||||
|
||||
foreach (var _compilation in compilationLibrary)
|
||||
{
|
||||
try
|
||||
{
|
||||
assemblyList.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(_compilation.Name)));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(_compilation.Name + ex.Message);
|
||||
}
|
||||
}
|
||||
//插件开发
|
||||
//try
|
||||
//{
|
||||
// var provider = services.BuildServiceProvider();
|
||||
// IWebHostEnvironment webHostEnvironment = provider.GetRequiredService<IWebHostEnvironment>();
|
||||
// string rootPath = (webHostEnvironment.ContentRootPath + "\\plugs").ReplacePath();
|
||||
// foreach (var item in Directory.GetFiles(rootPath).Where(x => x.EndsWith(".dll")))
|
||||
// {
|
||||
// string path = ($"{item}").ReplacePath();
|
||||
// AssemblyName assemblyName = Assembly.LoadFrom(path).GetName(); ;
|
||||
// assemblyList.Add(AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName));
|
||||
// }
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Console.WriteLine($"解析类库异常:{ex.Message + ex.StackTrace}");
|
||||
//}
|
||||
int count = 0;
|
||||
foreach (var _compilation in compilationLibrary)
|
||||
{
|
||||
var types = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(_compilation.Name)).GetTypes();
|
||||
|
||||
var implementedInterfaces = types.Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Length > 0)
|
||||
.Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract)
|
||||
.Select(t => (serviceType: t.GetInterfaces(), implementationType: t))
|
||||
.ToList();
|
||||
|
||||
foreach (var (serviceType, implementationType) in implementedInterfaces)
|
||||
{
|
||||
if (serviceType.Length==1&& serviceType.Any(x => x == baseType))
|
||||
{
|
||||
services.AddScoped(implementationType);
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddScoped(serviceType[0], implementationType);
|
||||
//Console.WriteLine($"注入:{serviceType[0].Name},{implementationType.Name}");
|
||||
}
|
||||
count++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Console.WriteLine(count);
|
||||
services.AddScoped<UserContext>();
|
||||
services.AddScoped<ActionObserver>();
|
||||
services.AddScoped<ObjectModelValidatorState>();
|
||||
// services.AddScoped<WeChatService>();
|
||||
services.AddSingleton(typeof(ICacheService), AppSetting.UseRedis ? typeof(RedisCacheService) : typeof(MemoryCacheService));
|
||||
//if (AppSetting.UseRedis)
|
||||
//{
|
||||
// services.AddSingleton<RedisCacheService>();
|
||||
//}
|
||||
if (DBType.Name == DbCurrentType.PgSql.ToString())
|
||||
{
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
|
||||
}
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
|
||||
DapperParseGuidTypeHandler.InitParseGuid();
|
||||
DbCache.Init();
|
||||
//kafka注入
|
||||
//if (AppSetting.Kafka.UseConsumer)
|
||||
// builder.RegisterType<KafkaConsumer<string, string>>().As<IKafkaConsumer<string, string>>().SingleInstance();
|
||||
//if (AppSetting.Kafka.UseProducer)
|
||||
// builder.RegisterType<KafkaProducer<string, string>>().As<IKafkaProducer<string, string>>().SingleInstance();
|
||||
return services;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Extensions.AutofacManager
|
||||
{
|
||||
public interface IDependency
|
||||
{
|
||||
}
|
||||
}
|
||||
23
api_sqlsugar/VolPro.Core/Extensions/CacheKeyExtensions.cs
Normal file
23
api_sqlsugar/VolPro.Core/Extensions/CacheKeyExtensions.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using VolPro.Core.Enums;
|
||||
using System;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class CacheKeyExtensions
|
||||
{
|
||||
public static string GetKey(this CPrefix prefix, object value)
|
||||
{
|
||||
return prefix.ToString() + value;
|
||||
}
|
||||
|
||||
public static string GetUserIdKey(this int userId)
|
||||
{
|
||||
return CPrefix.UID.ToString() + userId;
|
||||
}
|
||||
|
||||
public static string GetRoleIdKey(this int roleId)
|
||||
{
|
||||
return CPrefix.Role.ToString() + roleId;
|
||||
}
|
||||
}
|
||||
}
|
||||
313
api_sqlsugar/VolPro.Core/Extensions/ConvertJsonExtension.cs
Normal file
313
api_sqlsugar/VolPro.Core/Extensions/ConvertJsonExtension.cs
Normal file
@@ -0,0 +1,313 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using VolPro.Core.Controllers.Basic;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class ConvertJsonExtension
|
||||
{
|
||||
#region 私有方法
|
||||
/// <summary>
|
||||
/// 过滤特殊字符
|
||||
/// </summary>
|
||||
/// <param name="s">字符串</param>
|
||||
/// <returns>json字符串</returns>
|
||||
private static string String2Json(String s)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
char c = s.ToCharArray()[i];
|
||||
switch (c)
|
||||
{
|
||||
case '\"':
|
||||
sb.Append("\\\""); break;
|
||||
case '\\':
|
||||
sb.Append("\\\\"); break;
|
||||
case '/':
|
||||
sb.Append("\\/"); break;
|
||||
case '\b':
|
||||
sb.Append("\\b"); break;
|
||||
case '\f':
|
||||
sb.Append("\\f"); break;
|
||||
case '\n':
|
||||
sb.Append("\\n"); break;
|
||||
case '\r':
|
||||
sb.Append("\\r"); break;
|
||||
case '\t':
|
||||
sb.Append("\\t"); break;
|
||||
default:
|
||||
sb.Append(c); break;
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// 格式化字符型、日期型、布尔型
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
private static string StringFormat(string str, Type type)
|
||||
{
|
||||
if (type == typeof(string))
|
||||
{
|
||||
str = String2Json(str);
|
||||
str = "\"" + str + "\"";
|
||||
}
|
||||
else if (type == typeof(DateTime))
|
||||
{
|
||||
str = "\"" + str + "\"";
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
str = str.ToLower();
|
||||
}
|
||||
else if (type != typeof(string) && string.IsNullOrEmpty(str))
|
||||
{
|
||||
str = "\"" + str + "\"";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region list转换成JSON
|
||||
/// <summary>
|
||||
/// list转换为Json
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <returns></returns>
|
||||
public static string ListToJson<T>(this IList<T> list)
|
||||
{
|
||||
object obj = list[0];
|
||||
return ListToJson<T>(list, obj.GetType().Name);
|
||||
}
|
||||
/// <summary>
|
||||
/// list转换为json
|
||||
/// </summary>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <param name="list"></param>
|
||||
/// <param name="p"></param>
|
||||
/// <returns></returns>
|
||||
private static string ListToJson<T>(this IList<T> list, string JsonName)
|
||||
{
|
||||
return list.Serialize();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 对象转换为Json
|
||||
/// <summary>
|
||||
/// 对象转换为json
|
||||
/// </summary>
|
||||
/// <param name="jsonObject">json对象</param>
|
||||
/// <returns>json字符串</returns>
|
||||
public static string ToJson(this object jsonObject)
|
||||
{
|
||||
if (jsonObject==null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return jsonObject.Serialize();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 对象集合转换为json
|
||||
/// <summary>
|
||||
/// 对象集合转换为json
|
||||
/// </summary>
|
||||
/// <param name="array">对象集合</param>
|
||||
/// <returns>json字符串</returns>
|
||||
public static string ToJson(this IEnumerable array)
|
||||
{
|
||||
string jsonString = "{";
|
||||
foreach (object item in array)
|
||||
{
|
||||
jsonString += ToJson(item) + ",";
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, jsonString.Length);
|
||||
return jsonString + "]";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 普通集合转换Json
|
||||
/// <summary>
|
||||
/// 普通集合转换Json
|
||||
/// </summary>
|
||||
/// <param name="array">集合对象</param>
|
||||
/// <returns>Json字符串</returns>
|
||||
public static string ToArrayString(this IEnumerable array)
|
||||
{
|
||||
string jsonString = "[";
|
||||
foreach (object item in array)
|
||||
{
|
||||
jsonString = ToJson(item.ToString()) + ",";
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, jsonString.Length);
|
||||
return jsonString + "]";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DataSet转换为Json
|
||||
/// <summary>
|
||||
/// DataSet转换为Json
|
||||
/// </summary>
|
||||
/// <param name="dataSet">DataSet对象</param>
|
||||
/// <returns>Json字符串</returns>
|
||||
public static string ToJson(this DataSet dataSet)
|
||||
{
|
||||
string jsonString = "{";
|
||||
foreach (DataTable table in dataSet.Tables)
|
||||
{
|
||||
jsonString += "\"" + table.TableName + "\":" + ToJson(table) + ",";
|
||||
}
|
||||
jsonString = jsonString.TrimEnd(',');
|
||||
return jsonString + "}";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Datatable转换为Json
|
||||
/// <summary>
|
||||
/// Datatable转换为Json
|
||||
/// </summary>
|
||||
/// <param name="table">Datatable对象</param>
|
||||
/// <returns>Json字符串</returns>
|
||||
public static string ToJson(this DataTable dt)
|
||||
{
|
||||
StringBuilder jsonString = new StringBuilder();
|
||||
jsonString.Append("[");
|
||||
DataRowCollection drc = dt.Rows;
|
||||
for (int i = 0; i < drc.Count; i++)
|
||||
{
|
||||
jsonString.Append("{");
|
||||
for (int j = 0; j < dt.Columns.Count; j++)
|
||||
{
|
||||
string strKey = dt.Columns[j].ColumnName;
|
||||
string strValue = drc[i][j].ToString();
|
||||
Type type = dt.Columns[j].DataType;
|
||||
jsonString.Append("\"" + strKey + "\":");
|
||||
strValue = StringFormat(strValue, type);
|
||||
if (j < dt.Columns.Count - 1)
|
||||
{
|
||||
jsonString.Append(strValue + ",");
|
||||
}
|
||||
else
|
||||
{
|
||||
jsonString.Append(strValue);
|
||||
}
|
||||
}
|
||||
jsonString.Append("},");
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, 1);
|
||||
jsonString.Append("]");
|
||||
return jsonString.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// DataTable转换为Json
|
||||
/// </summary>
|
||||
public static string ToJson(this DataTable dt, string jsonName)
|
||||
{
|
||||
StringBuilder Json = new StringBuilder();
|
||||
if (string.IsNullOrEmpty(jsonName))
|
||||
jsonName = dt.TableName;
|
||||
Json.Append("{\"" + jsonName + "\":[");
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < dt.Rows.Count; i++)
|
||||
{
|
||||
Json.Append("{");
|
||||
for (int j = 0; j < dt.Columns.Count; j++)
|
||||
{
|
||||
Type type = dt.Rows[i][j].GetType();
|
||||
Json.Append("\"" + dt.Columns[j].ColumnName.ToString() + "\":" + StringFormat(dt.Rows[i][j].ToString(), type));
|
||||
if (j < dt.Columns.Count - 1)
|
||||
{
|
||||
Json.Append(",");
|
||||
}
|
||||
}
|
||||
Json.Append("}");
|
||||
if (i < dt.Rows.Count - 1)
|
||||
{
|
||||
Json.Append(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
Json.Append("]}");
|
||||
return Json.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DataReader转换为Json
|
||||
/// <summary>
|
||||
/// DataReader转换为Json
|
||||
/// </summary>
|
||||
/// <param name="dataReader">DataReader对象</param>
|
||||
/// <returns>Json字符串</returns>
|
||||
public static string ReaderJson(this IDataReader dataReader)
|
||||
{
|
||||
StringBuilder jsonString = new StringBuilder();
|
||||
Dictionary<string, Type> ModelField = new Dictionary<string, Type>();
|
||||
for (int i = 0; i < dataReader.FieldCount; i++)
|
||||
{
|
||||
ModelField.Add(dataReader.GetName(i), dataReader.GetFieldType(i));
|
||||
}
|
||||
jsonString.Append("[");
|
||||
while (dataReader.Read())
|
||||
{
|
||||
jsonString.Append("{");
|
||||
foreach (KeyValuePair<string, Type> keyVal in ModelField)
|
||||
{
|
||||
Type type = keyVal.Value;
|
||||
string strKey = keyVal.Key;
|
||||
string strValue = dataReader[strKey].ToString();
|
||||
jsonString.Append("\"" + strKey + "\":");
|
||||
strValue = StringFormat(strValue, type);
|
||||
jsonString.Append(strValue + ",");
|
||||
}
|
||||
jsonString.Remove(jsonString.Length - 1, 1);
|
||||
jsonString.Append("},");
|
||||
}
|
||||
dataReader.Close();
|
||||
jsonString.Remove(jsonString.Length - 1, 1);
|
||||
jsonString.Append("]");
|
||||
return jsonString.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public static T DeserializeObject<T>(this string entityString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entityString))
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
if (entityString == "{}")
|
||||
{
|
||||
entityString = "[]";
|
||||
}
|
||||
var settings = new JsonSerializerSettings();
|
||||
settings.Converters.Add(new LongCovert());
|
||||
return JsonConvert.DeserializeObject<T>(entityString, settings);
|
||||
}
|
||||
|
||||
public static string Serialize(this object obj, JsonSerializerSettings formatDate = null)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
formatDate = formatDate ?? new JsonSerializerSettings
|
||||
{
|
||||
DateFormatString = "yyyy-MM-dd HH:mm:ss"
|
||||
};
|
||||
formatDate.Converters.Add(new LongCovert());
|
||||
return JsonConvert.SerializeObject(obj, formatDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
54
api_sqlsugar/VolPro.Core/Extensions/EntityCustom.cs
Normal file
54
api_sqlsugar/VolPro.Core/Extensions/EntityCustom.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Entity.DomainModels;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
|
||||
public static class EntityCustom
|
||||
{
|
||||
private static string[] DefaultFields = null;// new string[] { "你的字段1", "你的字段2" };
|
||||
|
||||
/// <summary>
|
||||
/// 功能作用:给所有表包括DefaultFields数组的字段都统一设置默认值
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="entity"></param>
|
||||
public static void SetValue<T>(this T entity) where T : class
|
||||
{
|
||||
if (DefaultFields == null) return;
|
||||
var properties = typeof(T).GetProperties().Where(x => DefaultFields.Contains(x.Name));
|
||||
if (!properties.Any()) return;
|
||||
|
||||
//如果某些表有相同的字段但不需要设置值,在这此执行
|
||||
//if (nameof(T)==nameof(表model))
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
//在这里给表对象设置默认值
|
||||
foreach (var item in properties)
|
||||
{
|
||||
//UserContext.Current.UserInfo获取用户信息,也可以在userinfo里面加其他字段
|
||||
//usercontext是已缓存的对象,尽量不要在这里查询数据库
|
||||
switch (item.Name)
|
||||
{
|
||||
case "你的字段1":
|
||||
//可以从UserContext.Current.UserInfo取值
|
||||
item.SetValue(entity, "你的字段1值");
|
||||
break;
|
||||
case "你的字段2":
|
||||
item.SetValue(entity, "你的字段2值");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1482
api_sqlsugar/VolPro.Core/Extensions/EntityProperties.cs
Normal file
1482
api_sqlsugar/VolPro.Core/Extensions/EntityProperties.cs
Normal file
File diff suppressed because it is too large
Load Diff
105
api_sqlsugar/VolPro.Core/Extensions/GenericExtension.cs
Normal file
105
api_sqlsugar/VolPro.Core/Extensions/GenericExtension.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 泛型扩展
|
||||
/// </summary>
|
||||
public static class GenericExtension
|
||||
{
|
||||
public static bool Equal<T>(this T x, T y)
|
||||
{
|
||||
return ((IComparable)(x)).CompareTo(y) == 0;
|
||||
}
|
||||
|
||||
#region ToDictionary
|
||||
/// <summary>
|
||||
/// 将实体指定的字段写入字典
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="t"></param>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public static Dictionary<string, object> ToDictionary<T>(this T t, Expression<Func<T, object>> expression) where T : class
|
||||
{
|
||||
Dictionary<string, object> dic = new Dictionary<string, object>();
|
||||
string[] fields = expression.GetExpressionToArray();
|
||||
PropertyInfo[] properties = expression == null ? t.GetType().GetProperties() : t.GetType().GetProperties().Where(x => fields.Contains(x.Name)).ToArray();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var value = property.GetValue(t, null);
|
||||
dic.Add(property.Name, value != null ? value.ToString() : "");
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> ToDictionary<TInterface, T>(this TInterface t, Dictionary<string, string> dic = null) where T : class, TInterface
|
||||
{
|
||||
if (dic == null)
|
||||
dic = new Dictionary<string, string>();
|
||||
var properties = typeof(T).GetProperties();
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var value = property.GetValue(t, null);
|
||||
if (value == null) continue;
|
||||
dic.Add(property.Name, value != null ? value.ToString() : "");
|
||||
}
|
||||
return dic;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public static DataTable ToDataTable<T>(this IEnumerable<T> source, Expression<Func<T, object>> columns = null, bool contianKey = true)
|
||||
{
|
||||
DataTable dtReturn = new DataTable();
|
||||
if (source == null) return dtReturn;
|
||||
|
||||
PropertyInfo[] oProps = typeof(T).GetProperties()
|
||||
.Where(x => x.PropertyType.Name != "List`1").ToArray();
|
||||
if (columns != null)
|
||||
{
|
||||
string[] columnArray = columns.GetExpressionToArray();
|
||||
oProps = oProps.Where(x => columnArray.Contains(x.Name)).ToArray();
|
||||
}
|
||||
//移除自增主键
|
||||
PropertyInfo keyType = oProps.GetKeyProperty();// oProps.GetKeyProperty()?.PropertyType;
|
||||
if (!contianKey && keyType != null && (keyType.PropertyType == typeof(int) || keyType.PropertyType == typeof(long)))
|
||||
{
|
||||
oProps = oProps.Where(x => x.Name != keyType.Name).ToArray();
|
||||
}
|
||||
|
||||
foreach (var pi in oProps)
|
||||
{
|
||||
var colType = pi.PropertyType;
|
||||
|
||||
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>)))
|
||||
{
|
||||
colType = colType.GetGenericArguments()[0];
|
||||
}
|
||||
|
||||
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
|
||||
}
|
||||
foreach (var rec in source)
|
||||
{
|
||||
var dr = dtReturn.NewRow();
|
||||
foreach (var pi in oProps)
|
||||
{
|
||||
dr[pi.Name] = pi.GetValue(rec, null) == null
|
||||
? DBNull.Value
|
||||
: pi.GetValue
|
||||
(rec, null);
|
||||
}
|
||||
dtReturn.Rows.Add(dr);
|
||||
}
|
||||
return dtReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
api_sqlsugar/VolPro.Core/Extensions/HtmlHelperViewExtensions.cs
Normal file
103
api_sqlsugar/VolPro.Core/Extensions/HtmlHelperViewExtensions.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class HtmlHelperViewExtensions
|
||||
{
|
||||
public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)
|
||||
{
|
||||
var controller = (string)helper.ViewContext.RouteData.Values["controller"];
|
||||
|
||||
return Action(helper, action, controller, parameters);
|
||||
}
|
||||
|
||||
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)
|
||||
{
|
||||
var area = (string)helper.ViewContext.RouteData.Values["area"];
|
||||
|
||||
return Action(helper, action, controller, area, parameters);
|
||||
}
|
||||
|
||||
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
|
||||
{
|
||||
if (action == null)
|
||||
throw new ArgumentNullException("action");
|
||||
|
||||
if (controller == null)
|
||||
throw new ArgumentNullException("controller");
|
||||
|
||||
|
||||
var task = RenderActionAsync(helper, action, controller, area, parameters);
|
||||
|
||||
return task.Result;
|
||||
}
|
||||
|
||||
private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
|
||||
{
|
||||
// fetching required services for invocation
|
||||
var serviceProvider = helper.ViewContext.HttpContext.RequestServices;
|
||||
var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
|
||||
var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
|
||||
var actionSelector = serviceProvider.GetRequiredService<IActionSelector>();
|
||||
|
||||
// creating new action invocation context
|
||||
var routeData = new RouteData();
|
||||
foreach (var router in helper.ViewContext.RouteData.Routers)
|
||||
{
|
||||
routeData.PushState(router, null, null);
|
||||
}
|
||||
routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null);
|
||||
routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null);
|
||||
|
||||
//get the actiondescriptor
|
||||
RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };
|
||||
var candidates = actionSelector.SelectCandidates(routeContext);
|
||||
var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);
|
||||
|
||||
var originalActionContext = actionContextAccessor.ActionContext;
|
||||
var originalhttpContext = httpContextAccessor.HttpContext;
|
||||
try
|
||||
{
|
||||
var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features);
|
||||
if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper)))
|
||||
{
|
||||
newHttpContext.Items.Remove(typeof(IUrlHelper));
|
||||
}
|
||||
newHttpContext.Response.Body = new MemoryStream();
|
||||
var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
|
||||
actionContextAccessor.ActionContext = actionContext;
|
||||
var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext);
|
||||
await invoker.InvokeAsync();
|
||||
newHttpContext.Response.Body.Position = 0;
|
||||
using (var reader = new StreamReader(newHttpContext.Response.Body))
|
||||
{
|
||||
return new HtmlString(reader.ReadToEnd());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new HtmlString(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
actionContextAccessor.ActionContext = originalActionContext;
|
||||
httpContextAccessor.HttpContext = originalhttpContext;
|
||||
if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper)))
|
||||
{
|
||||
helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Security.Policy;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class HttpClientFactoryExtension
|
||||
{
|
||||
public static async Task<string> PostAsync(this IHttpClientFactory httpClientFactory, string url,
|
||||
object parameters = null,
|
||||
Dictionary<string, string> headers = null,
|
||||
string contentType = "application/x-www-form-urlencoded")
|
||||
{
|
||||
var request = InitPostData(url, parameters, headers, contentType);
|
||||
var client = httpClientFactory.CreateClient();
|
||||
using HttpResponseMessage httpResponseMessage = await client.SendAsync(request);
|
||||
return await httpResponseMessage.Content.ReadAsStringAsync();
|
||||
}
|
||||
public static async Task<(bool status, T data, string message)> PostAsync<T>(
|
||||
this IHttpClientFactory httpClientFactory,
|
||||
string url,
|
||||
object parameters = null,
|
||||
Dictionary<string, string> headers = null,
|
||||
string contentType = "application/x-www-form-urlencoded")
|
||||
{
|
||||
var request = InitPostData(url, parameters, headers, contentType);
|
||||
var client = httpClientFactory.CreateClient();
|
||||
using HttpResponseMessage httpResponseMessage = await client.SendAsync(request);
|
||||
string message = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
return (true, message.DeserializeObject<T>(), null);
|
||||
}
|
||||
return (false, default(T), httpResponseMessage.StatusCode + "," + message);
|
||||
}
|
||||
|
||||
public static async Task<string> GetAsync(this IHttpClientFactory httpClientFactory, string url,
|
||||
Dictionary<string, string> parameters = null,
|
||||
Dictionary<string, string> headers = null,
|
||||
string contentType = "application/x-www-form-urlencoded")
|
||||
{
|
||||
var client = httpClientFactory.CreateClient();
|
||||
var request = InitGetData(url, parameters, headers, contentType);
|
||||
using (HttpResponseMessage httpResponseMessage = await client.SendAsync(request))
|
||||
{
|
||||
string result = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<(bool status, T data, string message)> GetAsync<T>(this IHttpClientFactory httpClientFactory, string url,
|
||||
Dictionary<string, string> parameters = null,
|
||||
Dictionary<string, string> headers = null,
|
||||
string contentType = "application/x-www-form-urlencoded")
|
||||
{
|
||||
var client = httpClientFactory.CreateClient();
|
||||
var request = InitGetData(url, parameters, headers, contentType);
|
||||
using HttpResponseMessage httpResponseMessage = await client.SendAsync(request);
|
||||
string message = await httpResponseMessage.Content.ReadAsStringAsync();
|
||||
if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
return (true, message.DeserializeObject<T>(), null);
|
||||
}
|
||||
return (false, default(T), httpResponseMessage.StatusCode + "," + message);
|
||||
}
|
||||
private static HttpRequestMessage InitPostData(
|
||||
string url,
|
||||
object parameters = null,
|
||||
Dictionary<string, string> headers = null,
|
||||
string contentType = "application/x-www-form-urlencoded")
|
||||
{
|
||||
HttpContent content = null;
|
||||
|
||||
if (parameters != null)
|
||||
{
|
||||
// 根据Content-Type处理参数
|
||||
if (contentType.Equals("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 处理表单格式:转换为键值对并URL编码
|
||||
var formData = new FormUrlEncodedContent(ConvertToKeyValuePairs(parameters));
|
||||
content = formData;
|
||||
}
|
||||
else if (contentType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 处理JSON格式
|
||||
string json = Newtonsoft.Json.JsonConvert.SerializeObject(parameters);
|
||||
content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"不支持的Content-Type: {contentType}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 无参数时创建空内容
|
||||
content = new StringContent(string.Empty);
|
||||
}
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, url)
|
||||
{
|
||||
Content = content
|
||||
};
|
||||
// 设置内容类型(覆盖默认值)
|
||||
content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
|
||||
|
||||
// 添加自定义请求头
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var item in headers)
|
||||
{
|
||||
// 注意:有些头信息(如Content-Type)不能通过这种方式添加,需要通过Content.Headers设置
|
||||
if (!content.Headers.TryAddWithoutValidation(item.Key, item.Value) &&
|
||||
!item.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 如果头信息不能添加到内容头,则尝试添加到请求头
|
||||
request.Headers.TryAddWithoutValidation(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
private static HttpRequestMessage InitGetData(
|
||||
string url,
|
||||
Dictionary<string, string> parameters = null,
|
||||
Dictionary<string, string> headers = null,
|
||||
string contentType = "application/x-www-form-urlencoded")
|
||||
{
|
||||
var content = new StringContent("");
|
||||
if (parameters != null)
|
||||
{
|
||||
url += string.Join("&", parameters.Select(s => s.Key + "=" + HttpUtility.UrlEncode(s.Value)));
|
||||
}
|
||||
content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url)
|
||||
{
|
||||
Content = content
|
||||
};
|
||||
if (headers != null)
|
||||
{
|
||||
foreach (var item in headers)
|
||||
{
|
||||
request.Headers.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
// 将对象转换为键值对(用于表单提交)
|
||||
private static IEnumerable<KeyValuePair<string, string>> ConvertToKeyValuePairs(object obj)
|
||||
{
|
||||
var dict = new Dictionary<string, string>();
|
||||
if (obj == null) return dict;
|
||||
|
||||
var properties = obj.GetType().GetProperties();
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
var value = prop.GetValue(obj)?.ToString() ?? string.Empty;
|
||||
dict.Add(prop.Name, value);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
}
|
||||
277
api_sqlsugar/VolPro.Core/Extensions/IdentityCode.cs
Normal file
277
api_sqlsugar/VolPro.Core/Extensions/IdentityCode.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.BaseProvider;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.DbSqlSugar;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Core.Tenancy;
|
||||
using VolPro.Entity.DomainModels;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
|
||||
public static class IdentityCode
|
||||
{
|
||||
|
||||
private static List<Sys_CodeRule> _codeRules = null;
|
||||
private static object ruleObject = new object();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
_codeRules = null;
|
||||
}
|
||||
|
||||
public static List<Sys_CodeRule> CodeRules
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_codeRules == null)
|
||||
{
|
||||
lock (ruleObject)
|
||||
{
|
||||
if (_codeRules == null)
|
||||
{
|
||||
_codeRules = DBServerProvider.DbContext.Set<Sys_CodeRule>().ToList();//.FilterTenancy()
|
||||
}
|
||||
}
|
||||
}
|
||||
return _codeRules;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 生成单据号(先在[单据编码]菜单维护规则)
|
||||
/// 使用方式:var order = new DemoOrder();
|
||||
/// order.CreateCode();
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static T CreateCode<T>(this T entity) where T : class, new()
|
||||
{
|
||||
CreateCodeList(new List<T>() { entity });
|
||||
return entity;
|
||||
}
|
||||
/// <summary>
|
||||
/// 批量生成单据号(先在[单据编码]菜单维护规则)
|
||||
/// 使用方式:var list =new List<DemoOrder>(){};
|
||||
/// list.CreateCode();
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public static List<T> CreateCodeList<T>(this List<T> entity) where T : class, new()
|
||||
{
|
||||
var query = CodeRules.Where(x => x.TableName == typeof(T).Name);
|
||||
//租户分库
|
||||
if (AppSetting.UseDynamicShareDB)
|
||||
{
|
||||
query = query.Where(x => x.DbServiceId == UserContext.CurrentServiceId);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AppSetting.TenancyField != null)
|
||||
{
|
||||
query = query.Where(x => x.TenancyId == UserContext.CurrentServiceId.ToString());
|
||||
}
|
||||
}
|
||||
var rule = query.OrderByDescending(x => x.CreateDate).FirstOrDefault();
|
||||
if (rule == null)
|
||||
{
|
||||
return entity;
|
||||
}
|
||||
|
||||
RuleIncremental ruleIncremental = RuleIncremental.day;
|
||||
try
|
||||
{
|
||||
ruleIncremental = (RuleIncremental)Enum.Parse(typeof(RuleIncremental), rule.RuleIncremental);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"单据号枚举转换失败:${rule.RuleIncremental},ex:{ex.Message}");
|
||||
}
|
||||
CreateList<T>(entity,
|
||||
rule.Field.GetExpression<T>(),
|
||||
rule.PrefixCode,
|
||||
rule.OrderFiled?.GetExpression<T>(),
|
||||
filter: null,
|
||||
startingDay: rule.RuleIncremental == "day",//这里待完,只处理了是否每天每生成与一直接自增
|
||||
dateFormat: rule.RuleType,
|
||||
rule.ValueLen,
|
||||
rule.ConcatenationSymbol,
|
||||
ruleIncremental: ruleIncremental);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建自增单据号
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="entity">实体对象</param>
|
||||
/// <param name="codeField">要设置单据号的字段</param>
|
||||
/// <param name="preCode">单据号前缀,如:{TC}{2023}{0001}</param>
|
||||
/// <param name="dateFieldExpression">排序字段,每天都从第1个号码开始</param>
|
||||
/// <param name="filter">过滤条件</param>
|
||||
/// <param name="startingDay">是否每天都从第1个号码开始</param>
|
||||
/// <param name="dateFormat">是否生成日期流水号</param>
|
||||
/// <param name="len">数字长度</param>
|
||||
/// 使用示例:
|
||||
/// Sys_User user= new Sys_User();
|
||||
/// user.Create(x => x.UserName, "U", x => x.CreateDate);
|
||||
/// <returns></returns>
|
||||
public static string Create<T>(this T entity,
|
||||
Expression<Func<T, object>> codeField,
|
||||
string preCode = "Code",
|
||||
Expression<Func<T, object>> dateFieldExpression = null,
|
||||
Expression<Func<T, bool>> filter = null,
|
||||
bool startingDay = true,
|
||||
string dateFormat = "yyyyMMdd",
|
||||
int len = 4,
|
||||
string concatenationSymbol = null,
|
||||
RuleIncremental ruleIncremental = RuleIncremental.day
|
||||
) where T : class, new()
|
||||
{
|
||||
return new List<T>() { entity }.CreateList(codeField, preCode, dateFieldExpression, filter, startingDay, dateFormat, len, concatenationSymbol, ruleIncremental: ruleIncremental);
|
||||
}
|
||||
|
||||
public static string CreateList<T>(this List<T> list,
|
||||
Expression<Func<T, object>> codeField,
|
||||
string preCode = "Code",
|
||||
Expression<Func<T, object>> dateFieldExpression = null,
|
||||
Expression<Func<T, bool>> filter = null,
|
||||
bool startingDay = true,
|
||||
string dateFormat = "yyyyMMdd",
|
||||
int len = 4,
|
||||
string concatenationSymbol = null,
|
||||
RuleIncremental ruleIncremental = RuleIncremental.day
|
||||
) where T : class,new()
|
||||
{
|
||||
if (dateFormat == RuleIncremental.none.ToString())
|
||||
{
|
||||
dateFormat = null;
|
||||
}
|
||||
|
||||
if (concatenationSymbol == null)
|
||||
{
|
||||
concatenationSymbol = "";
|
||||
}
|
||||
string dateField;
|
||||
|
||||
if (dateFieldExpression == null)
|
||||
{
|
||||
dateField = AppSetting.CreateMember.DateField;
|
||||
}
|
||||
else
|
||||
{
|
||||
dateField = dateFieldExpression.GetExpressionPropertyFirst();
|
||||
}
|
||||
var field = codeField.GetExpressionPropertyFirst();
|
||||
|
||||
|
||||
DateTime? dateNow = null;// (DateTime)DateTime.Now.ToString("yyyy-MM-dd").GetDateTime();
|
||||
switch (ruleIncremental)
|
||||
{
|
||||
case RuleIncremental.none:
|
||||
break;
|
||||
case RuleIncremental.day:
|
||||
dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-dd").GetDateTime();
|
||||
break;
|
||||
case RuleIncremental.month:
|
||||
dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-01").GetDateTime();
|
||||
break;
|
||||
case RuleIncremental.year:
|
||||
dateNow = (DateTime)DateTime.Now.ToString("yyyy-01-01").GetDateTime();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Expression<Func<T, bool>> condition = null;
|
||||
if (dateNow != null)
|
||||
{
|
||||
condition = dateField.CreateExpression<T>(dateNow, Enums.LinqExpressionType.ThanOrEqual);
|
||||
}
|
||||
|
||||
Expression<Func<T, bool>> conditionStartWdth = null;
|
||||
//增加指定开头单据号的查询,避免其他非单据号影响
|
||||
if (!string.IsNullOrEmpty(preCode))
|
||||
{
|
||||
conditionStartWdth = field.CreateExpression<T>(preCode, Enums.LinqExpressionType.LikeStart);
|
||||
}
|
||||
var select = field.GetExpression<T, string>();
|
||||
string rule = dateFormat == null ? preCode : $"{preCode}{concatenationSymbol}{DateTime.Now.ToString(dateFormat)}";
|
||||
string dateText = dateNow?.ToString("yyyy-MM-dd") ?? "none";
|
||||
//缓存获取自增编号
|
||||
|
||||
var property = typeof(T).GetProperty(field);
|
||||
string code = null;
|
||||
string serviceId = "";
|
||||
if (AppSetting.UseDynamicShareDB||!string.IsNullOrEmpty(AppSetting.TenancyField))
|
||||
{
|
||||
serviceId = $"_{UserContext.CurrentServiceId}";
|
||||
}
|
||||
string key = $"{typeof(T).Name}_{ruleIncremental.ToString()}_{dateText}{serviceId}";
|
||||
foreach (var entity in list)
|
||||
{
|
||||
int number = Increment<T>(key, filter, condition, conditionStartWdth, codeField, startingDay, select, len);
|
||||
code = $"{rule}{concatenationSymbol}{(number).ToString("D" + len)}";
|
||||
property.SetValue(entity, code);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
private static int GetTableLastIncrement<T>(Expression<Func<T, bool>> filter, Expression<Func<T, bool>> condition, Expression<Func<T, bool>> conditionStartWdth, Expression<Func<T, object>> codeField,bool startingDay, Expression<Func<T, string>> select, int len = 4) where T : class,new ()
|
||||
{
|
||||
string orderNo = DBServerProvider.GetEntityDbContext<T>().Set<T>()
|
||||
// .WhereIF(filter == null && startingDay, condition)
|
||||
.WhereIF(filter != null , filter)
|
||||
.WhereIF(condition != null, condition)
|
||||
.WhereIF(conditionStartWdth != null, conditionStartWdth)
|
||||
//.FilterTenancy()
|
||||
.OrderByDescending(codeField)
|
||||
.Select(select)
|
||||
.FirstOrDefault()
|
||||
?.ToString();
|
||||
|
||||
int number = 0;
|
||||
if (!string.IsNullOrEmpty(orderNo))
|
||||
{
|
||||
number = orderNo.Substring(orderNo.Length - len).GetInt();
|
||||
}
|
||||
return number;
|
||||
}
|
||||
internal static readonly ConcurrentDictionary<string, int> _counters = new ConcurrentDictionary<string, int>();
|
||||
private static int Increment<T>(string key, Expression<Func<T, bool>> filter, Expression<Func<T, bool>> condition, Expression<Func<T, bool>> conditionStartWdth, Expression<Func<T, object>> codeField, bool startingDay, Expression<Func<T, string>> select, int len = 4) where T : class, new()
|
||||
{
|
||||
//使用集群部署这里需要修改下,改为读取redis缓存或者取消下面的注释
|
||||
//return GetTableLastIncrement(filter, condition, conditionStartWdth, codeField, startingDay, select: select,len: len);
|
||||
|
||||
return _counters.AddOrUpdate(
|
||||
key,
|
||||
addValueFactory: (k) =>
|
||||
{
|
||||
int num = GetTableLastIncrement(filter, condition, conditionStartWdth, codeField,startingDay,select, len);
|
||||
return num+1;
|
||||
},
|
||||
(existingKey, existingValue) =>
|
||||
{
|
||||
return existingValue + 1;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public enum RuleIncremental
|
||||
{
|
||||
none = 0,
|
||||
day,
|
||||
month,
|
||||
year,
|
||||
}
|
||||
}
|
||||
206
api_sqlsugar/VolPro.Core/Extensions/IdentitySqlCode.cs
Normal file
206
api_sqlsugar/VolPro.Core/Extensions/IdentitySqlCode.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.DBManager;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Core.UserManager;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class IdentitySqlCode
|
||||
{
|
||||
public static void CreateCode(
|
||||
Dictionary<string, object> mainData,
|
||||
string tableName,
|
||||
List<TableColumnField> tableColumns = null,
|
||||
string leftQuote = null,
|
||||
string rightQuote = null)
|
||||
{
|
||||
// 1) 读取编码规则
|
||||
var query = IdentityCode.CodeRules.Where(x =>
|
||||
!string.IsNullOrEmpty(x.TableName) &&
|
||||
x.TableName.Equals(tableName, StringComparison.OrdinalIgnoreCase));
|
||||
if (AppSetting.UseDynamicShareDB)
|
||||
{
|
||||
query = query.Where(x => x.DbServiceId == UserContext.CurrentServiceId);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AppSetting.TenancyField != null)
|
||||
{
|
||||
query = query.Where(x => x.TenancyId == UserContext.CurrentServiceId.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
var rule = query.OrderByDescending(x => x.CreateDate).FirstOrDefault();
|
||||
if (rule == null) return;
|
||||
|
||||
RuleIncremental ruleIncremental = RuleIncremental.day;
|
||||
try
|
||||
{
|
||||
ruleIncremental = (RuleIncremental)Enum.Parse(typeof(RuleIncremental), rule.RuleIncremental);
|
||||
}
|
||||
catch
|
||||
{
|
||||
ruleIncremental = RuleIncremental.day;
|
||||
}
|
||||
|
||||
// 2) 映射单据字段(rule.Field 可能大小写/别名与实际列名不一致)
|
||||
string codeFieldName = rule.Field;
|
||||
if (tableColumns != null && !string.IsNullOrEmpty(codeFieldName))
|
||||
{
|
||||
var col = tableColumns.FirstOrDefault(c =>
|
||||
c.ColumnName.Equals(codeFieldName, StringComparison.OrdinalIgnoreCase));
|
||||
if (col != null) codeFieldName = col.ColumnName;
|
||||
}
|
||||
if (string.IsNullOrEmpty(codeFieldName)) return;
|
||||
|
||||
// 3) 找到业务表真实表名与库
|
||||
var tableInfo = TableColumnContext.TableInfo.FirstOrDefault(x =>
|
||||
!string.IsNullOrEmpty(x.TableName) &&
|
||||
x.TableName.Equals(tableName, StringComparison.OrdinalIgnoreCase));
|
||||
if (tableInfo == null) return;
|
||||
|
||||
string dbTableName = string.IsNullOrEmpty(tableInfo.TableTrueName)
|
||||
? tableInfo.TableName
|
||||
: tableInfo.TableTrueName;
|
||||
|
||||
string dbService = tableInfo.DBServer;
|
||||
if (string.IsNullOrEmpty(dbService)) return;
|
||||
|
||||
// 4) 构造规则前缀与日期起点
|
||||
string preCode = rule.PrefixCode ?? "";
|
||||
string concatenationSymbol = rule.ConcatenationSymbol ?? "";
|
||||
string dateFormat = rule.RuleType;
|
||||
if (dateFormat == RuleIncremental.none.ToString())
|
||||
{
|
||||
dateFormat = null;
|
||||
}
|
||||
|
||||
DateTime? dateNow = null;
|
||||
switch (ruleIncremental)
|
||||
{
|
||||
case RuleIncremental.day:
|
||||
dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-dd").GetDateTime();
|
||||
break;
|
||||
case RuleIncremental.month:
|
||||
dateNow = (DateTime)DateTime.Now.ToString("yyyy-MM-01").GetDateTime();
|
||||
break;
|
||||
case RuleIncremental.year:
|
||||
dateNow = (DateTime)DateTime.Now.ToString("yyyy-01-01").GetDateTime();
|
||||
break;
|
||||
case RuleIncremental.none:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
string dateText = dateNow?.ToString("yyyy-MM-dd") ?? "none";
|
||||
|
||||
string dateFieldName =
|
||||
!string.IsNullOrWhiteSpace(rule.OrderFiled)
|
||||
? rule.OrderFiled
|
||||
: AppSetting.CreateMember.DateField;
|
||||
|
||||
// 5) 共享缓存key(与 IdentityCode.CreateList 保持同形态,避免并发重复)
|
||||
string serviceId = "";
|
||||
if (AppSetting.UseDynamicShareDB || !string.IsNullOrEmpty(AppSetting.TenancyField))
|
||||
{
|
||||
serviceId = $"_{UserContext.CurrentServiceId}";
|
||||
}
|
||||
string cacheKey = $"{tableName}_{ruleIncremental}_{dateText}{serviceId}";
|
||||
|
||||
// 6) 自增流水号:同一 cacheKey 下,保证并发安全
|
||||
int number = IdentityCode._counters.AddOrUpdate(
|
||||
cacheKey,
|
||||
addValueFactory: (k) =>
|
||||
{
|
||||
// 获取库类型决定左右引号(MySql: ``, SqlServer: [ ])
|
||||
string dbType = DbRelativeCache.GetDbType(dbService) ?? DBType.Name;
|
||||
DbCurrentType dbCurrentType = (DbCurrentType)Enum.Parse(typeof(DbCurrentType), dbType, true);
|
||||
int last = GetLastIncrementBySql(
|
||||
dbService,
|
||||
dbTableName,
|
||||
codeFieldName,
|
||||
preCode,
|
||||
dateFieldName,
|
||||
dateNow,
|
||||
rule.ValueLen,
|
||||
leftQuote,
|
||||
rightQuote);
|
||||
return last + 1;
|
||||
},
|
||||
updateValueFactory: (k, existingValue) => existingValue + 1);
|
||||
|
||||
// 7) 生成最终编码字符串
|
||||
string ruleText = dateFormat == null
|
||||
? preCode
|
||||
: $"{preCode}{concatenationSymbol}{DateTime.Now.ToString(dateFormat)}";
|
||||
|
||||
string code = $"{ruleText}{concatenationSymbol}{(number).ToString("D" + rule.ValueLen)}";
|
||||
mainData[codeFieldName] = code;
|
||||
}
|
||||
|
||||
private static int GetLastIncrementBySql(
|
||||
string dbService,
|
||||
string dbTableName,
|
||||
string codeFieldName,
|
||||
string preCode,
|
||||
string dateFieldName,
|
||||
DateTime? dateNow,
|
||||
int len,
|
||||
string leftQuote,
|
||||
string rightQuote)
|
||||
{
|
||||
string table = $"{leftQuote}{dbTableName}{rightQuote}";
|
||||
string codeField = $"{leftQuote}{codeFieldName}{rightQuote}";
|
||||
string dateField = string.IsNullOrWhiteSpace(dateFieldName)
|
||||
? null
|
||||
: $"{leftQuote}{dateFieldName}{rightQuote}";
|
||||
|
||||
string sqlWhere = $"{codeField} LIKE @preCodeLike";
|
||||
if (dateNow != null && !string.IsNullOrEmpty(dateField))
|
||||
{
|
||||
sqlWhere += $" AND {dateField} >= @dateNow";
|
||||
}
|
||||
|
||||
// 取最后一条:按 codeField 倒序取 1 条
|
||||
// 这里不再通过 leftQuote/rightQuote 推断 DB 类型,所以按 dbService 取一次 DB 类型决定 SQL 语法
|
||||
string dbType = DbRelativeCache.GetDbType(dbService) ?? DBType.Name;
|
||||
DbCurrentType dbCurrentType = (DbCurrentType)Enum.Parse(typeof(DbCurrentType), dbType, true);
|
||||
|
||||
string sql;
|
||||
if (dbCurrentType == DbCurrentType.MsSql)
|
||||
{
|
||||
sql = $"SELECT TOP 1 {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC";
|
||||
}
|
||||
else if (dbCurrentType == DbCurrentType.Oracle)
|
||||
{
|
||||
sql = $"SELECT {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC FETCH FIRST 1 ROWS ONLY";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql = $"SELECT {codeField} FROM {table} WHERE {sqlWhere} ORDER BY {codeField} DESC LIMIT 1";
|
||||
}
|
||||
|
||||
var dapper = DbSqlSugar.DbManger.GetConnection(dbService);
|
||||
string lastCode = dapper.Ado.SqlQuery<string>(sql, new
|
||||
{
|
||||
preCodeLike = $"{preCode}%",
|
||||
dateNow
|
||||
}).FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrEmpty(lastCode)) return 0;
|
||||
|
||||
if (lastCode.Length >= len)
|
||||
{
|
||||
return int.TryParse(lastCode.Substring(lastCode.Length - len), out var n) ? n : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
842
api_sqlsugar/VolPro.Core/Extensions/LambdaExtensions.cs
Normal file
842
api_sqlsugar/VolPro.Core/Extensions/LambdaExtensions.cs
Normal file
@@ -0,0 +1,842 @@
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using VolPro.Core.BaseProvider;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.Enums;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class LambdaExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="queryable"></param>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
public static ISugarQueryable<T> TakePage<T>(this ISugarQueryable<T> queryable, int page, int size = 15)
|
||||
{
|
||||
return queryable.TakeOrderByPage<T>(page, size);
|
||||
}
|
||||
/// <summary>
|
||||
/// 分页查询
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="queryable"></param>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <returns></returns>
|
||||
public static ISugarQueryable<T> TakeOrderByPage<T>(this ISugarQueryable<T> queryable, int page, int size = 15, Expression<Func<T, Dictionary<object, QueryOrderBy>>> orderBy = null)
|
||||
{
|
||||
if (page <= 0)
|
||||
{
|
||||
page = 1;
|
||||
}
|
||||
return queryable.GetISugarQueryableOrderBy(orderBy.GetExpressionToDic())
|
||||
.Skip((page - 1) * size)
|
||||
.Take(size);
|
||||
}
|
||||
|
||||
|
||||
public static IEnumerable<T> TakePage<T>(this List<T> list, int page, int size = 15)
|
||||
{
|
||||
if (page <= 0)
|
||||
{
|
||||
page = 1;
|
||||
}
|
||||
return list.Skip((page - 1) * size).Take(size);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>true
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> True<T>()
|
||||
{
|
||||
return p => true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>false
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> False<T>()
|
||||
{
|
||||
|
||||
return p => false;
|
||||
}
|
||||
|
||||
public static ParameterExpression GetExpressionParameter(this Type type)
|
||||
{
|
||||
|
||||
return Expression.Parameter(type, "p");
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>p.propertyName
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="sort"></param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, TKey>> GetExpression<T, TKey>(this string propertyName)
|
||||
{
|
||||
return propertyName.GetExpression<T, TKey>(typeof(T).GetExpressionParameter());
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建委托有返回值的表达式:p=>p.propertyName
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="sort"></param>
|
||||
/// <returns></returns>
|
||||
public static Func<T, TKey> GetFun<T, TKey>(this string propertyName)
|
||||
{
|
||||
return propertyName.GetExpression<T, TKey>(typeof(T).GetExpressionParameter()).Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>false
|
||||
/// 在已知TKey字段类型时,如动态排序OrderBy(x=>x.ID)会用到此功能,返回的就是x=>x.ID
|
||||
/// Expression<Func<Out_Scheduling, DateTime>> expression = x => x.CreateDate;指定了类型
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, TKey>> GetExpression<T, TKey>(this string propertyName, ParameterExpression parameter)
|
||||
{
|
||||
if (typeof(TKey).Name == "Object")
|
||||
return Expression.Lambda<Func<T, TKey>>(Expression.Convert(Expression.Property(parameter, propertyName), typeof(object)), parameter);
|
||||
return Expression.Lambda<Func<T, TKey>>(Expression.Property(parameter, propertyName), parameter);
|
||||
}
|
||||
/// <summary>
|
||||
/// 创建lambda表达式:p=>false
|
||||
/// object不能确认字段类型(datetime,int,string),如动态排序OrderBy(x=>x.ID)会用到此功能,返回的就是x=>x.ID
|
||||
/// Expression<Func<Out_Scheduling, object>> expression = x => x.CreateDate;任意类型的字段
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, object>> GetExpression<T>(this string propertyName)
|
||||
{
|
||||
return propertyName.GetExpression<T, object>(typeof(T).GetExpressionParameter());
|
||||
}
|
||||
|
||||
public static Expression<Func<T, object>> GetExpression<T>(this string propertyName, ParameterExpression parameter)
|
||||
{
|
||||
return Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(parameter, propertyName), typeof(object)), parameter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="propertyName">字段名</param>
|
||||
/// <param name="propertyValue">表达式的值</param>
|
||||
/// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
|
||||
/// p=>p.propertyName.Contains(propertyValue)</param>
|
||||
/// <returns></returns>
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="propertyName">字段名</param>
|
||||
/// <param name="propertyValue">表达式的值</param>
|
||||
/// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
|
||||
/// p=>p.propertyName.Contains(propertyValue)</param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> CreateExpression<T>(this string propertyName, object propertyValue, LinqExpressionType expressionType, bool checkNullProperty = false)
|
||||
{
|
||||
return propertyName.CreateExpression<T>(propertyValue, null, expressionType, checkNullProperty);
|
||||
}
|
||||
private static Expression<Func<T, bool>> GetContainsExpression<T, FieldType>(string propertyName, object propertyValue, ParameterExpression parameter, LinqExpressionType expressionType)
|
||||
{
|
||||
Type proType = typeof(T).GetProperty(propertyName).PropertyType;
|
||||
var list = propertyValue as System.Collections.IList;
|
||||
|
||||
List<FieldType> arr = new List<FieldType>();
|
||||
foreach (var value in list)
|
||||
{
|
||||
if (value == null || value.ToString().Trim() == "")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var valRes = (proType == typeof(string) ? value.ToString() : value).ChangeType(proType);
|
||||
if (valRes != null)
|
||||
{
|
||||
arr.Add((FieldType)valRes);
|
||||
}
|
||||
}
|
||||
//string 类型的字段,如果值带有'单引号,EF会默认变成''两个单引号
|
||||
var method = arr.GetType().GetMethod("Contains");
|
||||
ConstantExpression constantCollection = Expression.Constant(arr);
|
||||
MemberExpression memberProperty = Expression.PropertyOrField(parameter, propertyName);
|
||||
if (expressionType == LinqExpressionType.NotIn)
|
||||
{
|
||||
return Expression.Lambda<Func<T, bool>>(Expression.Not(Expression.Call(constantCollection, method, memberProperty)), parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodCallExpression methodCall = Expression.Call(constantCollection, method, memberProperty);
|
||||
return Expression.Lambda<Func<T, bool>>(methodCall, parameter);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CheckFilterNullExpression(this LinqExpressionType filterType)
|
||||
{
|
||||
switch (filterType)
|
||||
{
|
||||
case LinqExpressionType.Empty:
|
||||
case LinqExpressionType.NotEmpty:
|
||||
case LinqExpressionType.Null:
|
||||
case LinqExpressionType.NotNull:
|
||||
case LinqExpressionType.NullOrEmpty:
|
||||
case LinqExpressionType.NotNullOrEmpty:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// 核心:创建与目标类型兼容的null常量表达式
|
||||
private static ConstantExpression CreateNullConstant(Type targetType)
|
||||
{
|
||||
if (!targetType.IsValueType)
|
||||
{
|
||||
return Expression.Constant(null, targetType);
|
||||
}
|
||||
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||||
{
|
||||
// 可空类型的null常量需用默认值(底层类型为null)
|
||||
return Expression.Constant(null, targetType);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"非可空值类型 {targetType} 不支持null常量");
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据条件类型生成相应的查询表达式
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体类型</typeparam>
|
||||
/// <param name="propertyName">属性名称</param>
|
||||
/// <param name="conditionType">条件类型</param>
|
||||
/// <returns>生成的查询表达式</returns>
|
||||
public static Expression<Func<T, bool>> GenerateEmptyCondition<T>(
|
||||
string propertyName,
|
||||
LinqExpressionType conditionType)
|
||||
{
|
||||
// 获取属性信息并验证
|
||||
PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
|
||||
|
||||
Type propertyType = propertyInfo.PropertyType;
|
||||
|
||||
// 检查字符串专属条件是否应用在字符串属性上
|
||||
bool isStringCondition =
|
||||
conditionType == LinqExpressionType.Empty ||
|
||||
conditionType == LinqExpressionType.NotEmpty ||
|
||||
conditionType == LinqExpressionType.NotNullOrEmpty;
|
||||
|
||||
if (isStringCondition && propertyType != typeof(string))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"条件类型 {conditionType} 仅适用于字符串类型的属性,不能用于 {propertyType} 类型");
|
||||
}
|
||||
|
||||
// 创建参数表达式 (x => ... 中的 x)
|
||||
ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
|
||||
// 创建属性访问表达式 (x.PropertyName)
|
||||
MemberExpression property = Expression.Property(parameter, propertyInfo);
|
||||
|
||||
Expression conditionExpression;
|
||||
|
||||
switch (conditionType)
|
||||
{
|
||||
case LinqExpressionType.Empty:
|
||||
// x.PropertyName == "" (仅适用于字符串)
|
||||
conditionExpression = Expression.Equal(
|
||||
property,
|
||||
Expression.Constant("", typeof(string))
|
||||
);
|
||||
break;
|
||||
|
||||
case LinqExpressionType.Null:
|
||||
// x.PropertyName == null
|
||||
if (typeof(string) == propertyType)
|
||||
{
|
||||
conditionExpression = Expression.Equal(
|
||||
property,
|
||||
Expression.Constant(null, propertyType.IsValueType ? typeof(object) : propertyType)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
conditionExpression = Expression.Equal(property, CreateNullConstant(propertyType));
|
||||
}
|
||||
break;
|
||||
|
||||
case LinqExpressionType.NotEmpty:
|
||||
case LinqExpressionType.NotNullOrEmpty:
|
||||
// x.PropertyName != "" (仅适用于字符串)
|
||||
var notNull = Expression.NotEqual(property, Expression.Constant(null, typeof(string)));
|
||||
var notEmpty = Expression.NotEqual(property, Expression.Constant("", typeof(string)));
|
||||
conditionExpression = Expression.AndAlso(notNull, notEmpty);
|
||||
break;
|
||||
|
||||
case LinqExpressionType.NotNull:
|
||||
// x.PropertyName != null
|
||||
if (typeof(string) == propertyType)
|
||||
{
|
||||
conditionExpression = Expression.NotEqual(
|
||||
property,
|
||||
Expression.Constant(null, propertyType.IsValueType ? typeof(object) : propertyType)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
conditionExpression = Expression.NotEqual(property, CreateNullConstant(propertyType));
|
||||
}
|
||||
break;
|
||||
|
||||
case LinqExpressionType.NullOrEmpty:
|
||||
// !string.IsNullOrEmpty(x.PropertyName) (仅适用于字符串)
|
||||
var isNull = Expression.Equal(property, Expression.Constant(null, typeof(string)));
|
||||
var isEmpty = Expression.Equal(property, Expression.Constant("", typeof(string)));
|
||||
conditionExpression = Expression.OrElse(isNull, isEmpty);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(conditionType),
|
||||
"不支持的条件类型"
|
||||
);
|
||||
}
|
||||
|
||||
// 创建并返回lambda表达式
|
||||
return Expression.Lambda<Func<T, bool>>(conditionExpression, parameter);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="propertyName">字段名</param>
|
||||
/// <param name="propertyValue">表达式的值</param>
|
||||
/// <param name="expressionType">创建表达式的类型,如:p=>p.propertyName != propertyValue
|
||||
/// p=>p.propertyName.Contains(propertyValue)</param>
|
||||
/// <returns></returns>
|
||||
private static Expression<Func<T, bool>> CreateExpression<T>(
|
||||
this string propertyName,
|
||||
object propertyValue,
|
||||
ParameterExpression parameter,
|
||||
LinqExpressionType expressionType,
|
||||
bool checkNullProperty = false)
|
||||
{
|
||||
Type proType = typeof(T).GetProperty(propertyName).PropertyType;
|
||||
|
||||
//空或者null查询
|
||||
if (expressionType.CheckFilterNullExpression())
|
||||
{
|
||||
return GenerateEmptyCondition<T>(propertyName, expressionType);
|
||||
}
|
||||
if (checkNullProperty)
|
||||
{
|
||||
if (propertyValue == null)
|
||||
{
|
||||
return True<T>();
|
||||
}
|
||||
if (!(proType == typeof(string) || proType == typeof(int?) || proType == typeof(long?) || proType == typeof(decimal?) || proType == typeof(float?) || proType == typeof(bool?) || proType == typeof(DateTime?)))
|
||||
{
|
||||
checkNullProperty = false;
|
||||
}
|
||||
}
|
||||
|
||||
//创建节点变量如p=>的节点p
|
||||
// parameter ??= Expression.Parameter(typeof(T), "p");//创建参数p
|
||||
parameter = parameter ?? Expression.Parameter(typeof(T), "p");
|
||||
|
||||
Expression<Func<T, bool>> expression = null;
|
||||
|
||||
|
||||
|
||||
//创建节点的属性p=>p.name 属性name
|
||||
MemberExpression memberProperty = Expression.PropertyOrField(parameter, propertyName);
|
||||
if (expressionType == LinqExpressionType.In || expressionType == LinqExpressionType.NotIn)
|
||||
{
|
||||
if (!(propertyValue is System.Collections.IList list) || list.Count == 0) return x => false;
|
||||
|
||||
var res = typeof(LambdaExtensions).GetMethod("GetContainsExpression", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static)
|
||||
.MakeGenericMethod(new Type[] { typeof(T), proType })
|
||||
.Invoke(null, new object[] { propertyName, propertyValue, parameter, expressionType }) as Expression<Func<T, bool>>;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// object value = propertyValue;
|
||||
ConstantExpression constant = proType == typeof(string)
|
||||
? Expression.Constant(propertyValue) : Expression.Constant(propertyValue.ToString().ChangeType(proType));
|
||||
|
||||
// DateTime只选择了日期的时候自动在结束日期加一天,修复DateTime类型使用日期区间查询无法查询到结束日期的问题
|
||||
if ((proType == typeof(DateTime) || proType == typeof(DateTime?)) && expressionType == LinqExpressionType.LessThanOrEqual && propertyValue.ToString().Length == 10)
|
||||
{
|
||||
expressionType = LinqExpressionType.LessThan;
|
||||
constant = Expression.Constant(Convert.ToDateTime(propertyValue.ToString()).AddDays(1));
|
||||
}
|
||||
|
||||
if (checkNullProperty)
|
||||
{
|
||||
expression = CreateHasValueCondition<T>(proType, parameter, propertyName, propertyValue, constant, expressionType);
|
||||
if (expression != null)
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
UnaryExpression member = Expression.Convert(memberProperty, constant.Type);
|
||||
|
||||
switch (expressionType)
|
||||
{
|
||||
////p=>p.propertyName == propertyValue
|
||||
//case LinqExpressionType.Equal:
|
||||
// expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter);
|
||||
// break;
|
||||
//p=>p.propertyName != propertyValue
|
||||
case LinqExpressionType.NotEqual:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.NotEqual(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName > propertyValue
|
||||
case LinqExpressionType.GreaterThan:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThan(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName < propertyValue
|
||||
case LinqExpressionType.LessThan:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.LessThan(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName >= propertyValue
|
||||
case LinqExpressionType.ThanOrEqual:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName <= propertyValue
|
||||
case LinqExpressionType.LessThanOrEqual:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(member, constant), parameter);
|
||||
break;
|
||||
// p => p.propertyName.Contains(propertyValue)
|
||||
// p => !p.propertyName.Contains(propertyValue)
|
||||
case LinqExpressionType.Like:
|
||||
case LinqExpressionType.NotLike:
|
||||
case LinqExpressionType.Contains:
|
||||
case LinqExpressionType.NotContains:
|
||||
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
|
||||
constant = Expression.Constant(propertyValue, typeof(string));
|
||||
if (expressionType == LinqExpressionType.Like || expressionType == LinqExpressionType.Contains)
|
||||
{
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.Call(member, method, constant), parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.Not(Expression.Call(member, method, constant)), parameter);
|
||||
}
|
||||
break;
|
||||
case LinqExpressionType.LikeStart:
|
||||
case LinqExpressionType.LikeEnd:
|
||||
string m = expressionType == LinqExpressionType.LikeStart ? "StartsWith" : "EndsWith";
|
||||
var startsWithMethod = typeof(string).GetMethod(m, new[] { typeof(string) });
|
||||
var searchTermConstant = Expression.Constant(propertyValue, typeof(string));
|
||||
var startsWithCall = Expression.Call(member, startsWithMethod, searchTermConstant);
|
||||
expression = Expression.Lambda<Func<T, bool>>(startsWithCall, parameter);
|
||||
break;
|
||||
default:
|
||||
expression = Expression.Lambda<Func<T, bool>>(Expression.Equal(member, constant), parameter);
|
||||
break;
|
||||
// break;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private static Expression<Func<T, bool>> CreateHasValueCondition<T>(
|
||||
Type proType,
|
||||
ParameterExpression parameter,
|
||||
string propertyName,
|
||||
object propertyValue,
|
||||
ConstantExpression constant,
|
||||
LinqExpressionType expressionType
|
||||
)
|
||||
{
|
||||
BinaryExpression condition = null;
|
||||
var property = Expression.Property(parameter, propertyName);
|
||||
|
||||
if (proType == typeof(string))
|
||||
{
|
||||
Expression binaryExpression = null;
|
||||
switch (expressionType)
|
||||
{
|
||||
case LinqExpressionType.Like:
|
||||
case LinqExpressionType.Contains:
|
||||
binaryExpression = Expression.Call(property, "Contains", null, constant);
|
||||
break;
|
||||
case LinqExpressionType.LikeStart:
|
||||
binaryExpression = Expression.Call(property, "StartsWith", null, constant);
|
||||
break;
|
||||
case LinqExpressionType.LikeEnd:
|
||||
binaryExpression = Expression.Call(property, "EndsWith", null, constant);
|
||||
break;
|
||||
case LinqExpressionType.NotLike:
|
||||
case LinqExpressionType.NotContains:
|
||||
binaryExpression = Expression.Not(Expression.Call(property, "Contains", null, constant));
|
||||
break;
|
||||
case LinqExpressionType.NotEqual:
|
||||
binaryExpression = Expression.Not(Expression.Equal(property, constant));
|
||||
break;
|
||||
default:
|
||||
binaryExpression = Expression.Equal(property, constant);
|
||||
break;
|
||||
}
|
||||
var stringCondition = Expression.Condition(
|
||||
Expression.Equal(property, Expression.Constant(null)), // 如果 Charlie 为 null
|
||||
Expression.Constant(false), // 返回 false
|
||||
binaryExpression // 否则比较值
|
||||
);
|
||||
var stringExpression = Expression.Lambda<Func<T, bool>>(stringCondition, parameter);
|
||||
return stringExpression;
|
||||
}
|
||||
|
||||
|
||||
var hasValue = Expression.Property(property, "HasValue"); // 判断 字段 是否有值
|
||||
var value = Expression.Property(property, "Value"); // 获取 字段 的值
|
||||
switch (expressionType)
|
||||
{
|
||||
case LinqExpressionType.NotEqual:
|
||||
condition = Expression.NotEqual(value, constant);
|
||||
break;
|
||||
// p => p.propertyName > propertyValue
|
||||
case LinqExpressionType.GreaterThan:
|
||||
condition = Expression.GreaterThan(value, constant);
|
||||
break;
|
||||
// p => p.propertyName < propertyValue
|
||||
case LinqExpressionType.LessThan:
|
||||
condition = Expression.LessThan(value, constant);
|
||||
break;
|
||||
case LinqExpressionType.LessThanOrEqual:
|
||||
condition = Expression.LessThanOrEqual(value, constant);
|
||||
break;
|
||||
// p => p.propertyName >= propertyValue
|
||||
case LinqExpressionType.ThanOrEqual:
|
||||
condition = Expression.GreaterThanOrEqual(value, constant);
|
||||
break;
|
||||
case LinqExpressionType.Equal:
|
||||
condition = Expression.Equal(value, constant); // 构建条件:xx==
|
||||
break;
|
||||
}
|
||||
if (condition == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var body = Expression.Condition(hasValue, condition, Expression.Constant(false)); // 构建条件体
|
||||
var expression = Expression.Lambda<Func<T, bool>>(body, parameter);
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式转换成KeyValList(主要用于多字段排序,并且多个字段的排序规则不一样)
|
||||
/// 如有多个字段进行排序,参数格式为
|
||||
/// Expression<Func<Out_Scheduling, Dictionary<object, bool>>> orderBy = x => new Dictionary<object, bool>() {
|
||||
/// { x.ID, true },
|
||||
/// { x.DestWarehouseName, true }
|
||||
/// };
|
||||
/// 返回的是new Dictionary<object, bool>(){{}}key为排序字段,bool为升降序
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<KeyValuePair<string, QueryOrderBy>> GetExpressionToPair<T>(this Expression<Func<T, Dictionary<object, QueryOrderBy>>> expression)
|
||||
{
|
||||
|
||||
foreach (var exp in ((ListInitExpression)expression.Body).Initializers)
|
||||
{
|
||||
yield return new KeyValuePair<string, QueryOrderBy>(
|
||||
exp.Arguments[0] is MemberExpression ?
|
||||
(exp.Arguments[0] as MemberExpression).Member.Name.ToString()
|
||||
: ((exp.Arguments[0] as UnaryExpression).Operand as MemberExpression).Member.Name,
|
||||
(QueryOrderBy)(
|
||||
exp.Arguments[1] as ConstantExpression != null
|
||||
? (exp.Arguments[1] as ConstantExpression).Value
|
||||
//2021.07.04增加自定排序按条件表达式
|
||||
: Expression.Lambda<Func<QueryOrderBy>>(exp.Arguments[1] as Expression).Compile()()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式转换成KeyValList(主要用于多字段排序,并且多个字段的排序规则不一样)
|
||||
/// 如有多个字段进行排序,参数格式为
|
||||
/// Expression<Func<Out_Scheduling, Dictionary<object, QueryOrderBy>>> orderBy = x => new Dictionary<object, QueryOrderBy>() {
|
||||
/// { x.ID, QueryOrderBy.Desc },
|
||||
/// { x.DestWarehouseName, QueryOrderBy.Asc }
|
||||
/// };
|
||||
/// 返回的是new Dictionary<object, QueryOrderBy>(){{}}key为排序字段,QueryOrderBy为排序方式
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, QueryOrderBy> GetExpressionToDic<T>(this Expression<Func<T, Dictionary<object, QueryOrderBy>>> expression)
|
||||
{
|
||||
//2020.09.14增加排序字段null值判断
|
||||
if (expression == null)
|
||||
{
|
||||
return new Dictionary<string, QueryOrderBy>();
|
||||
}
|
||||
return expression.GetExpressionToPair().ToList().ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
/// <summary>
|
||||
/// 解析多字段排序
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="queryable"></param>
|
||||
/// <param name="orderBySelector">string=排序的字段,bool=true降序/false升序</param>
|
||||
/// <returns></returns>
|
||||
public static ISugarQueryable<TEntity> GetISugarQueryableOrderBy<TEntity>(this ISugarQueryable<TEntity> queryable, Dictionary<string, QueryOrderBy> orderBySelector)
|
||||
{
|
||||
string[] orderByKeys = orderBySelector.Select(x => x.Key).ToArray();
|
||||
if (orderByKeys == null || orderByKeys.Length == 0) return queryable;
|
||||
|
||||
ISugarQueryable<TEntity> queryableOrderBy = null;
|
||||
|
||||
|
||||
// string orderByKey = orderByKeys[^1];
|
||||
string orderByKey = orderByKeys[0];
|
||||
queryableOrderBy = orderBySelector[orderByKey] == QueryOrderBy.Desc
|
||||
? queryableOrderBy = queryable.OrderByDescending(orderByKey.GetExpression<TEntity>())
|
||||
: queryable.OrderBy(orderByKey.GetExpression<TEntity>());
|
||||
|
||||
for (int i = 1; i < orderByKeys.Length; i++)
|
||||
{
|
||||
queryableOrderBy = orderBySelector[orderByKeys[i]] == QueryOrderBy.Desc
|
||||
? queryableOrderBy.OrderByDescending(orderByKeys[i].GetExpression<TEntity>())
|
||||
: queryableOrderBy.OrderBy(orderByKeys[i].GetExpression<TEntity>());
|
||||
}
|
||||
return queryableOrderBy;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对象表达式指定属性的值
|
||||
/// 如获取:Out_Scheduling对象的ID或基他字段
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="expression">格式 Expression<Func<Out_Scheduling, object>>sch=x=>new {x.v1,x.v2} or x=>x.v1 解析里面的值返回为数组</param>
|
||||
/// <returns></returns>
|
||||
public static string[] GetExpressionToArray<TEntity>(this Expression<Func<TEntity, object>> expression)
|
||||
{
|
||||
string[] propertyNames = null;
|
||||
if (expression.Body is MemberExpression)
|
||||
{
|
||||
propertyNames = new string[] { ((MemberExpression)expression.Body).Member.Name };
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyNames = expression.GetExpressionProperty().Distinct().ToArray();
|
||||
}
|
||||
return propertyNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 与下面and生成方式有所不同,如果直接用表达式1.2进行合并产会提示数据源不同的异常,只能使用下面的的and合并
|
||||
/// 此种合并是在使用的同一个数据源(变量),生成的sql语句同样有性能问题(本身可以索引扫描的,生成的sql语句的case when变成索引查找)
|
||||
/// <summary>
|
||||
/// 通过字段动态生成where and /or表达
|
||||
/// 如:有多个where条件,当条件成立时where 1=1 and/or 2=2,依次往后拼接
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="listParas">ExpressionParameters
|
||||
/// 1、Field生成的字段
|
||||
/// 2、ExpressionType 表达式类型大于、小于、于大=、小于=、contains
|
||||
/// 3、Value表达式的值
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> And<T>(List<ExpressionParameters> listExpress)
|
||||
{
|
||||
return listExpress.Compose<T>(Expression.AndAlso);
|
||||
}
|
||||
/// <summary>
|
||||
/// 同上面and用法相同
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="listExpress"></param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> Or<T>(this List<ExpressionParameters> listExpress)
|
||||
{
|
||||
return listExpress.Compose<T>(Expression.OrElse);
|
||||
}
|
||||
private static Expression<Func<T, bool>> Compose<T>(this List<ExpressionParameters> listExpress, Func<Expression, Expression, Expression> merge)
|
||||
{
|
||||
ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
|
||||
Expression<Func<T, bool>> expression = null;
|
||||
foreach (ExpressionParameters exp in listExpress)
|
||||
{
|
||||
if (expression == null)
|
||||
{
|
||||
expression = exp.Field.GetExpression<T, bool>(parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
expression = expression.Compose(exp.Field.GetExpression<T, bool>(parameter), merge);
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
/// <summary>
|
||||
/// https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/
|
||||
/// 表达式合并(合并生产的sql语句有性能问题)
|
||||
/// 合并两个where条件,如:多个查询条件时,判断条件成立才where
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="first"></param>
|
||||
/// <param name="second"></param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
|
||||
{
|
||||
return first.Compose(second, Expression.AndAlso);
|
||||
}
|
||||
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
|
||||
{
|
||||
return first.Compose(second, Expression.OrElse);
|
||||
}
|
||||
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
|
||||
{
|
||||
// build parameter map (from parameters of second to parameters of first)
|
||||
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
|
||||
// replace parameters in the second lambda expression with parameters from the first
|
||||
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
|
||||
// apply composition of lambda expression bodies to parameters from the first expression
|
||||
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
|
||||
}
|
||||
|
||||
public static ISugarQueryable<Result> GetQueryableSelect<Source, Result>(this ISugarQueryable<Source> queryable)
|
||||
{
|
||||
Expression<Func<Source, Result>> expression = CreateMemberInitExpression<Source, Result>();
|
||||
return queryable.Select(expression);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态创建表达式Expression<Func<Animal, User>> expression = CreateMemberInitExpression<Animal, User>();
|
||||
///结果为Expression<Func<Animal, User>> expression1 = x => new User() { Age = x.Age, Species = x.Species };
|
||||
///参照文档https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.memberinitexpression?redirectedfrom=MSDN&view=netframework-4.8
|
||||
/// </summary>
|
||||
/// <typeparam name="Source"></typeparam>
|
||||
/// <typeparam name="Result"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<Source, Result>> CreateMemberInitExpression<Source, Result>(Type resultType = null)
|
||||
{
|
||||
resultType = resultType ?? typeof(Result);
|
||||
ParameterExpression left = Expression.Parameter(typeof(Source), "p");
|
||||
NewExpression newExpression = Expression.New(resultType);
|
||||
PropertyInfo[] propertyInfos = resultType.GetProperties();
|
||||
List<MemberBinding> memberBindings = new List<MemberBinding>();
|
||||
foreach (PropertyInfo propertyInfo in propertyInfos)
|
||||
{
|
||||
MemberExpression member = Expression.Property(left, propertyInfo.Name);
|
||||
MemberBinding speciesMemberBinding = Expression.Bind(resultType.GetMember(propertyInfo.Name)[0], member);
|
||||
memberBindings.Add(speciesMemberBinding);
|
||||
}
|
||||
MemberInitExpression memberInitExpression = Expression.MemberInit(newExpression, memberBindings);
|
||||
Expression<Func<Source, Result>> expression = Expression.Lambda<Func<Source, Result>>(memberInitExpression, new ParameterExpression[] { left });
|
||||
return expression;
|
||||
}
|
||||
public static Expression<Func<Source, object>> CreateMemberInitExpression<Source>(Type resultType)
|
||||
{
|
||||
return CreateMemberInitExpression<Source, object>(resultType);
|
||||
}
|
||||
/// <summary>
|
||||
/// 属性判断待完
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<PropertyInfo> GetGenericProperties(this Type type)
|
||||
{
|
||||
return type.GetProperties().GetGenericProperties();
|
||||
}
|
||||
/// <summary>
|
||||
/// 属性判断待完
|
||||
/// </summary>
|
||||
/// <param name="properties"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<PropertyInfo> GetGenericProperties(this IEnumerable<PropertyInfo> properties)
|
||||
{
|
||||
return properties.Where(x => !x.PropertyType.IsGenericType && x.PropertyType.GetInterface("IList") == null || x.PropertyType.GetInterface("IEnumerable", false) == null);
|
||||
}
|
||||
|
||||
public static string GetDbCondition(this string stringType)
|
||||
{
|
||||
string reslut = null;
|
||||
switch (stringType?.ToLower())
|
||||
{
|
||||
case HtmlElementType.droplist:
|
||||
case HtmlElementType.selectlist:
|
||||
case HtmlElementType.textarea:
|
||||
case HtmlElementType.checkbox:
|
||||
reslut = HtmlElementType.Contains;
|
||||
break;
|
||||
case HtmlElementType.thanorequal:
|
||||
reslut = HtmlElementType.ThanOrEqual;
|
||||
break;
|
||||
case HtmlElementType.lessorequal:
|
||||
reslut = HtmlElementType.LessOrequal;
|
||||
break;
|
||||
case HtmlElementType.gt:
|
||||
reslut = HtmlElementType.GT;
|
||||
break;
|
||||
case HtmlElementType.lt:
|
||||
reslut = HtmlElementType.lt;
|
||||
break;
|
||||
case HtmlElementType.like:
|
||||
reslut = HtmlElementType.like;
|
||||
break;
|
||||
case HtmlElementType.NotEqual:
|
||||
reslut = HtmlElementType.NotEqual;
|
||||
break;
|
||||
default:
|
||||
reslut = HtmlElementType.Equal;
|
||||
break;
|
||||
}
|
||||
return reslut;
|
||||
}
|
||||
}
|
||||
|
||||
public class ExpressionParameters
|
||||
{
|
||||
public string Field { get; set; }
|
||||
public LinqExpressionType ExpressionType { get; set; }
|
||||
public object Value { get; set; }
|
||||
// public
|
||||
}
|
||||
public class ParameterRebinder : ExpressionVisitor
|
||||
{
|
||||
|
||||
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
|
||||
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
|
||||
{
|
||||
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
|
||||
}
|
||||
|
||||
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
|
||||
{
|
||||
return new ParameterRebinder(map).Visit(exp);
|
||||
}
|
||||
protected override Expression VisitParameter(ParameterExpression p)
|
||||
{
|
||||
ParameterExpression replacement;
|
||||
if (map.TryGetValue(p, out replacement))
|
||||
{
|
||||
p = replacement;
|
||||
}
|
||||
return base.VisitParameter(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
//using VolPro.Core.Enums;
|
||||
//using VolPro.Entity.DomainModels.ResponseEntity;
|
||||
//using VolPro.Entity.SystemsModels;
|
||||
//using Microsoft.AspNetCore.Http;
|
||||
//using Newtonsoft.Json;
|
||||
//using System;
|
||||
//using System.IO;
|
||||
//using System.Net;
|
||||
//using System.Text;
|
||||
//using System.Threading.Tasks;
|
||||
//using System.Xml.Serialization;
|
||||
|
||||
//namespace VolPro.Core.Extensions.Middleware
|
||||
//{
|
||||
// public class ExceptionHandlerMiddleWare
|
||||
// {
|
||||
// private readonly RequestDelegate next;
|
||||
|
||||
// public ExceptionHandlerMiddleWare(RequestDelegate next)
|
||||
// {
|
||||
// this.next = next;
|
||||
// }
|
||||
|
||||
// public async Task Invoke(HttpContext context)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// await next(context);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// await HandleExceptionAsync(context, ex);
|
||||
// }
|
||||
// }
|
||||
|
||||
// private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
|
||||
// {
|
||||
// if (exception == null) return;
|
||||
// await WriteExceptionAsync(context, exception).ConfigureAwait(false);
|
||||
// }
|
||||
|
||||
// private static async Task WriteExceptionAsync(HttpContext context, Exception exception)
|
||||
// {
|
||||
|
||||
// Logger.WriteLog(LogEnum.Exception, null, exception.Message + exception.StackTrace, null);
|
||||
|
||||
// var response = context.Response;
|
||||
|
||||
// if (exception is UnauthorizedAccessException)
|
||||
// response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
// else if (exception is Exception)
|
||||
// // response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
// response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
// response.ContentType = context.Request.Headers["Accept"];
|
||||
|
||||
// //if (response.ContentType.ToLower() == "application/xml")
|
||||
// response.ContentType = "application/json";
|
||||
// ResponseData responseData = new ResponseData();
|
||||
// responseData.SetResponseValue(ResponseType.ServerError);
|
||||
// string reslutMsg = JsonConvert.SerializeObject(responseData);
|
||||
|
||||
// await response.WriteAsync(reslutMsg, Encoding.UTF8).ConfigureAwait(false);
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 对象转为Xml
|
||||
// /// </summary>
|
||||
// /// <param name="o"></param>
|
||||
// /// <returns></returns>
|
||||
// private static string Object2XmlString(object o)
|
||||
// {
|
||||
// StringWriter sw = new StringWriter();
|
||||
// try
|
||||
// {
|
||||
// XmlSerializer serializer = new XmlSerializer(o.GetType());
|
||||
// serializer.Serialize(sw, o);
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// //Handle Exception Code
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// sw.Dispose();
|
||||
// }
|
||||
// return sw.ToString();
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public class HttpContextMiddleware
|
||||
{
|
||||
/// <summary>
|
||||
/// 将流重新
|
||||
/// </summary>
|
||||
public static Func<RequestDelegate, RequestDelegate> contextMiddleware
|
||||
{
|
||||
get
|
||||
{
|
||||
return next => async context =>
|
||||
{
|
||||
|
||||
var stream = context.Request.Body;
|
||||
if (stream == Stream.Null || stream.CanSeek)
|
||||
{
|
||||
await next(context);
|
||||
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
//将流拷贝一份出来,调用结束后再将流写回去
|
||||
using (var buffer = new MemoryStream())
|
||||
{
|
||||
// Copy the request stream to the memory stream.
|
||||
await stream.CopyToAsync(buffer);
|
||||
|
||||
// Rewind the memory stream.
|
||||
buffer.Position = 0L;
|
||||
|
||||
// Replace the request stream by the memory stream.
|
||||
context.Request.Body = buffer;
|
||||
|
||||
// Invoke the rest of the pipeline.
|
||||
await next(context);
|
||||
}
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
// Restore the original stream.
|
||||
context.Request.Body = stream;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
809
api_sqlsugar/VolPro.Core/Extensions/ObjectExtension.cs
Normal file
809
api_sqlsugar/VolPro.Core/Extensions/ObjectExtension.cs
Normal file
@@ -0,0 +1,809 @@
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
|
||||
public static class ObjectExtension
|
||||
{
|
||||
|
||||
public static bool DicKeyIsNullOrEmpty(this Dictionary<string, object> dic, string key)
|
||||
{
|
||||
if (dic == null)
|
||||
return true;
|
||||
if (!dic.ContainsKey(key)) return true;
|
||||
object value = dic[key];
|
||||
if (value == null || value.ToString() == "")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static Dictionary<string, object> ReaderToDictionary(this IDataReader Reader)
|
||||
{
|
||||
List<Dictionary<string, object>> rowList = Reader.ReaderToDictionaryList();
|
||||
return rowList.Count() > 0 ? rowList[0] : null;
|
||||
}
|
||||
/// <summary>
|
||||
/// IDataReader转换成DictionaryList
|
||||
/// </summary>
|
||||
/// <param name="Reader"></param>
|
||||
/// <returns></returns>
|
||||
public static List<Dictionary<string, object>> ReaderToDictionaryList(this IDataReader Reader)
|
||||
{
|
||||
List<Dictionary<string, object>> rowList = new List<Dictionary<string, object>>();
|
||||
try
|
||||
{
|
||||
while (Reader.Read())
|
||||
{
|
||||
Dictionary<string, object> row = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
for (var fieldCount = 0; fieldCount < Reader.FieldCount; fieldCount++)
|
||||
{
|
||||
row.Add(Reader.GetName(fieldCount), Reader[fieldCount]);
|
||||
}
|
||||
rowList.Add(row);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) { throw new Exception(ex.Message); }
|
||||
finally
|
||||
{
|
||||
Reader.Close();
|
||||
Reader.Dispose();
|
||||
}
|
||||
return rowList;
|
||||
}
|
||||
|
||||
public static T DicToEntity<T>(this Dictionary<string, object> dic)
|
||||
{
|
||||
return new List<Dictionary<string, object>>() { dic }.DicToList<T>().ToList()[0];
|
||||
}
|
||||
public static List<T> DicToList<T>(this List<Dictionary<string, object>> dicList)
|
||||
{
|
||||
return dicList.DicToIEnumerable<T>().ToList();
|
||||
}
|
||||
public static object DicToList(this List<Dictionary<string, object>> dicList, Type type)
|
||||
{
|
||||
return typeof(ObjectExtension).GetMethod("DicToList")
|
||||
.MakeGenericMethod(new Type[] { type })
|
||||
.Invoke(typeof(ObjectExtension), new object[] { dicList });
|
||||
}
|
||||
|
||||
public static IEnumerable<T> DicToIEnumerable<T>(this List<Dictionary<string, object>> dicList)
|
||||
{
|
||||
foreach (Dictionary<string, object> dic in dicList)
|
||||
{
|
||||
T model = Activator.CreateInstance<T>();
|
||||
foreach (PropertyInfo property in model.GetType()
|
||||
.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
if (!dic.TryGetValue(property.Name, out object value)) continue;
|
||||
property.SetValue(model, value?.ToString().ChangeType(property.PropertyType), null);
|
||||
}
|
||||
yield return model;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// IDataReader转换成List
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="Reader"></param>
|
||||
/// <returns></returns>
|
||||
public static List<T> ReaderToList<T>(this IDataReader Reader)
|
||||
{
|
||||
List<string> objectField = new List<string>(Reader.FieldCount);
|
||||
for (int i = 0; i < Reader.FieldCount; i++)
|
||||
{
|
||||
objectField.Add(Reader.GetName(i).ToLower());
|
||||
}
|
||||
List<T> objectList = new List<T>();
|
||||
try
|
||||
{
|
||||
while (Reader.Read())
|
||||
{
|
||||
T model = Activator.CreateInstance<T>();
|
||||
foreach (PropertyInfo property in model.GetType()
|
||||
.GetProperties(BindingFlags.GetProperty
|
||||
| BindingFlags.Public
|
||||
| BindingFlags.Instance))
|
||||
{
|
||||
if (!objectField.Contains(property.Name.ToLower())) { continue; }
|
||||
if (Reader[property.Name].IsNullOrEmpty()) { continue; }
|
||||
property.SetValue(model, Reader[property.Name].ToString().ChangeType(property.PropertyType), null);
|
||||
}
|
||||
objectList.Add(model);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception(ex.Message, ex.InnerException);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Reader.Close();
|
||||
Reader.Dispose();
|
||||
}
|
||||
return objectList;
|
||||
}
|
||||
|
||||
|
||||
public static object ChangeType(this object value, Type type)
|
||||
{
|
||||
if (null == value) return null;
|
||||
try
|
||||
{
|
||||
if (type == typeof(Guid) || type == typeof(Guid?))
|
||||
{
|
||||
string val = value.ToString();
|
||||
if (val == "") return null;
|
||||
return Guid.Parse(val);
|
||||
}
|
||||
if (type == typeof(bool) || type == typeof(bool?))
|
||||
{
|
||||
string val = value.ToString();
|
||||
return val == "1" || val == "True";
|
||||
}
|
||||
if (!type.IsGenericType) return Convert.ChangeType(value, type);
|
||||
Type genericTypeDefinition = type.GetGenericTypeDefinition();
|
||||
if (genericTypeDefinition == typeof(Nullable<>))
|
||||
{
|
||||
return Convert.ChangeType(value, Nullable.GetUnderlyingType(type));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 将集合转换为数据集。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">转换的元素类型。</typeparam>
|
||||
/// <param name="list">集合。</param>
|
||||
/// <param name="generic">是否生成泛型数据集。</param>
|
||||
/// <returns>数据集。</returns>
|
||||
public static DataSet ToDataSet<T>(this IEnumerable<T> list, bool generic = true)
|
||||
{
|
||||
return ListToDataSet(list, generic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将集合转换为数据集。
|
||||
/// </summary>
|
||||
/// <param name="list">集合。</param>
|
||||
/// <param name="generic">是否生成泛型数据集。</param>
|
||||
/// <returns>数据集。</returns>
|
||||
public static DataSet ToDataSet(this IEnumerable list, bool generic = true)
|
||||
{
|
||||
return ListToDataSet(list, generic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将集合转换为数据集。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">转换的元素类型。</typeparam>
|
||||
/// <param name="list">集合。</param>
|
||||
/// <param name="generic">是否生成泛型数据集。</param>
|
||||
/// <returns>数据集。</returns>
|
||||
public static DataSet ToDataSet<T>(this IEnumerable list, bool generic = true)
|
||||
{
|
||||
return ListToDataSet(list, typeof(T), generic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将实例转换为集合数据集。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实例类型。</typeparam>
|
||||
/// <param name="o">实例。</param>
|
||||
/// <param name="generic">是否生成泛型数据集。</param>
|
||||
/// <returns>数据集。</returns>
|
||||
public static DataSet ToListSet<T>(this T o, bool generic = true)
|
||||
{
|
||||
if (o is IEnumerable)
|
||||
{
|
||||
return ListToDataSet(o as IEnumerable, generic);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ListToDataSet(new T[] { o }, generic);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将可序列化实例转换为XmlDocument。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实例类型。</typeparam>
|
||||
/// <param name="o">实例。</param>
|
||||
/// <returns>XmlDocument。</returns>
|
||||
public static XmlDocument ToXmlDocument<T>(this T o)
|
||||
{
|
||||
XmlDocument xmlDocument = new XmlDocument
|
||||
{
|
||||
InnerXml = o.ToListSet().GetXml()
|
||||
};
|
||||
return xmlDocument;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将集合转换为数据集。
|
||||
/// </summary>
|
||||
/// <param name="list">集合。</param>
|
||||
/// <param name="t">转换的元素类型。</param>
|
||||
/// <param name="generic">是否生成泛型数据集。</param>
|
||||
/// <returns>转换后的数据集。</returns>
|
||||
private static DataSet ListToDataSet(IEnumerable list, Type t, bool generic)
|
||||
{
|
||||
DataSet ds = new DataSet("Data");
|
||||
if (t == null)
|
||||
{
|
||||
if (list != null)
|
||||
{
|
||||
foreach (var i in list)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
t = i.GetType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t == null)
|
||||
{
|
||||
return ds;
|
||||
}
|
||||
}
|
||||
ds.Tables.Add(t.Name);
|
||||
//如果集合中元素为DataSet扩展涉及到的基本类型时,进行特殊转换。
|
||||
if (t.IsValueType || t == typeof(string))
|
||||
{
|
||||
ds.Tables[0].TableName = "Info";
|
||||
ds.Tables[0].Columns.Add(t.Name);
|
||||
if (list != null)
|
||||
{
|
||||
foreach (var i in list)
|
||||
{
|
||||
DataRow addRow = ds.Tables[0].NewRow();
|
||||
addRow[t.Name] = i;
|
||||
ds.Tables[0].Rows.Add(addRow);
|
||||
}
|
||||
}
|
||||
return ds;
|
||||
}
|
||||
//处理模型的字段和属性。
|
||||
var fields = t.GetFields();
|
||||
var properties = t.GetProperties();
|
||||
foreach (var j in fields)
|
||||
{
|
||||
if (!ds.Tables[0].Columns.Contains(j.Name))
|
||||
{
|
||||
if (generic)
|
||||
{
|
||||
ds.Tables[0].Columns.Add(j.Name, j.FieldType);
|
||||
}
|
||||
else
|
||||
{
|
||||
ds.Tables[0].Columns.Add(j.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var j in properties)
|
||||
{
|
||||
if (!ds.Tables[0].Columns.Contains(j.Name))
|
||||
{
|
||||
if (generic)
|
||||
{
|
||||
ds.Tables[0].Columns.Add(j.Name, j.PropertyType);
|
||||
}
|
||||
else
|
||||
{
|
||||
ds.Tables[0].Columns.Add(j.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list == null)
|
||||
{
|
||||
return ds;
|
||||
}
|
||||
//读取list中元素的值。
|
||||
foreach (var i in list)
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DataRow addRow = ds.Tables[0].NewRow();
|
||||
foreach (var j in fields)
|
||||
{
|
||||
MemberExpression field = Expression.Field(Expression.Constant(i), j.Name);
|
||||
LambdaExpression lambda = Expression.Lambda(field, new ParameterExpression[] { });
|
||||
Delegate func = lambda.Compile();
|
||||
object value = func.DynamicInvoke();
|
||||
addRow[j.Name] = value;
|
||||
}
|
||||
foreach (var j in properties)
|
||||
{
|
||||
MemberExpression property = Expression.Property(Expression.Constant(i), j);
|
||||
LambdaExpression lambda = Expression.Lambda(property, new ParameterExpression[] { });
|
||||
Delegate func = lambda.Compile();
|
||||
object value = func.DynamicInvoke();
|
||||
addRow[j.Name] = value;
|
||||
}
|
||||
ds.Tables[0].Rows.Add(addRow);
|
||||
}
|
||||
return ds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将集合转换为数据集。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">转换的元素类型。</typeparam>
|
||||
/// <param name="list">集合。</param>
|
||||
/// <param name="generic">是否生成泛型数据集。</param>
|
||||
/// <returns>数据集。</returns>
|
||||
private static DataSet ListToDataSet<T>(IEnumerable<T> list, bool generic)
|
||||
{
|
||||
return ListToDataSet(list, typeof(T), generic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将集合转换为数据集。
|
||||
/// </summary>
|
||||
/// <param name="list">集合。</param>
|
||||
/// <param name="generic">是否转换为字符串形式。</param>
|
||||
/// <returns>转换后的数据集。</returns>
|
||||
private static DataSet ListToDataSet(IEnumerable list, bool generic)
|
||||
{
|
||||
return ListToDataSet(list, null, generic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取DataSet第一表,第一行,第一列的值。
|
||||
/// </summary>
|
||||
/// <param name="ds">DataSet数据集。</param>
|
||||
/// <returns>值。</returns>
|
||||
public static object GetData(this DataSet ds)
|
||||
{
|
||||
if (
|
||||
ds == null
|
||||
|| ds.Tables.Count == 0
|
||||
)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ds.Tables[0].GetData();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取DataTable第一行,第一列的值。
|
||||
/// </summary>
|
||||
/// <param name="dt">DataTable数据集表。</param>
|
||||
/// <returns>值。</returns>
|
||||
public static object GetData(this DataTable dt)
|
||||
{
|
||||
if (
|
||||
dt.Columns.Count == 0
|
||||
|| dt.Rows.Count == 0
|
||||
)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return dt.Rows[0][0];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取DataSet第一个匹配columnName的值。
|
||||
/// </summary>
|
||||
/// <param name="ds">数据集。</param>
|
||||
/// <param name="columnName">列名。</param>
|
||||
/// <returns>值。</returns>
|
||||
public static object GetData(this DataSet ds, string columnName)
|
||||
{
|
||||
if (
|
||||
ds == null
|
||||
|| ds.Tables.Count == 0
|
||||
)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
foreach (DataTable dt in ds.Tables)
|
||||
{
|
||||
object o = dt.GetData(columnName);
|
||||
if (!string.IsNullOrEmpty(o.ToString()))
|
||||
{
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取DataTable第一个匹配columnName的值。
|
||||
/// </summary>
|
||||
/// <param name="dt">数据表。</param>
|
||||
/// <param name="columnName">列名。</param>
|
||||
/// <returns>值。</returns>
|
||||
public static object GetData(this DataTable dt, string columnName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(columnName))
|
||||
{
|
||||
return GetData(dt);
|
||||
}
|
||||
if (
|
||||
dt.Columns.Count == 0
|
||||
|| dt.Columns.IndexOf(columnName) == -1
|
||||
|| dt.Rows.Count == 0
|
||||
)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return dt.Rows[0][columnName];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将object转换为string类型信息。
|
||||
/// </summary>
|
||||
/// <param name="o">object。</param>
|
||||
/// <param name="t">默认值。</param>
|
||||
/// <returns>string。</returns>
|
||||
//public static string ToString(this object o, string t)
|
||||
//{
|
||||
// string info = string.Empty;
|
||||
// if (o == null)
|
||||
// {
|
||||
// info = t;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// info = o.ToString(t);
|
||||
// }
|
||||
// return info;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 将DateTime?转换为string类型信息。
|
||||
/// </summary>
|
||||
/// <param name="o">DateTime?。</param>
|
||||
/// <param name="format">标准或自定义日期和时间格式的字符串。</param>
|
||||
/// <param name="t">默认值。</param>
|
||||
/// <returns>string。</returns>
|
||||
public static string ToString(this DateTime? date, string format)
|
||||
{
|
||||
return date.Value.ToString(format);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static Regex BoolRegex = new Regex("(?<info>(true|false))", RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
/// <summary>
|
||||
/// 从object中获取bool类型信息。
|
||||
/// </summary>
|
||||
/// <param name="o">object。</param>
|
||||
/// <returns>bool。</returns>
|
||||
public static bool GetBool(this string value)
|
||||
{
|
||||
bool.TryParse(value, out bool result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Regex IntRegex = new Regex("(?<info>-?\\d+)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
|
||||
|
||||
private static Regex DecimalRegex = new Regex("(?<info>-?\\d+(\\.\\d+)?)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 读取XElement节点的文本内容。
|
||||
/// </summary>
|
||||
/// <param name="xElement">XElement节点。</param>
|
||||
/// <param name="t">默认值。</param>
|
||||
/// <returns>文本内容。</returns>
|
||||
public static string Value(this XElement xElement, string t = default(string))
|
||||
{
|
||||
if (xElement == null)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
else
|
||||
{
|
||||
return xElement.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取与指定键相关的值。
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">键类型。</typeparam>
|
||||
/// <typeparam name="TValue">值类型。</typeparam>
|
||||
/// <param name="dictionary">表示键/值对象的泛型集合。</param>
|
||||
/// <param name="key">键。</param>
|
||||
/// <param name="t">默认值。</param>
|
||||
/// <returns>值。</returns>
|
||||
public static TValue GetValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue t = default(TValue))
|
||||
{
|
||||
TValue value = default(TValue);
|
||||
if (dictionary == null || key == null)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
if (!dictionary.TryGetValue(key, out value))
|
||||
{
|
||||
value = t;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取与指定键相关或者第一个的值。
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">键类型。</typeparam>
|
||||
/// <typeparam name="TValue">值类型。</typeparam>
|
||||
/// <param name="dictionary">表示键/值对象的泛型集合。</param>
|
||||
/// <param name="key">键。</param>
|
||||
/// <param name="t">默认值。</param>
|
||||
/// <returns>值。</returns>
|
||||
public static TValue GetFirstOrDefaultValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue t = default(TValue))
|
||||
{
|
||||
TValue value = default(TValue);
|
||||
if (dictionary == null || key == null)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
if (!dictionary.TryGetValue(key, out value))
|
||||
{
|
||||
if (dictionary.Count() == 0)
|
||||
{
|
||||
value = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = dictionary.FirstOrDefault().Value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取具有指定 System.Xml.Linq.XName 的第一个(按文档顺序)子元素。
|
||||
/// </summary>
|
||||
/// <param name="xContainer">XContainer。</param>
|
||||
/// <param name="xName">要匹配的 System.Xml.Linq.XName。</param>
|
||||
/// <param name="t">是否返回同名默认值。</param>
|
||||
/// <returns>与指定 System.Xml.Linq.XName 匹配的 System.Xml.Linq.XElement,或者为 null。</returns>
|
||||
public static XElement Element(this XContainer xContainer, XName xName, bool t)
|
||||
{
|
||||
XElement info;
|
||||
if (xContainer == null)
|
||||
{
|
||||
info = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
info = xContainer.Element(xName);
|
||||
}
|
||||
if (t && info == null)
|
||||
{
|
||||
info = new XElement(xName);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按文档顺序返回此元素或文档的子元素集合。
|
||||
/// </summary>
|
||||
/// <param name="xContainer">XContainer。</param>
|
||||
/// <param name="t">是否返回非空默认值。</param>
|
||||
/// <returns>System.Xml.Linq.XElement 的按文档顺序包含此System.Xml.Linq.XContainer 的子元素,或者非空默认值。</returns>
|
||||
public static IEnumerable<XElement> Elements(this XContainer xContainer, bool t)
|
||||
{
|
||||
IEnumerable<XElement> info;
|
||||
if (xContainer == null)
|
||||
{
|
||||
info = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
info = xContainer.Elements();
|
||||
}
|
||||
if (t && info == null)
|
||||
{
|
||||
info = new List<XElement>();
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按文档顺序返回此元素或文档的经过筛选的子元素集合。集合中只包括具有匹配 System.Xml.Linq.XName 的元素。
|
||||
/// </summary>
|
||||
/// <param name="xContainer">XContainer。</param>
|
||||
/// <param name="xName">要匹配的 System.Xml.Linq.XName。</param>
|
||||
/// <param name="t">是否返回非空默认值。</param>
|
||||
/// <returns>System.Xml.Linq.XElement 的按文档顺序包含具有匹配System.Xml.Linq.XName 的 System.Xml.Linq.XContainer 的子级,或者非空默认值。</returns>
|
||||
public static IEnumerable<XElement> Elements(this XContainer xContainer, XName xName, bool t)
|
||||
{
|
||||
IEnumerable<XElement> info;
|
||||
if (xContainer == null)
|
||||
{
|
||||
info = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
info = xContainer.Elements(xName);
|
||||
}
|
||||
if (t && info == null)
|
||||
{
|
||||
info = new List<XElement>();
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public static Guid? GetGuid(this object value)
|
||||
{
|
||||
if (Guid.TryParse(value?.ToString(), out Guid guid))
|
||||
{
|
||||
return guid;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string ToString(this decimal? value,string format)
|
||||
{
|
||||
return value?.ToString(format);
|
||||
}
|
||||
|
||||
public static string ToString(this int? value, string format)
|
||||
{
|
||||
return value?.ToString(format);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取默认非空字符串。
|
||||
/// </summary>
|
||||
/// <param name="s">首选默认非空字符串。</param>
|
||||
/// <param name="args">依次非空字符串可选项。</param>
|
||||
/// <returns>默认非空字符串。若无可选项则返回string.Empty。</returns>
|
||||
public static string DefaultStringIfEmpty(this string s, params string[] args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
foreach (string i in args)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(i) && !string.IsNullOrEmpty(i.Trim()))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return (s ?? string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对 URL 字符串进行编码。
|
||||
/// </summary>
|
||||
/// <param name="s">要编码的文本。</param>
|
||||
/// <param name="regex">匹配要编码的文本。</param>
|
||||
/// <param name="encoding">指定编码方案的 System.Text.Encoding 对象。</param>
|
||||
/// <returns>一个已编码的字符串。</returns>
|
||||
public static string ToUrlEncodeString(this string s, Regex regex = default(Regex), Encoding encoding = null)
|
||||
{
|
||||
if (encoding == null)
|
||||
{
|
||||
encoding = Encoding.UTF8;
|
||||
}
|
||||
if (regex == null)
|
||||
{
|
||||
return HttpUtility.UrlEncode(s, encoding);
|
||||
}
|
||||
List<string> l = new List<string>();
|
||||
foreach (char i in s)
|
||||
{
|
||||
string t = i.ToString();
|
||||
l.Add(regex.IsMatch(t) ? HttpUtility.UrlEncode(t, encoding) : t);
|
||||
}
|
||||
return string.Join(string.Empty, l);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对 URL 字符串进行编码。
|
||||
/// </summary>
|
||||
/// <param name="s">要编码的文本。</param>
|
||||
/// <param name="regex">匹配要编码的文本。</param>
|
||||
/// <param name="encoding">指定编码方案的 System.Text.Encoding 对象。</param>
|
||||
/// <returns>一个已编码的字符串。</returns>
|
||||
public static string ToUrlEncodeString(this string s, string regex, Encoding encoding = null)
|
||||
{
|
||||
return ToUrlEncodeString(s, new Regex(regex), encoding);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将日期转换为UNIX时间戳字符串
|
||||
/// </summary>
|
||||
/// <param name="date"></param>
|
||||
/// <returns></returns>
|
||||
public static string ToUnixTimeStamp(this DateTime date)
|
||||
{
|
||||
DateTime startTime = TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970, 1, 1));
|
||||
string timeStamp = date.Subtract(startTime).Ticks.ToString();
|
||||
return timeStamp.Substring(0, timeStamp.Length - 7);
|
||||
}
|
||||
|
||||
private static readonly Regex MobileRegex = new Regex("^1[3-9][0-9]\\d{4,8}$");
|
||||
private static readonly Regex EmailRegex = new Regex("^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\\.[a-zA-Z0-9_-]{2,3}){1,2})$");
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前字符串是否是移动电话号码
|
||||
/// </summary>
|
||||
/// <param name="mobile"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsMobile(this string mobile)
|
||||
{
|
||||
return MobileRegex.IsMatch(mobile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前字符串是否为邮箱
|
||||
/// </summary>
|
||||
/// <param name="email"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsEmail(this string email)
|
||||
{
|
||||
return EmailRegex.IsMatch(email);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 标记。
|
||||
/// </summary>
|
||||
public enum Flag
|
||||
{
|
||||
/// <summary>
|
||||
/// 默认。
|
||||
/// </summary>
|
||||
Default,
|
||||
|
||||
/// <summary>
|
||||
/// 真。
|
||||
/// </summary>
|
||||
True,
|
||||
|
||||
/// <summary>
|
||||
/// 假。
|
||||
/// </summary>
|
||||
False
|
||||
}
|
||||
}
|
||||
149
api_sqlsugar/VolPro.Core/Extensions/RequestExtension.cs
Normal file
149
api_sqlsugar/VolPro.Core/Extensions/RequestExtension.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using VolPro.Core.Enums;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class HttpContextExtension
|
||||
{
|
||||
|
||||
public static T GetService<T>(this HttpContext context) where T : class
|
||||
{
|
||||
return context.RequestServices.GetService(typeof(T)) as T;
|
||||
}
|
||||
public static string GetUserIp(this HttpContext context)
|
||||
{
|
||||
string realIP = null;
|
||||
string forwarded = null;
|
||||
string remoteIpAddress = context.Connection.RemoteIpAddress.ToString();
|
||||
if (context.Request.Headers.ContainsKey("X-Real-IP"))
|
||||
{
|
||||
realIP = context.Request.Headers["X-Real-IP"].ToString();
|
||||
if (realIP != remoteIpAddress)
|
||||
{
|
||||
remoteIpAddress = realIP;
|
||||
}
|
||||
}
|
||||
if (context.Request.Headers.ContainsKey("X-Forwarded-For"))
|
||||
{
|
||||
forwarded = context.Request.Headers["X-Forwarded-For"].ToString();
|
||||
if (forwarded != remoteIpAddress)
|
||||
{
|
||||
remoteIpAddress = forwarded;
|
||||
}
|
||||
}
|
||||
return remoteIpAddress;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取Request值
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="parameter"></param>
|
||||
/// <returns></returns>
|
||||
public static string Request(this HttpContext context, string parameter)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (context == null)
|
||||
return null;
|
||||
if (context.Request.Method == "POST")
|
||||
return context.Request.Form[parameter].ToString();
|
||||
else
|
||||
return context.Request.Query[parameter].ToString();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Console.Write(ex.Message + ex.InnerException);
|
||||
return context.RequestString(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
public static T Request<T>(this HttpContext context, string parameter) where T : class
|
||||
{
|
||||
return context.RequestString(parameter)?.DeserializeObject<T>();
|
||||
}
|
||||
public static string RequestString(this HttpContext context, string parameter)
|
||||
{
|
||||
string requestParam = context.GetRequestParameters();
|
||||
if (string.IsNullOrEmpty(requestParam)) return null;
|
||||
Dictionary<string, object> keyValues = requestParam.DeserializeObject<Dictionary<string, object>>();
|
||||
if (keyValues == null || keyValues.Count == 0) return null;
|
||||
if (keyValues.TryGetValue(parameter, out object value))
|
||||
{
|
||||
if (value == null) return null;
|
||||
if (value.GetType() == typeof(string))
|
||||
{
|
||||
return value?.ToString();
|
||||
}
|
||||
return value.Serialize();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否为ajax请求
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsAjaxRequest(this HttpContext context)
|
||||
{
|
||||
return context.Request("X-Requested-With") == "XMLHttpRequest"
|
||||
|| (context.Request.Headers != null
|
||||
&& context.Request.Headers["X-Requested-With"] == "XMLHttpRequest");
|
||||
}
|
||||
|
||||
public static UserAgent GetAgentType(this HttpContext context)
|
||||
{
|
||||
string agent = context.Request.Headers["User-Agent"].ToString().ToLower();
|
||||
|
||||
if (agent.Contains("ios") || agent.Contains("ipod") || agent.Contains("ipad"))
|
||||
{
|
||||
return UserAgent.IOS;
|
||||
}
|
||||
if (agent.Contains("windows"))
|
||||
{
|
||||
return UserAgent.Windows;
|
||||
}
|
||||
return UserAgent.Android;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取请求的参数
|
||||
/// net core 2.0已增加回读方法 context.Request.EnableRewind();
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public static string GetRequestParameters(this HttpContext context)
|
||||
{
|
||||
string prarameters = null;
|
||||
if (context.Request.Query != null && context.Request.Query.Keys.Count > 0)
|
||||
{
|
||||
prarameters = context.Request.Query.Serialize();
|
||||
}
|
||||
|
||||
//context.Request.EnableBuffering();
|
||||
context.Request.Body.Seek(0, SeekOrigin.Begin);
|
||||
if (context.Request.Body == null
|
||||
|| !context.Request.Body.CanRead
|
||||
|| !context.Request.Body.CanSeek
|
||||
|| context.Request.Body.Length == 0 || context.Request.Body.Length>10000)
|
||||
return prarameters;
|
||||
if (context.Request.ContentType.Contains("application/json"))
|
||||
{
|
||||
if (context.Request.Body.Position > 0)
|
||||
context.Request.Body.Position = 0;
|
||||
using (StreamReader reader = new StreamReader(context.Request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true))
|
||||
{
|
||||
prarameters += reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
return prarameters;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Utilities;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class ApiResponseExtension
|
||||
{
|
||||
|
||||
//public static ApiResponseData ApiResponseOK(this ApiResponseData responseData, string msg=null)
|
||||
//{
|
||||
// return responseData.ApiSetResponse(ResponseType.OperSuccess, msg, ApiStatutsCode.Ok);
|
||||
//}
|
||||
|
||||
//public static ApiResponseData ApiSetResponse(this ApiResponseData responseData, ResponseType responseType, ApiStatutsCode? status = null)
|
||||
//{
|
||||
// return responseData.ApiSetResponse(responseType, null, status);
|
||||
//}
|
||||
///// <summary>
|
||||
/////
|
||||
///// </summary>
|
||||
///// <param name="responseData"></param>
|
||||
///// <param name="responseType">返回消息类型</param>
|
||||
///// <param name="msg">返回消息,若msg为null,则取responseType的描述信息</param>
|
||||
///// <param name="status">返回状态,目前只有0、失败,1、成功,2、token过期</param>
|
||||
//public static ApiResponseData ApiSetResponse(this ApiResponseData responseData, ResponseType responseType, string msg,ApiStatutsCode? status=null)
|
||||
//{
|
||||
// if (status != null)
|
||||
// {
|
||||
// responseData.Status = (int)status;
|
||||
// }
|
||||
// if (!string.IsNullOrEmpty(msg))
|
||||
// {
|
||||
// responseData.Message = msg;
|
||||
// return responseData;
|
||||
// }
|
||||
// if (!string.IsNullOrEmpty(responseData.Message))
|
||||
// return responseData;
|
||||
// responseData.Message = responseType.GetMsg();
|
||||
// return responseData;
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//using VolPro.Core.Enums;
|
||||
//using VolPro.Entity.DomainModels;
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Text;
|
||||
//using VolPro.Core.Utilities;
|
||||
|
||||
//namespace VolPro.Core.Extensions
|
||||
//{
|
||||
// public static class ResponseExtension
|
||||
// {
|
||||
|
||||
// public static WebResponseContent Set(this WebResponseContent responseData, ResponseType responseType)
|
||||
// {
|
||||
// bool? b = null;
|
||||
// return Set(responseData, responseType, b);
|
||||
// }
|
||||
// public static WebResponseContent Set(this WebResponseContent responseData, ResponseType responseType, bool? status)
|
||||
// {
|
||||
// return Set(responseData, responseType, null, status);
|
||||
// }
|
||||
// public static WebResponseContent Set(this WebResponseContent responseData, ResponseType responseType, string msg)
|
||||
// {
|
||||
// bool? b = null;
|
||||
// return Set(responseData, responseType, msg, b);
|
||||
// }
|
||||
// public static WebResponseContent Set(this WebResponseContent responseData, ResponseType responseType, string msg, bool? status)
|
||||
// {
|
||||
// if (status != null)
|
||||
// {
|
||||
// responseData.Status = (bool)status;
|
||||
// }
|
||||
// responseData.Code = ((int)responseType).ToString();
|
||||
// if (!string.IsNullOrEmpty(msg))
|
||||
// {
|
||||
// responseData.Desc = msg;
|
||||
// return responseData;
|
||||
// }
|
||||
// responseData.Desc = responseType.GetMsg();
|
||||
// return responseData;
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
59
api_sqlsugar/VolPro.Core/Extensions/Response/ResponseMsg.cs
Normal file
59
api_sqlsugar/VolPro.Core/Extensions/Response/ResponseMsg.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using VolPro.Core.Enums;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class ResponseMsg
|
||||
{
|
||||
public static string GetMsg(this ResponseType responseType)
|
||||
{
|
||||
string msg;
|
||||
switch (responseType)
|
||||
{
|
||||
case ResponseType.LoginExpiration:
|
||||
msg = "登陆已过期,请重新登陆"; break;
|
||||
case ResponseType.TokenExpiration:
|
||||
msg = "Token已过期,请重新登陆"; break;
|
||||
case ResponseType.AccountLocked:
|
||||
msg = "帐号已被锁定"; break;
|
||||
case ResponseType.LoginSuccess:
|
||||
msg = "登陆成功"; break;
|
||||
case ResponseType.ParametersLack:
|
||||
msg = "参数不完整"; break;
|
||||
case ResponseType.NoPermissions:
|
||||
msg = "没有权限操作"; break;
|
||||
case ResponseType.NoRolePermissions:
|
||||
msg = "角色没有权限操作"; break;
|
||||
case ResponseType.ServerError:
|
||||
msg = "服务器好像出了点问题....."; break;
|
||||
case ResponseType.LoginError:
|
||||
msg = "用户名或密码错误"; break;
|
||||
case ResponseType.SaveSuccess:
|
||||
msg = "保存成功"; break;
|
||||
case ResponseType.NoKey:
|
||||
msg = "没有主键不能编辑"; break;
|
||||
case ResponseType.NoKeyDel:
|
||||
msg = "没有主键不能删除"; break;
|
||||
case ResponseType.KeyError:
|
||||
msg = "主键不正确或没有传入主键"; break;
|
||||
case ResponseType.EidtSuccess:
|
||||
msg = "编辑成功"; break;
|
||||
case ResponseType.DelSuccess:
|
||||
msg = "删除成功"; break;
|
||||
case ResponseType.RegisterSuccess:
|
||||
msg = "注册成功"; break;
|
||||
case ResponseType.AuditSuccess:
|
||||
msg = "审核成功"; break;
|
||||
case ResponseType.ModifyPwdSuccess:
|
||||
msg = "密码修改成功"; break;
|
||||
case ResponseType.OperSuccess:
|
||||
msg = "操作成功"; break;
|
||||
case ResponseType.PINError:
|
||||
msg = "验证码不正确"; break;
|
||||
|
||||
default: msg = responseType.ToString(); break;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class SecurityEncDecryptExtensions
|
||||
{
|
||||
|
||||
private static byte[] Keys = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
|
||||
/// <summary>
|
||||
/// DES加密字符串
|
||||
/// </summary>
|
||||
/// <param name="encryptString">待加密的字符串</param>
|
||||
/// <param name="encryptKey">加密密钥,要求为16位</param>
|
||||
/// <returns>加密成功返回加密后的字符串,失败返回源串</returns>
|
||||
|
||||
public static string EncryptDES(this string encryptString, string encryptKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] rgbKey = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 16));
|
||||
byte[] rgbIV = Keys;
|
||||
byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
|
||||
|
||||
using (var DCSP = Aes.Create())
|
||||
{
|
||||
using (MemoryStream mStream = new MemoryStream())
|
||||
{
|
||||
using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
|
||||
{
|
||||
cStream.Write(inputByteArray, 0, inputByteArray.Length);
|
||||
cStream.FlushFinalBlock();
|
||||
return Convert.ToBase64String(mStream.ToArray()).Replace('+', '_').Replace('/', '~');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("密码加密异常" + ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DES解密字符串
|
||||
/// </summary>
|
||||
/// <param name="decryptString">待解密的字符串</param>
|
||||
/// <param name="decryptKey">解密密钥,要求为16位,和加密密钥相同</param>
|
||||
/// <returns>解密成功返回解密后的字符串,失败返源串</returns>
|
||||
|
||||
public static string DecryptDES(this string decryptString, string decryptKey)
|
||||
{
|
||||
byte[] rgbKey = Encoding.UTF8.GetBytes(decryptKey.Substring(0, 16));
|
||||
byte[] rgbIV = Keys;
|
||||
byte[] inputByteArray = Convert.FromBase64String(decryptString.Replace('_', '+').Replace('~', '/'));
|
||||
using (var DCSP = Aes.Create())
|
||||
{
|
||||
using (MemoryStream mStream = new MemoryStream())
|
||||
{
|
||||
using (CryptoStream cStream = new CryptoStream(mStream, DCSP.CreateDecryptor(rgbKey, rgbIV), CryptoStreamMode.Write))
|
||||
{
|
||||
byte[] inputByteArrays = new byte[inputByteArray.Length];
|
||||
cStream.Write(inputByteArray, 0, inputByteArray.Length);
|
||||
cStream.FlushFinalBlock();
|
||||
return Encoding.UTF8.GetString(mStream.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public static bool TryDecryptDES(this string decryptString, string decryptKey, out string result)
|
||||
{
|
||||
result = "";
|
||||
try
|
||||
{
|
||||
result = DecryptDES(decryptString, decryptKey);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
api_sqlsugar/VolPro.Core/Extensions/ServerExtension.cs
Normal file
31
api_sqlsugar/VolPro.Core/Extensions/ServerExtension.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using VolPro.Core.BaseProvider.ServerMapPath;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using VolPro.Core.Extensions.AutofacManager;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class ServerExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回的路径后面不带/,拼接时需要自己加上/
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string MapPath(this string path)
|
||||
{
|
||||
return MapPath(path, false);
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="rootPath">获取wwwroot路径</param>
|
||||
/// <returns></returns>
|
||||
public static string MapPath(this string path,bool rootPath)
|
||||
{
|
||||
return AutofacContainerModule.GetService<IPathProvider>().MapPath(path,rootPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using VolPro.Core.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using VolPro.Core.Utilities;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class ServiceProviderManagerExtension
|
||||
{
|
||||
private static IServiceProvider _serviceProvider;
|
||||
|
||||
public static void UseCache(this IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
public static object GetService(this Type serviceType, bool scope = false)
|
||||
{
|
||||
if (HttpContext.Current == null || scope)
|
||||
{
|
||||
using (IServiceScope serviceScope = _serviceProvider.CreateScope())
|
||||
{
|
||||
return serviceScope.ServiceProvider.GetService(serviceType);
|
||||
}
|
||||
}
|
||||
return HttpContext.Current.RequestServices.GetRequiredService(serviceType);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
50
api_sqlsugar/VolPro.Core/Extensions/StaticFileExtensions.cs
Normal file
50
api_sqlsugar/VolPro.Core/Extensions/StaticFileExtensions.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class StaticDefaultFileExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseStaticDefaultFile(this IApplicationBuilder app, string path)
|
||||
{
|
||||
app.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
|
||||
FileProvider = new PhysicalFileProvider(
|
||||
Path.Combine(path, "Content")),
|
||||
RequestPath = new PathString("/Content")
|
||||
//,
|
||||
//OnPrepareResponse = x => {
|
||||
// x.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");
|
||||
//}
|
||||
})
|
||||
.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
|
||||
FileProvider = new PhysicalFileProvider(
|
||||
Path.Combine(path, "fonts")),
|
||||
RequestPath = new PathString("/fonts")
|
||||
})
|
||||
.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
|
||||
FileProvider = new PhysicalFileProvider(
|
||||
Path.Combine(path, "Scripts")),
|
||||
RequestPath = new PathString("/Scripts")
|
||||
})
|
||||
.UseStaticFiles(new StaticFileOptions()
|
||||
{
|
||||
|
||||
FileProvider = new PhysicalFileProvider(
|
||||
Path.Combine(path, "Html")),
|
||||
RequestPath = new PathString("/Html")
|
||||
});
|
||||
return app;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class StaticHttpContextExtensions
|
||||
{
|
||||
//public static void AddHttpContextAccessor(this IServiceCollection services)
|
||||
//{
|
||||
// services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
//}
|
||||
|
||||
public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
|
||||
{
|
||||
var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
|
||||
Utilities.HttpContext.Configure(httpContextAccessor);
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
594
api_sqlsugar/VolPro.Core/Extensions/StringExtension.cs
Normal file
594
api_sqlsugar/VolPro.Core/Extensions/StringExtension.cs
Normal file
@@ -0,0 +1,594 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using VolPro.Core.Const;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.ManageUser;
|
||||
|
||||
namespace VolPro.Core.Extensions
|
||||
{
|
||||
public static class StringExtension
|
||||
{
|
||||
public static bool _windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
public static string ReplacePath(this string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return "";
|
||||
if (_windows)
|
||||
return path.Replace("/", "\\");
|
||||
return path.Replace("\\", "/");
|
||||
|
||||
}
|
||||
private static DateTime dateStart = new DateTime(1970, 1, 1, 8, 0, 0);
|
||||
|
||||
private static long longTime = 621355968000000000;
|
||||
|
||||
private static int samllTime = 10000000;
|
||||
/// <summary>
|
||||
/// 获取时间戳
|
||||
/// </summary>
|
||||
/// <param name="dateTime"></param>
|
||||
/// <returns></returns>
|
||||
public static long GetTimeStamp(this DateTime dateTime)
|
||||
{
|
||||
return (dateTime.ToUniversalTime().Ticks - longTime) / samllTime;
|
||||
}
|
||||
/// <summary>
|
||||
/// 时间戳转换成日期
|
||||
/// </summary>
|
||||
/// <param name="timeStamp"></param>
|
||||
/// <returns></returns>
|
||||
public static DateTime GetTimeSpmpToDate(this object timeStamp)
|
||||
{
|
||||
if (timeStamp == null) return dateStart;
|
||||
DateTime dateTime = new DateTime(longTime + Convert.ToInt64(timeStamp) * samllTime, DateTimeKind.Utc).ToLocalTime();
|
||||
return dateTime;
|
||||
}
|
||||
public static string CreateHtmlParas(this string urlPath, int? userId = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(urlPath))
|
||||
return null;
|
||||
userId = userId ?? UserContext.Current.UserInfo.User_Id;
|
||||
return $"{urlPath}{(urlPath.IndexOf("?token") > 0 ? "&" : "?")}uid={userId}&rt_v={DateTime.Now.ToString("HHmmss")}";
|
||||
// return urlPath + ((urlPath.IndexOf("?token") > 0 ? "&" : "?") + "uid=" + userId);
|
||||
}
|
||||
|
||||
public static bool IsUrl(this string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return false;
|
||||
string Url = @"^(?i)(?:http://|https://)([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
|
||||
return Regex.IsMatch(str, Url);
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 判断是不是正确的手机号码
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsPhoneNo(this string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return false;
|
||||
if (input.Length != 11)
|
||||
return false;
|
||||
|
||||
if (new Regex(@"^1[3578][01379]\d{8}$").IsMatch(input)
|
||||
|| new Regex(@"^1[34578][01256]\d{8}").IsMatch(input)
|
||||
|| new Regex(@"^(1[012345678]\d{8}|1[345678][0123456789]\d{8})$").IsMatch(input)
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string GetDBCondition(this string stringType)
|
||||
{
|
||||
string reslut = "";
|
||||
switch (stringType?.ToLower())
|
||||
{
|
||||
case HtmlElementType.droplist:
|
||||
case HtmlElementType.selectlist:
|
||||
case HtmlElementType.textarea:
|
||||
case HtmlElementType.checkbox:
|
||||
reslut = HtmlElementType.Contains;
|
||||
break;
|
||||
case HtmlElementType.thanorequal:
|
||||
reslut = HtmlElementType.ThanOrEqual;
|
||||
break;
|
||||
case HtmlElementType.lessorequal:
|
||||
reslut = HtmlElementType.LessOrequal;
|
||||
break;
|
||||
case HtmlElementType.gt:
|
||||
reslut = HtmlElementType.GT;
|
||||
break;
|
||||
case HtmlElementType.lt:
|
||||
reslut = HtmlElementType.lt;
|
||||
break;
|
||||
case HtmlElementType.like:
|
||||
reslut = HtmlElementType.like;
|
||||
break;
|
||||
default:
|
||||
reslut = HtmlElementType.Equal;
|
||||
break;
|
||||
}
|
||||
return reslut;
|
||||
}
|
||||
|
||||
public static LinqExpressionType GetLinqCondition(this string stringType)
|
||||
{
|
||||
LinqExpressionType linqExpression;
|
||||
switch (stringType)
|
||||
{
|
||||
case "!=":
|
||||
linqExpression = LinqExpressionType.NotEqual;
|
||||
break;
|
||||
case "like"://模糊查询
|
||||
linqExpression = LinqExpressionType.Like;
|
||||
break;
|
||||
case "likeStart"://like 'xx%'
|
||||
linqExpression = LinqExpressionType.LikeStart;
|
||||
break;
|
||||
case "likeEnd"://like '%xx'
|
||||
linqExpression = LinqExpressionType.LikeEnd;
|
||||
break;
|
||||
case "selectList": //多选
|
||||
case "checkbox": //多选
|
||||
case "droplist":
|
||||
linqExpression = LinqExpressionType.In;
|
||||
break;
|
||||
case "notIn": //多选不包括
|
||||
case "notin": //多选不包括
|
||||
case "in":
|
||||
linqExpression = LinqExpressionType.NotIn;
|
||||
break;
|
||||
case "thanorequal": //>=
|
||||
case ">=":
|
||||
linqExpression = LinqExpressionType.ThanOrEqual;
|
||||
break;
|
||||
case "lessorequal": //<=
|
||||
case "<=":
|
||||
linqExpression = LinqExpressionType.LessThanOrEqual;
|
||||
break;
|
||||
case "gt": //>=
|
||||
case ">":
|
||||
linqExpression = LinqExpressionType.GreaterThan;
|
||||
break;
|
||||
case "lt": //<=
|
||||
case "<":
|
||||
linqExpression = LinqExpressionType.LessThan;
|
||||
break;
|
||||
default:
|
||||
linqExpression = LinqExpressionType.Equal;
|
||||
break;
|
||||
}
|
||||
return linqExpression;
|
||||
}
|
||||
|
||||
public static bool GetGuid(this string guid, out Guid outId)
|
||||
{
|
||||
Guid emptyId = Guid.Empty;
|
||||
return Guid.TryParse(guid, out outId);
|
||||
}
|
||||
|
||||
public static bool IsGuid(this string guid)
|
||||
{
|
||||
Guid newId;
|
||||
return guid.GetGuid(out newId);
|
||||
}
|
||||
|
||||
public static bool IsInt(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
bool reslut = Int32.TryParse(obj.ToString(), out int _number);
|
||||
return reslut;
|
||||
|
||||
}
|
||||
public static bool IsDate(this object str)
|
||||
{
|
||||
return str.IsDate(out _);
|
||||
}
|
||||
public static bool IsDate(this object str, out DateTime dateTime)
|
||||
{
|
||||
dateTime = DateTime.Now;
|
||||
if (str == null || str.ToString() == "")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return DateTime.TryParse(str.ToString(), out dateTime);
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据传入格式判断是否为小数
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <param name="formatString">18,5</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsNumber(this string str, string formatString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str)) return false;
|
||||
|
||||
return Regex.IsMatch(str, @"^[+-]?\d*[.]?\d*$");
|
||||
//int precision = 32;
|
||||
//int scale = 5;
|
||||
//try
|
||||
//{
|
||||
// if (string.IsNullOrEmpty(formatString))
|
||||
// {
|
||||
// precision = 10;
|
||||
// scale = 2;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// string[] numbers = formatString.Split(',');
|
||||
// precision = Convert.ToInt32(numbers[0]);
|
||||
// scale = numbers.Length == 0 ? 2 : Convert.ToInt32(numbers[1]);
|
||||
// }
|
||||
//}
|
||||
//catch { };
|
||||
//return IsNumber(str, precision, scale);
|
||||
}
|
||||
/**/
|
||||
/// <summary>
|
||||
/// 判断一个字符串是否为合法数字(指定整数位数和小数位数)
|
||||
/// </summary>
|
||||
/// <param name="str">字符串</param>
|
||||
/// <param name="precision">整数位数</param>
|
||||
/// <param name="scale">小数位数</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsNumber(this string str, int precision, int scale)
|
||||
{
|
||||
if ((precision == 0) && (scale == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string pattern = @"(^\d{1," + precision + "}";
|
||||
if (scale > 0)
|
||||
{
|
||||
pattern += @"\.\d{0," + scale + "}$)|" + pattern;
|
||||
}
|
||||
pattern += "$)";
|
||||
return Regex.IsMatch(str, pattern);
|
||||
}
|
||||
|
||||
|
||||
public static bool IsNullOrEmpty(this object str)
|
||||
{
|
||||
if (str == null)
|
||||
return true;
|
||||
return str.ToString() == "";
|
||||
}
|
||||
|
||||
|
||||
public static int GetInt(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return 0;
|
||||
int.TryParse(obj.ToString(), out int _number);
|
||||
return _number;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 object 中的枚举值
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks></remarks>
|
||||
public static long GetLong(this string obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return 0;
|
||||
|
||||
if (long.TryParse(obj, out long value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 object 中的 float
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public static float GetFloat(this object obj)
|
||||
{
|
||||
if (System.DBNull.Value.Equals(obj) || null == obj)
|
||||
return 0;
|
||||
|
||||
try
|
||||
{
|
||||
return float.Parse(obj.ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static double GetDouble(this object obj)
|
||||
{
|
||||
if (System.DBNull.Value.Equals(obj) || null == obj)
|
||||
return 0;
|
||||
|
||||
try
|
||||
{
|
||||
return Convert.ToDouble(obj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取 object 中的 decimal
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks></remarks>
|
||||
public static decimal GetDecimal(this object obj)
|
||||
{
|
||||
if (System.DBNull.Value.Equals(obj) || null == obj)
|
||||
return 0;
|
||||
|
||||
try
|
||||
{
|
||||
return Convert.ToDecimal(obj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取 object 中的 decimal
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks></remarks>
|
||||
public static dynamic GetDynamic(this object obj)
|
||||
{
|
||||
if (System.DBNull.Value.Equals(obj) || null == obj)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
string str = obj.ToString();
|
||||
if (str.IsNumber(25, 15)) return Convert.ToDecimal(obj);
|
||||
else return str;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static DateTime? GetDateTime(this object obj)
|
||||
{
|
||||
if (System.DBNull.Value.Equals(obj) || null == obj)
|
||||
return null;
|
||||
bool result = DateTime.TryParse(obj.ToString(), out DateTime dateTime);
|
||||
if (!result)
|
||||
return null;
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static object ParseTo(this string str, string type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case "System.Boolean":
|
||||
return ToBoolean(str);
|
||||
case "System.SByte":
|
||||
return ToSByte(str);
|
||||
case "System.Byte":
|
||||
return ToByte(str);
|
||||
case "System.UInt16":
|
||||
return ToUInt16(str);
|
||||
case "System.Int16":
|
||||
return ToInt16(str);
|
||||
case "System.uInt32":
|
||||
return ToUInt32(str);
|
||||
case "System.Int32":
|
||||
return str.ToInt32();
|
||||
case "System.UInt64":
|
||||
return ToUInt64(str);
|
||||
case "System.Int64":
|
||||
return ToInt64(str);
|
||||
case "System.Single":
|
||||
return ToSingle(str);
|
||||
case "System.Double":
|
||||
return ToDouble(str);
|
||||
case "System.Decimal":
|
||||
return ToDecimal(str);
|
||||
case "System.DateTime":
|
||||
return ToDateTime(str);
|
||||
case "System.Guid":
|
||||
return ToGuid(str);
|
||||
}
|
||||
throw new NotSupportedException(string.Format("The string of \"{0}\" can not be parsed to {1}", str, type));
|
||||
}
|
||||
|
||||
public static sbyte? ToSByte(this string value)
|
||||
{
|
||||
sbyte value2;
|
||||
if (sbyte.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte? ToByte(this string value)
|
||||
{
|
||||
byte value2;
|
||||
if (byte.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ushort? ToUInt16(this string value)
|
||||
{
|
||||
ushort value2;
|
||||
if (ushort.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static short? ToInt16(this string value)
|
||||
{
|
||||
if (short.TryParse(value, out short value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static uint? ToUInt32(this string value)
|
||||
{
|
||||
uint value2;
|
||||
if (uint.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ulong? ToUInt64(this string value)
|
||||
{
|
||||
ulong value2;
|
||||
if (ulong.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static long? ToInt64(this string value)
|
||||
{
|
||||
long value2;
|
||||
if (long.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static float? ToSingle(this string value)
|
||||
{
|
||||
float value2;
|
||||
if (float.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static double? ToDouble(this string value)
|
||||
{
|
||||
double value2;
|
||||
if (double.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static decimal? ToDecimal(this string value)
|
||||
{
|
||||
decimal value2;
|
||||
if (decimal.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool? ToBoolean(this string value)
|
||||
{
|
||||
bool value2;
|
||||
if (bool.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Guid? ToGuid(this string str)
|
||||
{
|
||||
Guid value;
|
||||
if (Guid.TryParse(str, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static DateTime? ToDateTime(this string value)
|
||||
{
|
||||
DateTime value2;
|
||||
if (DateTime.TryParse(value, out value2))
|
||||
{
|
||||
return value2;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int? ToInt32(this string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int value;
|
||||
if (int.TryParse(input, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 替换空格字符
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="replacement">替换为该字符</param>
|
||||
/// <returns>替换后的字符串</returns>
|
||||
public static string ReplaceWhitespace(this string input, string replacement = "")
|
||||
{
|
||||
return string.IsNullOrEmpty(input) ? null : Regex.Replace(input, "\\s", replacement, RegexOptions.Compiled);
|
||||
}
|
||||
|
||||
private static char[] randomConstant ={
|
||||
'0','1','2','3','4','5','6','7','8','9',
|
||||
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
|
||||
};
|
||||
/// <summary>
|
||||
/// 生成指定长度的随机数
|
||||
/// </summary>
|
||||
/// <param name="length"></param>
|
||||
/// <returns></returns>
|
||||
public static string GenerateRandomNumber(this int length)
|
||||
{
|
||||
System.Text.StringBuilder newRandom = new System.Text.StringBuilder(62);
|
||||
Random rd = new Random();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
newRandom.Append(randomConstant[rd.Next(62)]);
|
||||
}
|
||||
return newRandom.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
26
api_sqlsugar/VolPro.Core/Filters/ActionExecuteFilter.cs
Normal file
26
api_sqlsugar/VolPro.Core/Filters/ActionExecuteFilter.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.ObjectActionValidator;
|
||||
using VolPro.Core.Services;
|
||||
using VolPro.Core.Utilities;
|
||||
|
||||
namespace VolPro.Core.Filters
|
||||
{
|
||||
public class ActionExecuteFilter : IActionFilter
|
||||
{
|
||||
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
//验证方法参数
|
||||
context.ActionParamsValidator();
|
||||
}
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
111
api_sqlsugar/VolPro.Core/Filters/ActionPermissionAttribute.cs
Normal file
111
api_sqlsugar/VolPro.Core/Filters/ActionPermissionAttribute.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
|
||||
namespace VolPro.Core.Filters
|
||||
{
|
||||
public class ActionPermissionAttribute : TypeFilterAttribute
|
||||
{
|
||||
public ActionPermissionAttribute(bool isApi = false)
|
||||
: base(typeof(ActionPermissionFilter))
|
||||
{
|
||||
Arguments = new object[] { new ActionPermissionRequirement() { IsApi = isApi } };
|
||||
}
|
||||
/// <summary>
|
||||
/// 限定角色访问
|
||||
/// </summary>
|
||||
/// <param name="roles"></param>
|
||||
public ActionPermissionAttribute(int roleId, bool isApi = false)
|
||||
: base(typeof(ActionPermissionFilter))
|
||||
{
|
||||
Arguments = new object[] { new ActionPermissionRequirement() { RoleIds = new int[] { roleId }, IsApi = isApi } };
|
||||
}
|
||||
public ActionPermissionAttribute(ActionRolePermission actionRolePermission, bool isApi = false)
|
||||
: base(typeof(ActionPermissionFilter))
|
||||
{
|
||||
Array array = Enum.GetValues(typeof(ActionRolePermission));
|
||||
List<int> roles = new List<int>();
|
||||
foreach (ActionRolePermission item in array)
|
||||
{
|
||||
if (actionRolePermission.HasFlag(item))
|
||||
{
|
||||
roles.Add((int)item);
|
||||
}
|
||||
}
|
||||
Arguments = new object[] { new ActionPermissionRequirement() { RoleIds = roles.ToArray(), IsApi = isApi } };
|
||||
}
|
||||
/// <summary>
|
||||
/// 限定角色访问
|
||||
/// </summary>
|
||||
/// <param name="roles"></param>
|
||||
public ActionPermissionAttribute(int[] roleIds, bool isApi = false)
|
||||
: base(typeof(ActionPermissionFilter))
|
||||
{
|
||||
Arguments = new object[] { new ActionPermissionRequirement() { RoleIds = roleIds, IsApi = isApi } };
|
||||
}
|
||||
|
||||
public ActionPermissionAttribute(string tableName, ActionPermissionOptions tableAction, bool sysController = false, bool isApi = false)
|
||||
: base(typeof(ActionPermissionFilter))
|
||||
{
|
||||
this.SetActionPermissionRequirement(tableName, tableAction, sysController, isApi);
|
||||
}
|
||||
|
||||
public ActionPermissionAttribute(string tableName, string roleIds, ActionPermissionOptions tableAction, bool sysController = false, bool isApi = false)
|
||||
: base(typeof(ActionPermissionFilter))
|
||||
{
|
||||
this.SetActionPermissionRequirement(tableName, tableAction, (roleIds ?? "").Split(",").Select(x => x.GetInt()).ToArray(), sysController, isApi);
|
||||
}
|
||||
|
||||
public ActionPermissionAttribute(ActionPermissionOptions tableAction, bool isApi = false)
|
||||
: base(typeof(ActionPermissionFilter))
|
||||
{
|
||||
this.SetActionPermissionRequirement("", tableAction, true, isApi);
|
||||
}
|
||||
/// <summary>
|
||||
/// 解析组合枚举值为权限数组
|
||||
/// </summary>
|
||||
private string[] ParseActionPermissionOptions(ActionPermissionOptions tableAction)
|
||||
{
|
||||
List<string> actions = new List<string>();
|
||||
Array enumValues = Enum.GetValues(typeof(ActionPermissionOptions));
|
||||
|
||||
foreach (ActionPermissionOptions item in enumValues)
|
||||
{
|
||||
// 跳过值为0的项(如果存在)
|
||||
int itemValue = (int)item;
|
||||
if (itemValue == 0) continue;
|
||||
|
||||
// 使用 HasFlag 检查是否包含该权限
|
||||
// 对于位标志枚举,HasFlag 会检查是否设置了该位
|
||||
if (tableAction.HasFlag(item))
|
||||
{
|
||||
actions.Add(item.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
return actions.ToArray();
|
||||
}
|
||||
|
||||
private void SetActionPermissionRequirement(string tableName, ActionPermissionOptions tableAction,
|
||||
int[] roleId, bool sysController = false, bool isApi = false)
|
||||
{
|
||||
string[] tableActions = ParseActionPermissionOptions(tableAction);
|
||||
|
||||
Arguments = new object[] { new ActionPermissionRequirement() {
|
||||
SysController=sysController,
|
||||
TableActions=tableActions, // 存储权限数组
|
||||
TableName=tableName,
|
||||
IsApi = isApi,
|
||||
RoleIds=roleId
|
||||
} };
|
||||
}
|
||||
|
||||
private void SetActionPermissionRequirement(string tableName, ActionPermissionOptions tableAction, bool sysController = false, bool isApi = false, int? roleId = null)
|
||||
{
|
||||
SetActionPermissionRequirement(tableName, tableAction, roleId == null ? null : new int[] { (int)roleId }, sysController, isApi);
|
||||
}
|
||||
}
|
||||
}
|
||||
165
api_sqlsugar/VolPro.Core/Filters/ActionPermissionFilter.cs
Normal file
165
api_sqlsugar/VolPro.Core/Filters/ActionPermissionFilter.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Enums;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.Generic;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Core.Services;
|
||||
using VolPro.Core.UserManager;
|
||||
using VolPro.Core.Utilities;
|
||||
using VolPro.Entity.AttributeManager;
|
||||
|
||||
namespace VolPro.Core.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// 1、控制器或controller设置了AllowAnonymousAttribute直接返回
|
||||
/// 2、TableName、TableActions 同时为null或空,SysController为false的,只判断是否登陆
|
||||
/// 3、TableName、TableActions 都不null根据表名与action判断是否有权限
|
||||
/// 4、SysController为true,通过httpcontext获取表名与action判断是否有权限
|
||||
/// 5、Roles对指定角色验证
|
||||
/// </summary>
|
||||
public class ActionPermissionFilter : IAsyncActionFilter
|
||||
{
|
||||
private WebResponseContent ResponseContent { get; set; }
|
||||
private ActionPermissionRequirement ActionPermission;
|
||||
private UserContext _userContext { get; set; }
|
||||
// private ResponseType responseType;
|
||||
public ActionPermissionFilter(ActionPermissionRequirement actionPermissionRequirement, UserContext userContext)
|
||||
{
|
||||
this.ResponseContent = new WebResponseContent();
|
||||
this.ActionPermission = actionPermissionRequirement;
|
||||
_userContext = userContext;
|
||||
}
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
if (OnActionExecutionPermission(context).Status)
|
||||
{
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
FilterResponse.SetActionResult(context, ResponseContent);
|
||||
}
|
||||
private WebResponseContent OnActionExecutionPermission(ActionExecutingContext context)
|
||||
{
|
||||
//!context.Filters.Any(item => item is IFixedTokenFilter))固定token的是否验证权限
|
||||
//if ((context.Filters.Any(item => item is IAllowAnonymousFilter)
|
||||
// && !context.Filters.Any(item => item is IFixedTokenFilter))
|
||||
// || UserContext.Current.IsSuperAdmin
|
||||
// )
|
||||
if (context.Filters.Any(item => item is IAllowAnonymousFilter)
|
||||
|| UserContext.Current.IsSuperAdmin)
|
||||
return ResponseContent.OK();
|
||||
|
||||
//演示环境除了admin帐号,其他帐号都不能增删改等操作
|
||||
if (!_userContext.IsSuperAdmin && AppSetting.GlobalFilter.Enable
|
||||
&& AppSetting.GlobalFilter.Actions.Any(x => x.ToLower() == ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor).ActionName.ToLower()))
|
||||
{
|
||||
return ResponseContent.Error(AppSetting.GlobalFilter.Message);
|
||||
}
|
||||
|
||||
//如果没有指定表的权限,则默认为代码生成的控制器,优先获取PermissionTableAttribute指定的表,如果没有数据则使用当前控制器的名作为表名权限
|
||||
if (ActionPermission.SysController)
|
||||
{
|
||||
object[] permissionArray = ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor)?.ControllerTypeInfo.GetCustomAttributes(typeof(PermissionTableAttribute), false);
|
||||
if (permissionArray == null || permissionArray.Length == 0)
|
||||
{
|
||||
ActionPermission.TableName = ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor).ControllerName;
|
||||
}
|
||||
else
|
||||
{
|
||||
ActionPermission.TableName = (permissionArray[0] as PermissionTableAttribute).Name;
|
||||
}
|
||||
if (string.IsNullOrEmpty(ActionPermission.TableName))
|
||||
{
|
||||
//responseType = ResponseType.ParametersLack;
|
||||
return ResponseContent.Error(ResponseType.ParametersLack);
|
||||
}
|
||||
}
|
||||
string tableName = ActionPermission.TableName?.ToLower();
|
||||
if (tableName == "generic")
|
||||
{
|
||||
tableName = GenericTableAsyncLocal.CurrentTableName?.ToLower();
|
||||
}
|
||||
|
||||
//如果没有给定权限,不需要判断
|
||||
if (string.IsNullOrEmpty(tableName)
|
||||
&& (ActionPermission.TableActions == null || ActionPermission.TableActions.Length == 0)
|
||||
&& (ActionPermission.RoleIds == null || ActionPermission.RoleIds.Length == 0))
|
||||
{
|
||||
return ResponseContent.OK();
|
||||
}
|
||||
|
||||
//是否限制的角色ID称才能访问
|
||||
//权限判断角色ID,
|
||||
if (ActionPermission.RoleIds != null && ActionPermission.RoleIds.Length > 0)
|
||||
{
|
||||
if (ActionPermission.RoleIds.Contains(_userContext.UserInfo.Role_Id)) return ResponseContent.OK();
|
||||
//如果角色ID没有权限。并且也没控制器权限
|
||||
if (ActionPermission.TableActions == null || ActionPermission.TableActions.Length == 0)
|
||||
{
|
||||
return ResponseContent.Error(ResponseType.NoRolePermissions);
|
||||
}
|
||||
}
|
||||
//2020.05.05移除x.TableName.ToLower()转换,获取权限时已经转换成为小写
|
||||
// 使用 TableActions 数组进行权限判断
|
||||
string[] actionsToCheck = ActionPermission.TableActions ?? [];
|
||||
|
||||
bool actionAuth = false;
|
||||
if (actionsToCheck.Length > 0)
|
||||
{
|
||||
//var permissions = _userContext.GetPermissions(x => x.TableName == ActionPermission.TableName.ToLower());
|
||||
//if (permissions?.UserAuthArr != null)
|
||||
//{
|
||||
// // 检查用户权限数组中是否包含任意一个需要的权限
|
||||
// actionAuth = actionsToCheck.Any(action => permissions.UserAuthArr.Contains(action));
|
||||
//}
|
||||
actionAuth = CheckPermission(actionsToCheck, tableName);
|
||||
}
|
||||
|
||||
if (!actionAuth)
|
||||
{
|
||||
if (UserContext.MenuType == 1 && actionsToCheck.Length > 0)
|
||||
{
|
||||
actionAuth = _userContext.Permissions.Where(x => x.TableName == tableName)
|
||||
.Any(c => c.UserAuthArr != null && actionsToCheck.Any(action => c.UserAuthArr.Contains(action)));
|
||||
}
|
||||
//明细表没权限的走主表权限
|
||||
if (!actionAuth)
|
||||
{
|
||||
string table = TableColumnContext.TableInfo.Where(x => x.DetailName != null && x.DetailName.ToLower().Split(",").Contains(tableName))
|
||||
.Select(s => s.TableName)
|
||||
.FirstOrDefault();
|
||||
actionAuth = CheckPermission(actionsToCheck, table?.ToLower());
|
||||
}
|
||||
|
||||
if (!actionAuth)
|
||||
{
|
||||
string actionsStr = actionsToCheck.Length > 0 ? string.Join(",", actionsToCheck) : "无权限";
|
||||
Logger.Info(LoggerType.Authorzie, $"没有权限操作," +
|
||||
$"用户ID{_userContext.UserId}:{_userContext.UserTrueName}," +
|
||||
$"操作权限{tableName}:{actionsStr}");
|
||||
return ResponseContent.Error(ResponseType.NoPermissions);
|
||||
}
|
||||
}
|
||||
return ResponseContent.OK();
|
||||
}
|
||||
|
||||
private bool CheckPermission(string[] actionsToCheck, string table)
|
||||
{
|
||||
if (table == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var permissions = _userContext.GetPermissions(x => x.TableName == table);
|
||||
if (permissions?.UserAuthArr != null)
|
||||
{
|
||||
// 检查用户权限数组中是否包含任意一个需要的权限
|
||||
return actionsToCheck.Any(action => permissions.UserAuthArr.Contains(action));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace VolPro.Core.Filters
|
||||
{
|
||||
public class ActionPermissionRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// 控制器要操作的表
|
||||
/// </summary>
|
||||
public string TableName { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// 对表的操作/删除/查询等(多个权限数组)
|
||||
/// </summary>
|
||||
public string[] TableActions { get; set; }
|
||||
/// <summary>
|
||||
/// 是否为框架定义的控制器
|
||||
/// </summary>
|
||||
public bool SysController { get; set; }
|
||||
/// <summary>
|
||||
/// 限制只能由某些角色Id访问
|
||||
/// </summary>
|
||||
public int[] RoleIds { get; set; }
|
||||
|
||||
public bool IsApi { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using VolPro.Core.Enums;
|
||||
|
||||
namespace VolPro.Core.Filters
|
||||
{
|
||||
public class ApiActionPermissionAttribute : ActionPermissionAttribute
|
||||
{
|
||||
public ApiActionPermissionAttribute()
|
||||
: base(true)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// 限定角色访问
|
||||
/// </summary>
|
||||
/// <param name="roles"></param>
|
||||
public ApiActionPermissionAttribute(int roleId)
|
||||
: base(roleId, true)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// 限定角色访问
|
||||
/// </summary>
|
||||
/// <param name="roles"></param>
|
||||
public ApiActionPermissionAttribute(ActionRolePermission actionRolePermission)
|
||||
: base(actionRolePermission, true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ApiActionPermissionAttribute(string tableName, ActionPermissionOptions tableAction, bool sysController = false)
|
||||
: base(tableName, tableAction, sysController, true)
|
||||
{
|
||||
|
||||
}
|
||||
public ApiActionPermissionAttribute(string tableName, string roleIds, ActionPermissionOptions tableAction, bool sysController = false)
|
||||
: base(tableName, roleIds, tableAction, sysController, true)
|
||||
{
|
||||
}
|
||||
public ApiActionPermissionAttribute(ActionPermissionOptions tableAction)
|
||||
: base(tableAction, true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum ActionRolePermission
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色ID为1
|
||||
/// </summary>
|
||||
SuperAdmin = 1,
|
||||
Admin=2
|
||||
}
|
||||
}
|
||||
85
api_sqlsugar/VolPro.Core/Filters/ApiAuthorizeFilter.cs
Normal file
85
api_sqlsugar/VolPro.Core/Filters/ApiAuthorizeFilter.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Claims;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.ManageUser;
|
||||
using static VolPro.Core.Filters.ApiTaskAttribute;
|
||||
|
||||
namespace VolPro.Core.Filters
|
||||
{
|
||||
public class ApiAuthorizeFilter : IAuthorizationFilter
|
||||
{
|
||||
|
||||
public ApiAuthorizeFilter()
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 只判断token是否正确,不判断权限
|
||||
/// 如果需要判断权限的在Action上加上ApiActionPermission属性标识权限类别,ActionPermissionFilter作权限处理
|
||||
///(string,string,string)1、请求参数,2、返回消息,3,异常消息,4状态
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
// is Microsoft.AspNetCore.Authentication.AllowAnonymousAttribute
|
||||
//if (context.Filters.Any(item => item is IAllowAnonymousFilter))
|
||||
if (context.ActionDescriptor.EndpointMetadata.Any(item => item is IAllowAnonymous))
|
||||
{
|
||||
if (context.Filters
|
||||
.Where(item => item is IApiTaskFilter)
|
||||
.FirstOrDefault() is IApiTaskFilter apiTaskFilter)
|
||||
{
|
||||
apiTaskFilter.OnAuthorization(context);
|
||||
return;
|
||||
}
|
||||
//如果使用了固定Token不过期,直接对token的合法性及token是否存在进行验证
|
||||
else if (context.Filters
|
||||
.Where(item => item is IFixedTokenFilter)
|
||||
.FirstOrDefault() is IFixedTokenFilter tokenFilter)
|
||||
{
|
||||
tokenFilter.OnAuthorization(context);
|
||||
return;
|
||||
}
|
||||
//匿名并传入了token,需要将用户的ID缓存起来,保证UserHelper里能正确获取到用户信息
|
||||
if (!context.HttpContext.User.Identity.IsAuthenticated
|
||||
&& !string.IsNullOrEmpty(context.HttpContext.Request.Headers[AppSetting.TokenHeaderName]))
|
||||
{
|
||||
context.AddIdentity();
|
||||
}
|
||||
return;
|
||||
}
|
||||
//限定一个帐号不能在多处登陆 UserContext.Current.Token != ((ClaimsIdentity)context.HttpContext.User.Identity)?.BootstrapContext?.ToString()
|
||||
|
||||
// &&UserContext.Current.UserName!="admin666"为演示环境,实际使用时去掉此条件
|
||||
//if (!context.HttpContext.User.Identity.IsAuthenticated
|
||||
// || (
|
||||
// UserContext.Current.Token != ((ClaimsIdentity)context.HttpContext.User.Identity)
|
||||
// ?.BootstrapContext?.ToString()
|
||||
// && UserContext.Current.UserName != "admin666"
|
||||
// ))
|
||||
//{
|
||||
// Console.Write($"IsAuthenticated:{context.HttpContext.User.Identity.IsAuthenticated}," +
|
||||
// $"userToken{UserContext.Current.Token}" +
|
||||
// $"BootstrapContext:{((ClaimsIdentity)context.HttpContext.User.Identity)?.BootstrapContext?.ToString()}");
|
||||
// context.Unauthorized("登陆已过期".Translator());
|
||||
// return;
|
||||
//}
|
||||
|
||||
DateTime expDate = context.HttpContext.User.Claims.Where(x => x.Type == JwtRegisteredClaimNames.Exp)
|
||||
.Select(x => x.Value).FirstOrDefault().GetTimeSpmpToDate();
|
||||
//动态标识刷新token(2021.05.01)
|
||||
if ((expDate - DateTime.Now).TotalMinutes < AppSetting.ExpMinutes/ 3 && context.HttpContext.Request.Path != replaceTokenPath)
|
||||
{
|
||||
context.HttpContext.Response.Headers["vol_exp"]= "1";
|
||||
}
|
||||
}
|
||||
private static readonly string replaceTokenPath = "/api/User/replaceToken";
|
||||
}
|
||||
}
|
||||
26
api_sqlsugar/VolPro.Core/Filters/ApiTaskAttribute.cs
Normal file
26
api_sqlsugar/VolPro.Core/Filters/ApiTaskAttribute.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.Quartz;
|
||||
|
||||
namespace VolPro.Core.Filters
|
||||
{
|
||||
public interface IApiTaskFilter : IFilterMetadata
|
||||
{
|
||||
AuthorizationFilterContext OnAuthorization(AuthorizationFilterContext context);
|
||||
}
|
||||
public class ApiTaskAttribute : Attribute, IApiTaskFilter, IAllowAnonymous
|
||||
{
|
||||
public AuthorizationFilterContext OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
return QuartzAuthorization.Validation(context) ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
53
api_sqlsugar/VolPro.Core/Filters/FixedTokenAttribute.cs
Normal file
53
api_sqlsugar/VolPro.Core/Filters/FixedTokenAttribute.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Security.Claims;
|
||||
using VolPro.Core.Configuration;
|
||||
using VolPro.Core.Extensions;
|
||||
using VolPro.Core.ManageUser;
|
||||
using VolPro.Core.Utilities;
|
||||
|
||||
namespace VolPro.Core.Filters
|
||||
{
|
||||
public interface IFixedTokenFilter : IFilterMetadata
|
||||
{
|
||||
AuthorizationFilterContext OnAuthorization(AuthorizationFilterContext context);
|
||||
}
|
||||
public class FixedTokenAttribute : Attribute, IFixedTokenFilter, IAllowAnonymous
|
||||
{
|
||||
public AuthorizationFilterContext OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
string fixedoken = "";
|
||||
//如果token已失效,直接获取header里的token
|
||||
if (!context.HttpContext.User.Identity.IsAuthenticated)
|
||||
{
|
||||
fixedoken = context.HttpContext.Request.Headers[AppSetting.TokenHeaderName];
|
||||
fixedoken = fixedoken?.Replace("Bearer ", "");
|
||||
//判断是否传入了token
|
||||
if (string.IsNullOrEmpty(fixedoken))
|
||||
{
|
||||
return context.Unauthorized("没有传入token");
|
||||
}
|
||||
//解析token
|
||||
int userId = JwtHelper.GetUserId(fixedoken);
|
||||
if (userId <= 0)
|
||||
{
|
||||
return context.Unauthorized("token不正确");
|
||||
}
|
||||
context.AddIdentity(userId);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixedoken = ((ClaimsIdentity)context.HttpContext.User.Identity)
|
||||
?.BootstrapContext?.ToString();
|
||||
}
|
||||
//判断当前用户的token与缓存的token是否相同
|
||||
if (UserContext.Current.Token != fixedoken)
|
||||
{
|
||||
context.FilterResult(HttpStatusCode.Unauthorized, "token已失效");
|
||||
}
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user