سلام
یک برنامه داریم که با Asp.Core5 نوشته شده است
می خواهیم هنگام ثبت اطلاعات حروف (ک و ی) بصورت یکسان شده در جداول دیتابیس ذخیره بشود باید چه کدی بنویسم
باتشکر
سلام
یک برنامه داریم که با Asp.Core5 نوشته شده است
می خواهیم هنگام ثبت اطلاعات حروف (ک و ی) بصورت یکسان شده در جداول دیتابیس ذخیره بشود باید چه کدی بنویسم
باتشکر
چند تا راه برای این مسئله وجود داره:
- از طریق یک Middleware بدنه Request رو بخوانید، و کاراکترهای ی و ک عربی رو با فارسی جایگزین کنید (این روش آسان نیست، خودم تا این لحظه که این پاسخ رو می نویسم دارم رویش کار می کنم، اما هنوز به نتیجه نرسیدم).
- یک Model Binder برای نوع داده String بنویسید، و در اون Model Binder کاراکترهای مورد نظر را با معادل هاش جایگزین کنید (پروسه اش کمی سخته، ولی انجامش دادم، اگر میخواهی بگو کدش رو بگذارم).
- از طریق مکانیسمی مثل نوشتن فیلتر برای EF Core کار مورد نظر رو انجام دهید (هنوز این روش رو بررسی نکردم که شدنی هست یا نه، نمونه کدش برای EF 6 دیدم).
اگر روش 2 به کارت میاد اعلام کن. مزیت روش 2 این است که روی داده های دریافتی از تمام منابع، از جمله Form و Query String و Route Parameter تاثیر میگذاره، اما روی داده های خوانده شده از دیتابیس، یا مثلا یک فایل Text و ... تاثیری نداره.
سلام
لطف می کنید
قرار دهیدکدهای مربوطه
سمت sql هم با دستوراتی که دارم انجام می دهم
من اینطوری مشکل رو حل کردم
متد savechange رو overrid کردم
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
ApplyCorrectYeKe();
return (await base.SaveChangesAsync(true, cancellationToken));
}
private void ApplyCorrectYeKe()
{
//پیدا کردن موجودیتهای تغییر کرده
var changedEntities = this.ChangeTracker
.Entries()
.Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
foreach (var item in changedEntities)
{
if (item.Entity == null) continue;
//یافتن خواص قابل تنظیم و رشتهای این موجودیتها
var propertyInfos = item.Entity.GetType().GetProperties(
BindingFlags.Public | BindingFlags.Instance
).Where(p => p.CanRead && p.CanWrite && p.PropertyType == typeof(string));
//var pr = new PropertyReflector();
var pr = new PropertyReflector();
//اعمال یکپارچگی نهایی
foreach (var propertyInfo in propertyInfos)
{
var propName = propertyInfo.Name;
var val = pr.GetValue(item.Entity, propName);
if (val != null)
{
var newVal = val.ToString().Replace("ي", "ی").Replace("ك", "ک").Trim();
if (newVal == val.ToString()) continue;
pr.SetValue(item.Entity, propName, newVal);
}
}
}
}
روشی که جناب حمزه معرفی کرده اند بسیار جالب بود، با تشکر فراوان.
من مشکل رو از طریق ModelBinder حل کردم. به این صورت:
public class StringModelBinder: IModelBinder
{
private readonly IModelBinder _fallbackBinder;
public StringModelBinder(IModelBinder fallbackBinder)
{
if (fallbackBinder == null)
throw new ArgumentNullException(nameof(fallbackBinder));
_fallbackBinder = fallbackBinder;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingConte xt.ModelName);
var attemptedValue = value.FirstValue;
var modifiedValue = value.ToString().Replace((char) 1610, (char) 1740).Replace((char) 1603, (char) 1705);
bindingContext.Result = ModelBindingResult.Success(modifiedValue);
}
}
public class StringEncodeModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!context.Metadata.IsComplexType && context.Metadata.ModelType == typeof(string)) // only encode string types
{
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory >();
return new StringModelBinder(new SimpleTypeModelBinder(context.Metadata.ModelType, loggerFactory));
}
return null;
}
}
public static class MvcOptionsExtensions
{
public static void UseStringEncodeModelBinding(this MvcOptions opts)
{
var binderToFind = opts.ModelBinderProviders.FirstOrDefault(x => x.GetType() == typeof(SimpleTypeModelBinderProvider));
if (binderToFind == null) return;
var index = opts.ModelBinderProviders.IndexOf(binderToFind);
opts.ModelBinderProviders.Insert(index, new StringEncodeModelBinderProvider());
}
}
در نمونه کد فوق، کلاس اصلی، کلاس StringModelBinder است. کلاس فوق اگر بصورت صحیح رجیستر شود، هنگام تبدیل تمام مقادیر دریافت شده String از تمام ورودی ها (Model, Post,Query String, Route Parameter) عمل می کند و مقدار دریافتی را تبدیل به تایپ String می کند. در هنگام تبدیل، هم جایگزینی حرف های ی و ک عربی به فارسی را نیز انجام می دهد.
برای ثبت کلاس های Model Binder در ASP.NET Core نیاز به یک کلاس Provider نیز هست که در نمونه کد فوق در قالب کلاس StringEncodeModelBinderProvider پیاده سازی شده است.
در نهایت، جهت معرفی کلاس StringModelBinder به عنوان تبدیل گر پیش فرض تایپ String در متد استاتیک UseStringEncodeModelBinding کدهای مورد نیاز برای رجیستر کردن کلاس تبدیل گر اضافه شده است.
برای فعال کردن این کلاس کافی است در فایل Startup در متد ConfigureServices به این صورت عمل کنید:
services.AddMvc(options => { options.UseStringEncodeModelBinding(); });
توضیح درباره روش جناب حمزه:
متد override شده SaveChangesAsync ایشان میبایست به همین شکل در کلاس DbContext پروژه اضافه شود.
من هم یک کمی دستکاری اش کردم و کد ایشان را به این شکل به یک Extension Method تبدیل کردم:
public static class EfExtensions
{
public static DbContext FixArabicYeKaf(this DbContext db)
{
//پیدا کردن موجودیتهای تغییر کرده
var changedEntities = db.ChangeTracker
.Entries()
.Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
foreach (var item in changedEntities)
{
if (item.Entity == null) continue;
//یافتن خواص قابل تنظیم و رشتهای این موجودیتها
var propertyInfos = item.Entity.GetType().GetProperties(
BindingFlags.Public | BindingFlags.Instance
).Where(p => p.CanRead && p.CanWrite && p.PropertyType == typeof(string));
//var pr = new PropertyReflector();
//var pr = new PropertyReflector();
//اعمال یکپارچگی نهایی
foreach (var propertyInfo in propertyInfos)
{
var propName = propertyInfo.Name;
var val = propertyInfo.GetValue(item.Entity);
if (val != null)
{
var newVal = val.ToString().Replace("ي", "ی").Replace("ك", "ک").Trim();
if (newVal == val.ToString()) continue;
propertyInfo.SetValue(item.Entity, newVal);
}
}
}
return db;
}
}
برای فراخوانی اش هم متد override شده SaveChangeAsync رو به این شکل تغییر دادم:
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
this.FixArabicYeKaf();
return (await base.SaveChangesAsync(true, cancellationToken));
}
ممنونم استاد کرامتی عزیز