mirror of
https://gitee.com/dotnetchina/SqlSugar.git
synced 2025-09-19 10:08:19 +08:00
Update Core
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SqlSugar
|
||||
{
|
||||
public class SugarCacheProvider
|
||||
{
|
||||
public ICacheService Servie { get; set; }
|
||||
|
||||
public void RemoveDataCache(string likeString)
|
||||
{
|
||||
if (Servie == null) return;
|
||||
CacheSchemeMain.RemoveCacheByLike(Servie, likeString);
|
||||
}
|
||||
|
||||
public List<string> GetAllKey()
|
||||
{
|
||||
if (Servie == null) return new List<string>();
|
||||
return Servie.GetAllKey<string>()?.ToList();
|
||||
}
|
||||
|
||||
public void Add(string key,object value)
|
||||
{
|
||||
if (Servie == null) return;
|
||||
Servie.Add(key,value,60*60*24*100);
|
||||
}
|
||||
|
||||
public void Add(string key, object value,int seconds)
|
||||
{
|
||||
if (Servie == null) return;
|
||||
Servie.Add(key, value,seconds);
|
||||
}
|
||||
|
||||
public T Get<T>(string key)
|
||||
{
|
||||
if (Servie == null) return default(T);
|
||||
return Servie.Get<T>(key);
|
||||
}
|
||||
}
|
||||
}
|
@@ -238,7 +238,15 @@ namespace SqlSugar
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
public IDeleteable<T> RemoveDataCache(string likeString)
|
||||
{
|
||||
this.RemoveCacheFunc = () =>
|
||||
{
|
||||
var cacheService = this.Context.CurrentConnectionConfig.ConfigureExternalServices.DataInfoCacheService;
|
||||
CacheSchemeMain.RemoveCacheByLike(cacheService, likeString);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
public IDeleteable<T> In<PkType>(List<PkType> primaryKeyValues)
|
||||
{
|
||||
if (primaryKeyValues == null || primaryKeyValues.Count() == 0)
|
||||
|
@@ -188,19 +188,20 @@ namespace SqlSugar
|
||||
if (columns == null)
|
||||
columns = new string[] { };
|
||||
this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => !columns.Any(ig => ig.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase))).ToList();
|
||||
this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => !columns.Any(ig => ig.Equals(it.DbColumnName, StringComparison.CurrentCultureIgnoreCase))).ToList();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IInsertable<T> InsertColumns(Expression<Func<T, object>> columns)
|
||||
{
|
||||
var ignoreColumns = InsertBuilder.GetExpressionValue(columns, ResolveExpressType.ArraySingle).GetResultArray().Select(it => this.SqlBuilder.GetNoTranslationColumnName(it)).ToList();
|
||||
this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => ignoreColumns.Any(ig => ig.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase))).ToList();
|
||||
this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => ignoreColumns.Any(ig => ig.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase)) || ignoreColumns.Any(ig => ig.Equals(it.DbColumnName, StringComparison.CurrentCultureIgnoreCase))).ToList();
|
||||
return this;
|
||||
}
|
||||
|
||||
public IInsertable<T> InsertColumns(string[] columns)
|
||||
{
|
||||
this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => columns.Any(ig => ig.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase))).ToList();
|
||||
this.InsertBuilder.DbColumnInfoList = this.InsertBuilder.DbColumnInfoList.Where(it => columns.Any(ig => ig.Equals(it.PropertyName, StringComparison.CurrentCultureIgnoreCase))|| columns.Any(ig => ig.Equals(it.DbColumnName, StringComparison.CurrentCultureIgnoreCase))).ToList();
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -228,6 +229,15 @@ namespace SqlSugar
|
||||
};
|
||||
return this;
|
||||
}
|
||||
public IInsertable<T> RemoveDataCache(string likeString)
|
||||
{
|
||||
this.RemoveCacheFunc = () =>
|
||||
{
|
||||
var cacheService = this.Context.CurrentConnectionConfig.ConfigureExternalServices.DataInfoCacheService;
|
||||
CacheSchemeMain.RemoveCacheByLike(cacheService, likeString);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
public MySqlBlueCopy<T> UseMySql()
|
||||
{
|
||||
return new MySqlBlueCopy<T>(this.Context, this.SqlBuilder, InsertObjs);
|
||||
|
@@ -166,6 +166,10 @@ namespace SqlSugar
|
||||
child.GetType().GetProperty(subMemberName).SetValue(child, pkValue);
|
||||
}
|
||||
}
|
||||
if (!(childList as IEnumerable<object>).Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var type = (childList as IEnumerable<object>).First().GetType();
|
||||
this.Context.InitMappingInfo(type);
|
||||
var entityInfo = this.Context.EntityMaintenance.GetEntityInfo(type);
|
||||
|
@@ -622,6 +622,7 @@ namespace SqlSugar
|
||||
if (QueryBuilder.Take == null)
|
||||
QueryBuilder.Take = 1;
|
||||
_PartitionBy(expression);
|
||||
QueryBuilder.DisableTop = true;
|
||||
return this;
|
||||
}
|
||||
public virtual ISugarQueryable<T> PartitionBy(string groupFileds)
|
||||
@@ -750,6 +751,9 @@ namespace SqlSugar
|
||||
var result = InstanceFactory.GetQueryable<TResult>(this.Context.CurrentConnectionConfig);
|
||||
result.Context = this.Context;
|
||||
result.SqlBuilder = this.SqlBuilder;
|
||||
result.QueryBuilder.ResultType = this.QueryBuilder.ResultType;
|
||||
result.IsCache = this.IsCache;
|
||||
result.CacheTime = this.CacheTime;
|
||||
QueryBuilder.SelectValue = selectValue;
|
||||
if (this.IsAs)
|
||||
{
|
||||
@@ -953,6 +957,7 @@ namespace SqlSugar
|
||||
|
||||
public virtual DataTable ToDataTable()
|
||||
{
|
||||
QueryBuilder.ResultType = typeof(SugarCacheDataTable);
|
||||
InitMapping();
|
||||
var sqlObj = this.ToSql();
|
||||
RestoreMapping();
|
||||
@@ -1001,6 +1006,7 @@ namespace SqlSugar
|
||||
|
||||
public Dictionary<string, object> ToDictionary(Expression<Func<T, object>> key, Expression<Func<T, object>> value)
|
||||
{
|
||||
this.QueryBuilder.ResultType = typeof(SugarCacheDictionary);
|
||||
var keyName = QueryBuilder.GetExpressionValue(key, ResolveExpressType.FieldSingle).GetResultString();
|
||||
var valueName = QueryBuilder.GetExpressionValue(value, ResolveExpressType.FieldSingle).GetResultString();
|
||||
var result = this.Select<KeyValuePair<string, object>>(keyName + "," + valueName).ToList().ToDictionary(it => it.Key.ObjToString(), it => it.Value);
|
||||
@@ -1008,8 +1014,9 @@ namespace SqlSugar
|
||||
}
|
||||
public async Task<Dictionary<string, object>> ToDictionaryAsync(Expression<Func<T, object>> key, Expression<Func<T, object>> value)
|
||||
{
|
||||
var keyName = QueryBuilder.GetExpressionValue(key, ResolveExpressType.FieldSingle);
|
||||
var valueName = QueryBuilder.GetExpressionValue(value, ResolveExpressType.FieldSingle);
|
||||
this.QueryBuilder.ResultType = typeof(SugarCacheDictionary);
|
||||
var keyName = QueryBuilder.GetExpressionValue(key, ResolveExpressType.FieldSingle).GetResultString();
|
||||
var valueName = QueryBuilder.GetExpressionValue(value, ResolveExpressType.FieldSingle).GetResultString();
|
||||
var list = await this.Select<KeyValuePair<string, object>>(keyName + "," + valueName).ToListAsync();
|
||||
var result =list.ToDictionary(it => it.Key.ObjToString(), it => it.Value);
|
||||
return result;
|
||||
@@ -1323,6 +1330,7 @@ namespace SqlSugar
|
||||
}
|
||||
public async Task<DataTable> ToDataTableAsync()
|
||||
{
|
||||
QueryBuilder.ResultType = typeof(SugarCacheDataTable);
|
||||
InitMapping();
|
||||
var sqlObj = this.ToSql();
|
||||
RestoreMapping();
|
||||
|
@@ -40,6 +40,7 @@ namespace SqlSugar
|
||||
public int ExternalPageIndex { get; set; }
|
||||
public int ExternalPageSize { get; set; }
|
||||
public int? Take { get; set; }
|
||||
public bool DisableTop { get; set; }
|
||||
public string OrderByValue { get; set; }
|
||||
public object SelectValue { get; set; }
|
||||
public string SelectCacheKey { get; set; }
|
||||
@@ -47,6 +48,7 @@ namespace SqlSugar
|
||||
|
||||
|
||||
public Type EntityType { get; set; }
|
||||
public Type ResultType { get; set; }
|
||||
public string TableWithString { get; set; }
|
||||
public string GroupByValue { get; set; }
|
||||
public string PartitionByValue { get; set; }
|
||||
|
@@ -544,6 +544,7 @@ namespace SqlSugar
|
||||
List<KeyValuePair<string, List<SugarParameter>>> allItems = new List<KeyValuePair<string, List<SugarParameter>>>();
|
||||
foreach (var item in queryables)
|
||||
{
|
||||
item.QueryBuilder.DisableTop = true;
|
||||
var sqlObj = item.ToSql();
|
||||
string sql = sqlObj.Key;
|
||||
UtilMethods.RepairReplicationParameters(ref sql, sqlObj.Value.ToArray(), i, "Union");
|
||||
@@ -1068,5 +1069,21 @@ namespace SqlSugar
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cache
|
||||
public SugarCacheProvider DataCache
|
||||
{
|
||||
get {
|
||||
var services=this.CurrentConnectionConfig.ConfigureExternalServices;
|
||||
if (services == null)
|
||||
return new SugarCacheProvider();
|
||||
if (services.DataInfoCacheService == null)
|
||||
return new SugarCacheProvider();
|
||||
SugarCacheProvider cache = new SugarCacheProvider();
|
||||
cache.Servie=services.DataInfoCacheService;
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
@@ -97,6 +97,15 @@ namespace SqlSugar
|
||||
};
|
||||
return this;
|
||||
}
|
||||
public IUpdateable<T> RemoveDataCache(string likeString)
|
||||
{
|
||||
this.RemoveCacheFunc = () =>
|
||||
{
|
||||
var cacheService = this.Context.CurrentConnectionConfig.ConfigureExternalServices.DataInfoCacheService;
|
||||
CacheSchemeMain.RemoveCacheByLike(cacheService,likeString);
|
||||
};
|
||||
return this;
|
||||
}
|
||||
public IUpdateable<T> IsEnableUpdateVersionValidation()
|
||||
{
|
||||
this.IsVersionValidation = true;
|
||||
@@ -740,11 +749,11 @@ namespace SqlSugar
|
||||
|
||||
private void ThrowUpdateByExpression()
|
||||
{
|
||||
Check.Exception(UpdateParameterIsNull == true, ErrorMessage.GetThrowMessage("no support SetColumns and Where ", "根据对象进行更新 db.Updateable(现有集合对象) 禁止使用 SetColumns和Where,你可以使用 WhereColumns UpdateColumns 等。更新分为2种方式 1.根据表达式更新 2.根据实体或者集合更新, 具体用法请查看文档 "));
|
||||
Check.Exception(UpdateParameterIsNull == true, ErrorMessage.GetThrowMessage(" no support UpdateColumns and WhereColumns", "根据表达式更新 db.Updateable<T>() 禁止使用 UpdateColumns和WhereColumns,你可以使用 SetColumns Where 等。更新分为2种方式 1.根据表达式更新 2.根据实体或者集合更新, 具体用法请查看文档 "));
|
||||
}
|
||||
private void ThrowUpdateByObject()
|
||||
{
|
||||
Check.Exception(UpdateParameterIsNull == false, ErrorMessage.GetThrowMessage("no support UpdateColumns and WhereColumns ", "根据表达式进行更新 禁止使用 UpdateColumns和WhereColumns ,你可以使用SetColumns 和 Where。 更新分为2种方式 1.根据表达式更新 2.根据实体或者集合更新 , 具体用法请查看文档 "));
|
||||
Check.Exception(UpdateParameterIsNull == false, ErrorMessage.GetThrowMessage(" no support SetColumns and Where", "根据对像更新 db.Updateabe(对象) 禁止使用 SetColumns和Where ,你可以使用WhereColumns 和 UpdateColumns。 更新分为2种方式 1.根据表达式更新 2.根据实体或者集合更新 , 具体用法请查看文档 "));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -13,6 +14,10 @@ namespace SqlSugar
|
||||
result.Database = context.Context.Ado.Connection.Database;
|
||||
AddTables(context, queryBuilder, result);
|
||||
AddIdentificationList(queryBuilder, result);
|
||||
if (queryBuilder.ResultType!=null)
|
||||
{
|
||||
result.IdentificationList.Add(queryBuilder.ResultType.FullName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -58,4 +63,17 @@ namespace SqlSugar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class SugarCacheDictionary
|
||||
{
|
||||
|
||||
}
|
||||
internal class SugarCacheDictionaryList
|
||||
{
|
||||
|
||||
}
|
||||
internal class SugarCacheDataTable
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -33,5 +33,23 @@ namespace SqlSugar
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void RemoveCacheByLike(ICacheService cacheService, string likeString)
|
||||
{
|
||||
if (cacheService == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var keys = cacheService.GetAllKey<string>();
|
||||
if (keys.HasValue())
|
||||
{
|
||||
foreach (var item in keys)
|
||||
{
|
||||
if (item.ToLower().Contains(likeString.ToLower()))
|
||||
{
|
||||
cacheService.Remove<string>(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -134,7 +134,14 @@ namespace SqlSugar
|
||||
base.Start();
|
||||
string parameterName = this.Context.SqlParameterKeyWord + ExpressionConst.Const + this.Context.ParameterIndex;
|
||||
parameter.Context.Result.Append(base.Context.GetEqString(memberName, parameterName));
|
||||
this.Context.Parameters.Add(new SugarParameter(parameterName, parameter.CommonTempData));
|
||||
var addItem = new SugarParameter(parameterName, parameter.CommonTempData);
|
||||
var dataType = UtilMethods.GetUnderType(item.Type);
|
||||
if (addItem.Value == null && dataType == UtilConstants.DateType)
|
||||
{
|
||||
addItem.DbType = System.Data.DbType.Date;
|
||||
|
||||
}
|
||||
this.Context.Parameters.Add(addItem);
|
||||
this.Context.ParameterIndex++;
|
||||
}
|
||||
else if (item is MemberExpression)
|
||||
|
@@ -9,7 +9,7 @@ namespace SqlSugar
|
||||
|
||||
public class InstanceFactory
|
||||
{
|
||||
static Assembly assembly = Assembly.Load(UtilConstants.AssemblyName);
|
||||
static Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
static Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
|
||||
public static bool NoCache = false;
|
||||
|
||||
|
@@ -32,6 +32,7 @@ namespace SqlSugar
|
||||
IDeleteable<T> WhereColumns(Expression<Func<T, object>> columns);
|
||||
IDeleteable<T> EnableDiffLogEvent(object businessData = null);
|
||||
IDeleteable<T> RemoveDataCache();
|
||||
IDeleteable<T> RemoveDataCache(string likeString);
|
||||
KeyValuePair<string, List<SugarParameter>> ToSql();
|
||||
void AddQueue();
|
||||
}
|
||||
|
@@ -14,6 +14,8 @@ namespace SqlSugar
|
||||
SqlSugarProvider Context { get; set; }
|
||||
ISqlBuilder SqlBuilder { get; set; }
|
||||
QueryBuilder QueryBuilder { get; set; }
|
||||
bool IsCache { get; set; }
|
||||
int CacheTime { get; set; }
|
||||
ISugarQueryable<T> Clone();
|
||||
ISugarQueryable<T> AS<T2>(string tableName);
|
||||
ISugarQueryable<T> AS(string tableName);
|
||||
|
@@ -162,5 +162,9 @@ namespace SqlSugar
|
||||
IUpdateable<T> Updateable<T>(T UpdateObj) where T : class, new();
|
||||
IUpdateable<T> Updateable<T>(T[] UpdateObjs) where T : class, new();
|
||||
#endregion
|
||||
|
||||
#region Cache
|
||||
SugarCacheProvider DataCache { get; }
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -87,6 +87,7 @@ namespace SqlSugar
|
||||
IUpdateable<T> EnableDiffLogEvent(object businessData = null);
|
||||
IUpdateable<T> ReSetValue(Expression<Func<T, bool>> setValueExpression);
|
||||
IUpdateable<T> RemoveDataCache();
|
||||
IUpdateable<T> RemoveDataCache(string likeString);
|
||||
IUpdateable<T> CallEntityMethod(Expression<Action<T>> method);
|
||||
KeyValuePair<string,List<SugarParameter>> ToSql();
|
||||
void AddQueue();
|
||||
|
@@ -36,6 +36,7 @@ namespace SqlSugar
|
||||
|
||||
IInsertable<T> EnableDiffLogEvent(object businessData = null);
|
||||
IInsertable<T> RemoveDataCache();
|
||||
IInsertable<T> RemoveDataCache(string likeString);
|
||||
KeyValuePair<string, List<SugarParameter>> ToSql();
|
||||
SqlServerBlueCopy UseSqlServer();
|
||||
MySqlBlueCopy<T> UseMySql();
|
||||
|
@@ -25,13 +25,12 @@ namespace SqlSugar
|
||||
this.Builder = builder;
|
||||
this.Entitys = entitys;
|
||||
}
|
||||
public bool ExecuteBlueCopy(string chara)
|
||||
public bool ExecuteBlueCopy(string characterSet)
|
||||
{
|
||||
this.Chara = chara;
|
||||
this.Chara = characterSet;
|
||||
return ExecuteBlueCopy();
|
||||
}
|
||||
|
||||
|
||||
public bool ExecuteBlueCopy()
|
||||
{
|
||||
var IsBulkLoad = false;
|
||||
@@ -61,9 +60,9 @@ namespace SqlSugar
|
||||
var name = p.Name;
|
||||
if (entity.Columns.Any(it => it.PropertyName == name))
|
||||
{
|
||||
name=entity.Columns.First(it => it.PropertyName == name).DbColumnName;
|
||||
name = entity.Columns.First(it => it.PropertyName == name).DbColumnName;
|
||||
}
|
||||
row[name] = p.GetValue(item, null);
|
||||
row[name] = GetValue(p, item);
|
||||
});
|
||||
dt.Rows.Add(row);
|
||||
}
|
||||
@@ -75,7 +74,7 @@ namespace SqlSugar
|
||||
}
|
||||
var fileName = dllPath + "\\" + Guid.NewGuid().ToString() + ".csv";
|
||||
var dataTableToCsv = DataTableToCsvString(dt);
|
||||
File.WriteAllText(fileName, dataTableToCsv, Encoding.UTF8);
|
||||
File.WriteAllText(fileName, dataTableToCsv, new UTF8Encoding(false));
|
||||
MySqlConnection conn = this.Context.Ado.Connection as MySqlConnection;
|
||||
try
|
||||
{
|
||||
@@ -112,6 +111,18 @@ namespace SqlSugar
|
||||
return IsBulkLoad; ;
|
||||
}
|
||||
|
||||
public Task<bool> ExecuteBlueCopyAsync()
|
||||
{
|
||||
return Task.FromResult(ExecuteBlueCopy());
|
||||
}
|
||||
|
||||
public Task<bool> ExecuteBlueCopyAsync(string characterSet)
|
||||
{
|
||||
this.Chara = characterSet;
|
||||
return Task.FromResult(ExecuteBlueCopy());
|
||||
}
|
||||
|
||||
#region Helper
|
||||
private string GetChara()
|
||||
{
|
||||
if (this.Chara == null)
|
||||
@@ -124,17 +135,6 @@ namespace SqlSugar
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> ExecuteBlueCopyAsync()
|
||||
{
|
||||
return Task.FromResult(ExecuteBlueCopy());
|
||||
}
|
||||
|
||||
public Task<bool> ExecuteBlueCopyAsync(string chara)
|
||||
{
|
||||
this.Chara = chara;
|
||||
return Task.FromResult(ExecuteBlueCopy());
|
||||
}
|
||||
|
||||
private void CloseDb()
|
||||
{
|
||||
if (this.Context.CurrentConnectionConfig.IsAutoCloseConnection && this.Context.Ado.Transaction == null)
|
||||
@@ -170,5 +170,21 @@ namespace SqlSugar
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
|
||||
private static object GetValue(PropertyInfo p, T item)
|
||||
{
|
||||
var result= p.GetValue(item, null);
|
||||
if (result != null && UtilMethods.GetUnderType(p.PropertyType) == UtilConstants.BoolType)
|
||||
{
|
||||
if (result.ObjToBool() == false)
|
||||
{
|
||||
result = null;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -28,7 +28,7 @@ namespace SqlSugar
|
||||
{
|
||||
this.OrderByValue = this.PartitionByValue + this.OrderByValue;
|
||||
}
|
||||
var isFirst = (Skip == 0 || Skip == null) && Take == 1;
|
||||
var isFirst = (Skip == 0 || Skip == null) && Take == 1&&DisableTop==false;
|
||||
var isRowNumber = (Skip != null || Take != null) && !isFirst;
|
||||
var rowNumberString = string.Format(",ROW_NUMBER() OVER({0}) AS RowIndex ", GetOrderByString);
|
||||
string groupByValue = GetGroupByString + HavingInfos;
|
||||
|
@@ -718,6 +718,13 @@ namespace SqlSugar
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cache
|
||||
public SugarCacheProvider DataCache
|
||||
{
|
||||
get { return this.Context.DataCache; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other method
|
||||
public DateTime GetDate()
|
||||
{
|
||||
|
Reference in New Issue
Block a user