با سلام؛ چرا در متد addCustomClaims دوباره userId به Claimها اضافه شده؟
سلام جناب رجبی مطلب بسیار خوبی بود مخصوصا که من واقعا بهش نیاز داشتم اما سوالاتی برام پیش اومده من دیتابیس بزرگی دارم که سه جدولش از همه بزرگته و یکیش 190 میلیون و دو تا جدول 43 میلیون رکوردی دارم و بقیه جداول زیر 5 میلیون هست
چون در شروع کار تجربه خوبی نداشتم و از حجم اطلاعات مطمئن نبودم روی دیتابیسم pk نذاشتم حالا که میخوام pk و ایندکس گذاریش کنم برای هر جدول یک filegroup و در هر فایل گروپ یک فایل برای pk و یک فایل برای indexها گذاشتم و تقریبا هر کدوم از اون جدوال بزرگ را به 30 تا جدول تقسیم کردم تا سرعت پرس و جوهای زیادم بسیار کمتر بشه که به نظرم خوب نمیاومد (کار پرس و جو و ایجاد کوئری را دشوارتر میکنه) تا با راه حل شما اشنا شدم اما سوالم اینجاست اگر داده هام رو بر اساس تاریخ در datafileها پارتیشن بندی کنم زمانی که بخوام مثلا اطلاعات تا قبل از سال 85 را ارشیو کنم تاثیری در زمان پرس و جوی من دارد و کلیدها و ایندکسها وضعیتشون به چه شکل خواهد بود اگر از راه حل خودم استفاده نکنم چون همینجوریش حجم دیتابیسم 35 گیگه و با گذاشتن کلید و ایندکس چیزی بین 15 تا 20 گیگ هم اضافه میشه که خیلی بد هست.
الان که یه خورده رو کدها کار کردم یه سوال برام پیش اومد مثالی میزنم من جدولی دارم که تاریخ را با نام شرکت میگیره و یک کد گزارش میده حالا من این کد گزارش را با مثلا 10 هزار رکورد در جدول دوم ذخیره میکنم و و باز با همون کد گزارش 5000 رکورد را در جدول سوم ذخیره میکنم و به همین ترتیب برای تمام روزها و برای کل شرکتها این کد گزارش تولید و با حجم انبوهی از رکوردها در جداول ذخیره میشن
حالا سوال اینه که چطور بر اساس تاریخ که در جدول فقط اول هست جداول دیگر را پارتیشن بندی کنم ؟
چون در شروع کار تجربه خوبی نداشتم و از حجم اطلاعات مطمئن نبودم روی دیتابیسم pk نذاشتم حالا که میخوام pk و ایندکس گذاریش کنم برای هر جدول یک filegroup و در هر فایل گروپ یک فایل برای pk و یک فایل برای indexها گذاشتم و تقریبا هر کدوم از اون جدوال بزرگ را به 30 تا جدول تقسیم کردم تا سرعت پرس و جوهای زیادم بسیار کمتر بشه که به نظرم خوب نمیاومد (کار پرس و جو و ایجاد کوئری را دشوارتر میکنه) تا با راه حل شما اشنا شدم اما سوالم اینجاست اگر داده هام رو بر اساس تاریخ در datafileها پارتیشن بندی کنم زمانی که بخوام مثلا اطلاعات تا قبل از سال 85 را ارشیو کنم تاثیری در زمان پرس و جوی من دارد و کلیدها و ایندکسها وضعیتشون به چه شکل خواهد بود اگر از راه حل خودم استفاده نکنم چون همینجوریش حجم دیتابیسم 35 گیگه و با گذاشتن کلید و ایندکس چیزی بین 15 تا 20 گیگ هم اضافه میشه که خیلی بد هست.
الان که یه خورده رو کدها کار کردم یه سوال برام پیش اومد مثالی میزنم من جدولی دارم که تاریخ را با نام شرکت میگیره و یک کد گزارش میده حالا من این کد گزارش را با مثلا 10 هزار رکورد در جدول دوم ذخیره میکنم و و باز با همون کد گزارش 5000 رکورد را در جدول سوم ذخیره میکنم و به همین ترتیب برای تمام روزها و برای کل شرکتها این کد گزارش تولید و با حجم انبوهی از رکوردها در جداول ذخیره میشن
حالا سوال اینه که چطور بر اساس تاریخ که در جدول فقط اول هست جداول دیگر را پارتیشن بندی کنم ؟
نظرات مطالب
ASP.NET MVC #11
با سلام و عرض خسته نباشید خدمت مهندس نصیری
در قسمت سفارشی سازی model binder پیش فرض ASP.NET MVC و مثالی که برای تاریخ شمسی ارائه شد، اگر فیلد تاریخ Nullable باشد، با خطا موجه میشویم که برای رفع آن خط زیر هم باید به Application_Start اضافه شود:
ModelBinders.Binders.Add(typeof(DateTime?), new PersianDateModelBinder());
نظرات اشتراکها
نگاهی به قابلیتهای بهبود یافتهی WebStorm 2019.1
بله درسته، من یک لحظه از وابستگی razor به کامپایلر #C غافل شدم.
در intelij idea میشد خیلی از امکانات webstorm رو با کمک plugin اضافه کرد، با اینکه rider رو استفاده کردم اما به این نکته دقت نکردم، آیا توی rider هم این امکان هست؟
مطالب
EF Code First #9
تنظیمات ارث بری کلاسها در EF Code first
بانکهای اطلاعاتی مبتنی بر SQL، تنها روابطی از نوع «has a» یا «دارای» را پشتیبانی میکنند؛ اما در دنیای شیءگرا روابطی مانند «is a» یا «هست» نیز قابل تعریف هستند. برای توضیحات بیشتر به مدلهای زیر دقت نمائید:
using System;
namespace EF_Sample05.DomainClasses.Models
{
public abstract class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
}
namespace EF_Sample05.DomainClasses.Models
{
public class Coach : Person
{
public string TeamName { set; get; }
}
}
namespace EF_Sample05.DomainClasses.Models
{
public class Player : Person
{
public int Number { get; set; }
public string Description { get; set; }
}
}
در این مدلها که بر اساس ارث بری از کلاس شخص، تهیه شدهاند؛ بازیکن، یک شخص است. مربی نیز یک شخص است؛ و به این ترتیب خوانده میشوند:
Coach "is a" Person
Player "is a" Person
در EF Code first سه روش جهت کار با این نوع کلاسها و کلا ارث بری وجود دارد که در ادامه به آنها خواهیم پرداخت:
الف) Table per Hierarchy یا TPH
همانطور که از نام آن نیز پیدا است، کل سلسله مراتبی را که توسط ارث بری تعریف شده است، تبدیل به یک جدول در بانک اطلاعاتی میکند. این حالت، شیوه برخورد پیش فرض EF Code first با ارث بری کلاسها است و نیاز به هیچگونه تنظیم خاصی ندارد.
برای آزمایش این مساله، کلاس Context را به نحو زیر تعریف نمائید و سپس اجازه دهید تا EF بانک اطلاعاتی معادل آنرا تولید کند:
using System.Data.Entity;
using EF_Sample05.DomainClasses.Models;
namespace EF_Sample05.DataLayer.Context
{
public class Sample05Context : DbContext
{
public DbSet<Person> People { set; get; }
}
}
ساختار جدول تولید شده آن همانند تصویر زیر است:
همانطور که ملاحظه میکنید، تمام کلاسهای مشتق شده از کلاس شخص را تبدیل به یک جدول کرده است؛ به علاوه یک فیلد جدید را هم به نام Discriminator به این جدول اضافه نموده است. برای درک بهتر عملکرد این فیلد، چند رکورد را توسط برنامه به بانک اطلاعاتی اضافه میکنیم. حاصل آن به شکل زیر خواهد بود:
از فیلد Discriminator جهت ثبت نام کلاسهای متناظر با هر رکورد، استفاده شده است. به این ترتیب EF حین کار با اشیاء دقیقا میداند که چگونه باید خواص متناظر با کلاسهای مختلف را مقدار دهی کند.
به علاوه اگر به ساختار جدول تهیه شده دقت کنید، مشخص است که در حالت TPH، نیاز است فیلدهای متناظر با کلاسهای مشتق شده از کلاس پایه، همگی null پذیر باشند. برای نمونه فیلد Number که از نوع int تعریف شده، در سمت بانک اطلاعاتی نال پذیر تعریف شده است.
و برای کوئری نوشتن در این حالت میتوان از متد الحاقی OfType جهت فیلتر کردن اطلاعات بر اساس کلاسی خاص، کمک گرفت:
db.People.OfType<Coach>().FirstOrDefault(x => x.LastName == "Coach L1")
سفارشی سازی نحوه نگاشت TPH
همانطور که عنوان شد، TPH نیاز به تنظیمات خاصی ندارد و حالت پیش فرض است؛ اما برای مثال میتوان بر روی مقادیر و نوع ستون Discriminator تولیدی، کنترل داشت. برای این منظور باید از Fluent API به نحو زیر استفاده کرد:
using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;
namespace EF_Sample05.DataLayer.Mappings
{
public class CoachConfig : EntityTypeConfiguration<Coach>
{
public CoachConfig()
{
// For TPH
this.Map(m => m.Requires(discriminator: "PersonType").HasValue(1));
}
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;
namespace EF_Sample05.DataLayer.Mappings
{
public class PlayerConfig : EntityTypeConfiguration<Player>
{
public PlayerConfig()
{
// For TPH
this.Map(m => m.Requires(discriminator: "PersonType").HasValue(2));
}
}
}
در اینجا توسط متد Map، نام فیلد discriminator به PersonType تغییر کرده. همچنین چون مقدار پیش فرض تعیین شده توسط متد HasValue عددی است، نوع این فیلد در سمت بانک اطلاعاتی به int null تغییر میکند.
ب) Table per Type یا TPT
در حالت TPT، به ازای هر کلاس موجود در سلسله مراتب تعیین شده، یک جدول در سمت بانک اطلاعاتی تشکیل میگردد.
در جداول متناظر با Sub classes، تنها همان فیلدهایی وجود خواهند داشت که در کلاسهای هم نام وجود دارد و فیلدهای کلاس پایه در آنها ذکر نخواهد گردید. همچنین این جداول دارای یک Primary key نیز خواهند بود (که دقیقا همان کلید اصلی جدول پایه است که به آن Shared primary key هم گفته میشود). این کلید اصلی، به عنوان کلید خارجی اشاره کننده به کلاس یا جدول پایه نیز تنظیم میگردد:
برای تنظیم این نوع ارث بری، تنها کافی است ویژگی Table را بر روی Sub classes قرار داد:
using System.ComponentModel.DataAnnotations;
namespace EF_Sample05.DomainClasses.Models
{
[Table("Coaches")]
public class Coach : Person
{
public string TeamName { set; get; }
}
}
using System.ComponentModel.DataAnnotations;
namespace EF_Sample05.DomainClasses.Models
{
[Table("Players")]
public class Player : Person
{
public int Number { get; set; }
public string Description { get; set; }
}
}
یا اگر حالت Fluent API را ترجیح میدهید، همانطور که در قسمتهای قبل نیز ذکر شد، معادل ویژگی Table در اینجا، متد ToTable است.
ج) Table per Concrete type یا TPC
در تعاریف ارث بری که تاکنون بررسی کردیم، مرسوم است کلاس پایه را از نوع abstract تعریف کنند. به این ترتیب هدف اصلی، Sub classes تعریف شده خواهند بود؛ چون نمیتوان مستقیما وهلهای را از کلاس abstract تعریف شده ایجاد کرد.
در حالت TPC، به ازای هر sub class غیر abstract، یک جدول ایجاد میشود. هر جدول نیز حاوی فیلدهای کلاس پایه میباشد (برخلاف حالت TPT که جداول متناظر با کلاسهای مشتق شده، تنها حاوی همان خواص و فیلدهای کلاسهای متناظر بودند و نه بیشتر). به این ترتیب عملا جداول تشکیل شده در بانک اطلاعاتی، از وجود ارث بری در سمت کدهای ما بیخبر خواهند بود.
برای پیاده سازی TPC نیاز است از Fluent API استفاده شود:
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;
namespace EF_Sample05.DataLayer.Mappings
{
public class PersonConfig : EntityTypeConfiguration<Person>
{
public PersonConfig()
{
// for TPC
this.Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;
namespace EF_Sample05.DataLayer.Mappings
{
public class CoachConfig : EntityTypeConfiguration<Coach>
{
public CoachConfig()
{
// For TPH
//this.Map(m => m.Requires(discriminator: "PersonType").HasValue(1));
// for TPT
//this.ToTable("Coaches");
//for TPC
this.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Coaches");
});
}
}
}
using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;
namespace EF_Sample05.DataLayer.Mappings
{
public class PlayerConfig : EntityTypeConfiguration<Player>
{
public PlayerConfig()
{
// For TPH
//this.Map(m => m.Requires(discriminator: "PersonType").HasValue(2));
// for TPT
//this.ToTable("Players");
//for TPC
this.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Players");
});
}
}
}
ابتدا نوع فیلد Id از حالت Identity خارج شده است. این مورد جهت کار با TPC ضروری است در غیراینصورت EF هنگام ثبت، به مشکل بر میخورد، از این لحاظ که برای دو شیء، به یک Id خواهد رسید و امکان ثبت را نخواهد داد. بنابراین در یک چنین حالتی استفاده از نوع Guid برای تعریف primary key شاید بهتر باشد. بدیهی است در این حالت باید Id را به صورت دستی مقدار دهی نمود.
در ادامه توسط متد MapInheritedProperties، به همان مقصود لحاظ کردن تمام فیلدهای ارث بری شده در جدول حاصل، خواهیم رسید. همچنین نام جداول متناظر نیز ذکر گردیده است.
سؤال : از این بین، بهتر است از کدامیک استفاده شود؟
- برای حالتهای ساده از TPH استفاده کنید. برای مثال یک بانک اطلاعاتی قدیمی دارید که هر جدول آن 200 تا یا شاید بیشتر فیلد دارد! امکان تغییر طراحی آن هم وجود ندارد. برای اینکه بتوان به حس بهتری حین کارکردن با این نوع سیستمهای قدیمی رسید، میشود از ترکیب TPH و ComplexTypes (که در قسمتهای قبل در مورد آن بحث شد) برای مدیریت بهتر این نوع جداول در سمت کدهای برنامه استفاده کرد.
- اگر علاقمند به استفاده از روابط پلیمرفیک هستید ( برای مثال در کلاسی دیگر، ارجاعی به کلاس پایه Person وجود دارد) و sub classes دارای تعداد فیلدهای کمی هستند، از TPH استفاده کنید.
- اگر تعداد فیلدهای sub classes زیاد است و بسیار بیشتر است از کلاس پایه، از روش TPT استفاده کنید.
- اگر عمق ارث بری و تعداد سطوح تعریف شده بالا است، بهتر است از TPC استفاده کنید. حالت TPT از join استفاده میکند و حالت TPC از union برای تشکیل کوئریها کمک خواهد گرفت
من تست نکردم. ولی به نظر شدنی میآد.
چطور میتونم حذف کنم؟ پیدا نکردم
نظرات مطالب
متدی برای بررسی صحت کد ملی وارد شده
فعلا نمیدونم بررسی نکردم
سلام؛ از مثالی که زدید دارم استفاده میکنم، در کلاس ReflectionHelper متد FindFieldType موقعی که از جداول خود ارجاع دهنده استفاده میکنیم(در اینجا جدول پست)، خطا stackoverflow میگیرم، کجاش رو باید چک کنیم که فراخوانی بی نهایت اتفاق نیفته؟ مگه فیلد dumplevel همچین کاری انجام نمیده؟
data model م به این صورته :
مدیریت کنندهی سیاست دسترسی پویای نمونهی DynamicPermissionsAuthorizationHandler ، بر اساس نتیجهی تصمیم گیری در متد CanUserAccess کار میکند. کارکرد این متد را به دلخواه خودتان تغییر دهید. در حال حاضر این متد در نهایت بر اساس مقدار claim انتسابی، یعنی ناحیه/کنترلر/اکشن متد جاری:
var currentClaimValue = $"{area}:{controller}:{action}"