دوره آموزشی Entity FrameWork Core - قسمت پنجم

هر entity type در مدل شما دارای مجموعه ای از propertyها است که EF Core آنها را از پایگاه داده می خواند و می نویسد. اگر از یک پایگاه داده رابطه‌ای استفاده می‌کنید، propertyهای موجودیت به ستون‌های جدول نگاشت می‌شوند.گنجاندن و مستثنی کردن پراپرتی ها در مدل: طبق قرارداد، تمام پراپرتی های public با getter و setter در مدل گنجانده می شود.و برای حذف آنها از مدل EF Core به صورت زیر اقدام می کنیم : با استفاده از Data annotation :public class Blog { public int BlogId { get; set; } public string Url { get; set; } [NotMapped] public DateTime LoadedFromDatabase { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Ignore(b => b.LoadedFromDatabase); }نام ستون ها(Column names) : طبق قرارداد، هنگام استفاده از یک پایگاه داده رابطه‌ای، پراپرتی های موجودیت به ستون‌های جدول با همان نام پراپرتی نگاشت می‌شوند.اگر ترجیح می دهید ستون های خود را با نام های مختلف پیکربندی کنید، می توانید این کار را به صورت قطعه کد زیر انجام دهید:با استفاده از Data annotation :public class Blog { [Column(&quotblog_id&quot)] public int BlogId { get; set; } public string Url { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.BlogId) .HasColumnName(&quotblog_id&quot); }نوع داده ای ستون ها(Column data types) : هنگام استفاده از یک پایگاه داده رابطه ای،database provider یک نوع داده را بر اساس نوع دات نت پراپرتی انتخاب می کند. همچنین سایر metadataها، مانند حداکثر طول پیکربندی‌شده(maximum length)، اینکه آیا این پراپرتی بخشی از یک کلید اصلی است و غیره را نیز در نظر می‌گیرد.برای مثال، SQL Server پراپرتی های DateTime را به ستون‌های datetime2(7) و پراپرتی های string را به ستون‌های nvarchar(max) (یا به nvarchar(450) برای پراپرتی هایی که به عنوان کلید استفاده می‌شود)، نگاشت می‌کند.همچنین می‌توانید ستون‌های خود را طوری پیکربندی کنید که نوع داده دقیقی را برای یک ستون مشخص کنید. به عنوان مثال، کد زیر URL را به عنوان یک رشته غیر یونیکد با حداکثر طول 200 و Rating به صورت اعشاری با دقت 5 و مقیاس 2 پیکربندی می کند:با استفاده از Data annotation :public class Blog { public int BlogId { get; set; } [Column(TypeName = &quotvarchar(200)&quot)] public string Url { get; set; } [Column(TypeName = &quotdecimal(5, 2)&quot)] public decimal Rating { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>( eb => { eb.Property(b => b.Url).HasColumnType(&quotvarchar(200)&quot); eb.Property(b => b.Rating).HasColumnType(&quotdecimal(5, 2)&quot); }); } تعیین حداکثر طول Maximum length :حداکثر طول فقط برای انواع داده‌های آرایه، مانند string و []byte اعمال می‌شود.توجه داشته باشید Entity Framework هیچ گونه اعتبارسنجی حداکثر طول را قبل از ارسال داده به database provider انجام نمی دهد. در صورت لزوم اعتبار سنجی به عهده database provider یا data store است. به عنوان مثال، در یک data store مانند SQL Server، بیش از حداکثر طول مجاز منجر به exception می شود زیرا نوع داده ستون اجازه ذخیره داده های اضافی را نمی دهد.با استفاده از Data annotation :public class Blog { public int BlogId { get; set; } [MaxLength(500)] public string Url { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.Url) .HasMaxLength(500); }دقت و مقایس Precision and Scale : برخی از Data Typeها از جنبه های دقت و مقیاس پشتیبانی می کنند. اینها کنترل می کنند که چه مقادیری می توانند ذخیره شوند و چه مقدار فضای ذخیره برای ستون مورد نیاز است. اینکه کدام data type از دقت و مقیاس پشتیبانی می کند، به پایگاه داده وابسته است، اما در اکثر پایگاه های داده، انواع decimal و DateTime از این جنبه ها پشتیبانی می کنند. برای پراپرتی های از نوع decimal، دقت، حداکثر تعداد ارقام مورد نیاز برای بیان هر مقداری که ستون حاوی آن خواهد بود را تعیین می‌کند و مقیاس حداکثر تعداد ارقام اعشاری مورد نیاز را تعیین می‌کند. برای ویژگی‌های DateTime، دقت، حداکثر تعداد ارقام مورد نیاز برای بیان کسری از ثانیه را تعیین می‌کند و مقیاس استفاده نمی‌شود.بازهم توجه داشته باشید Entity Framework هیچ گونه اعتبارسنجی دقت یا مقیاسی را قبل از ارسال داده به database provider انجام نمی دهد. این بر عهده database provider یا data store است که در صورت لزوم اعتبار سنجی کند. به عنوان مثال در یک data store مانند SQL Server، ستونی از نوع داده datetime اجازه تنظیم دقت را نمی دهد، در حالی که datetime2 می تواند دقتی بین 0 تا 7 داشته باشد.در مثال زیر، پیکربندی پراپرتی Score برای داشتن دقت 14 و مقیاس 2 باعث ایجاد ستونی از نوع اعشاری (14,2) در SQL Server می شود و پیکربندی ویژگی LastUpdated برای داشتن دقت 3 باعث ایجاد ستونی از نوع datetime2 (3) می شود :با استفاده از Data annotation :توجه داشته باشید Data annotation برای پیکربندی دقت و مقیاس در EF Core 6.0 معرفی شد.public class Blog { public int BlogId { get; set; } [Precision(14, 2)] public decimal Score { get; set; } [Precision(3)] public DateTime LastUpdated { get; set; } }با استفاده از Fluent API :توجه داشته باشید Fluent API برای پیکربندی دقت و مقیاس در EF Core 5.0 معرفی شد.protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.Score) .HasPrecision(14, 2); modelBuilder.Entity<Blog>() .Property(b => b.LastUpdated) .HasPrecision(3); }مقیاس هرگز بدون تعریف دقت تعریف نمی شود، بنابراین Fluent API برای تعریف مقیاسHasPrecision(precision, scale) یونیکد Unicode : در برخی پایگاه های داده رابطه ای، انواع مختلفی برای نمایش داده های متنی یونیکد و غیریونیکد وجود دارد. به عنوان مثال، در SQL Server، nvarchar(x) برای نمایش داده های یونیکد در کدگذاری UTF-16 استفاده می شود، در حالی که varchar(x) برای نمایش داده های غیر Unicode استفاده می شود برای پایگاه های داده ای که از این مفهوم پشتیبانی نمی کنند، پیکربندی آن تاثیری ندارد.یونیکد و UTF-8SQL Server دارای دو نوع ستون برای ذخیره داده های متنی است: nvarchar(x) و varchar(x). اینها به طور سنتی برای نگهداری داده‌های یونیکد به ترتیب در کدگذاری UTF-16 و داده‌های غیریونیکد استفاده می‌شوند. SQL Server 2019 توانایی ذخیره داده‌های یونیکد UTF-8 را در ستون‌های varchar(x) معرفی کرد.متأسفانه، این در حال حاضر با ارائه دهنده SQL Server EF Core کار نمی کند. برای نگاشت یک پراپرتی از نوع string به ستون varchar(x)، از Fluent API یا Data Annotation معمولاً برای غیرفعال کردن یونیکد استفاده می شود (در پاراگراف بعدی به آن اشاره شده است). در حالی که این امر باعث می شود EF Core پارامترهای پایگاه داده را به گونه ای ارسال کند که با داده های UTF-8 ناسازگار است: DbType.AnsiString استفاده می شود (به معنی داده های غیر یونیکد است)، اما برای ارسال صحیح داده های یونیکد DbType.String مورد نیاز است. برای ذخیره داده های UTF-8 در SQL Server، مراحل زیر را دنبال کنید:1.تغییر پیکربندی collation در SQL Server به utf-8 ALTER DATABASE <database_name> COLLATE Persian_100_CI_ASSELECT CONVERT (nvarchar(128), DATABASEPROPERTYEX('database_name', 'collation'))2.Unicode را در پراپرتی غیرفعال نکنید. این باعث می شود EF Core یک ستون nvarchar(x) ایجاد کند.3.migration ها را ویرایش کنید و به جای آن به صورت دستی نوع ستون را روی varchar(x) تنظیم کنید.پراپرتی های text به طور پیش فرض به صورت یونیکد پیکربندی می شوند. می توانید یک ستون را به صورت غیر یونیکد به صورت زیر پیکربندی کنید:با استفاده از Data annotation :توجه داشته باشید Data annotation برای پیکربندی Unicode در EF Core 6.0 معرفی شد.public class Book{ public int Id { get; set; } public string Title { get; set; } [Unicode(false)] [MaxLength(22)] public string Isbn { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Book>() .Property(b => b.Isbn) .IsUnicode(false); }پراپرتی های اجباری یا اختیاری (Required and optional properties) : یک پراپرتی در صورتی اختیاری در نظر گرفته می شود که معتبر باشد که حاوی null باشد. اگر null یک مقدار معتبر برای تخصیص به یک ویژگی نباشد، به عنوان یک ویژگی اجباری در نظر گرفته می شود. هنگام نگاشت به یک relational database schema، پراپرتیهای اجباری به‌عنوان ستون‌های غیر قابل null و پراپرتی های اختیاری به‌عنوان ستون‌های nullable ایجاد می‌شوند.قراردادها (Conventions) :طبق قرارداد، یک ویژگی که نوع دات‌نت آن می‌تواند حاوی null باشد، به‌عنوان اختیاری پیکربندی می‌شود، در حالی که ویژگی‌هایی که نوع دات‌نت آن‌ها نمی‌تواند حاوی null باشد، در صورت نیاز پیکربندی می‌شوند. به عنوان مثال، تمام پراپرتی ها با انواع مقدار دات نت (int، decimal، bool، و غیره) بر اساس نیاز پیکربندی می شوند، و تمام پراپرتی ها با انواع مقدار nullable دات نت (?int?، decimal، ?bool، و غیره) به صورت اختیاری پیکربندی می شوند.سی شارپ 8 یک ویژگی جدید به نام nullable reference types (NRT) معرفی کرد که به reference typeها اجازه می دهد حاشیه نویسی شوند(annotated) و نشان می دهد که آیا معتبر است که آنها حاوی null باشند یا خیر.nullable reference typeها به روش زیر بر رفتار EF Core تأثیر می گذارد:اگر nullable reference typeها غیرفعال باشند، همه پراپرتی های دارای انواع مرجع دات‌نت بر اساس قرارداد به‌صورت اختیاری (string) پیکربندی می‌شوند.در فایل csproj.cs می توان آن را پیکربندی کنید. <Nullable>disable</Nullable>اگر nullable reference typeها فعال باشند، پراپرتی ها بر اساس C# nullability نوع NET آنها پیکربندی می شود: ?string به صورت اختیاری پیکربندی خواهد شد، اما string در صورت نیاز پیکربندی خواهد شد.در فایل csproj.cs می توان آن را پیکربندی کنید. <Nullable>enable</Nullable>مثال زیر یک نوع موجودیت را با property های اجباری و اختیاری نشان می دهد که ویژگی مرجع nullable غیرفعال و فعال است:درصورت فعال بودن NRT :public class Customer { public int Id { get; set; } public string FirstName { get; set; } // Required by convention public string LastName { get; set; } // Required by convention public string? MiddleName { get; set; } // Optional by convention // Note the following use of constructor binding, which avoids compiled warnings // for uninitialized non-nullable properties. public Customer(string firstName, string lastName, string? middleName = null) { FirstName = firstName; LastName = lastName; MiddleName = middleName; } }درصورت غیرفعال بودن NRT :public class CustomerWithoutNullableReferenceTypes { public int Id { get; set; } [Required] // Data annotations needed to configure as required public string FirstName { get; set; } [Required] public string LastName { get; set; } // Data annotations needed to configure as required public string MiddleName { get; set; } // Optional by convention }استفاده ازNRT توصیه می‌شود زیرا nullپذیری بیان شده در کد #C را به مدل EF Core و پایگاه داده منتقل می‌کند و استفاده از Fluent API یا Data Annotations را برای بیان یک مفهوم دوباره حذف می‌کند.مانند آنچه در ادامه خواهیم دید با NRT دیگر نیازی به آن نخواهد بود.یک ویژگی که طبق قرارداد اختیاری است را می توان به صورت زیر پیکربندی کرد:با استفاده از Data annotation :public class Blog { public int BlogId { get; set; } [Required] public string Url { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.Url) .IsRequired(); }ـColumn collations : یک collation را می توان بر روی ستون های متنی(text column) تعریف کرد و نحوه مقایسه و ترتیب آنها را تعیین کرد. به عنوان مثال، قطعه کد زیر یک ستون SQL Server را پیکربندی می‌کند تا به حروف بزرگ و کوچک حساس نباشد:modelBuilder.Entity<Customer>().Property(c => c.Name) .UseCollation(&quotSQL_Latin1_General_CP1_CI_AS&quot);اگر همه ستون‌های یک پایگاه داده نیاز به استفاده از یک دسته بندی خاص دارند، به جای آن، collation را در سطح پایگاه داده تعریف کنید.modelBuilder.UseCollation(&quotSQL_Latin1_General_CP1_CS_AS&quot);ـColumn comments : می توانید یک متن دلخواه تنظیم کنید که برروی ستون پایگاه داده تنظیم می شود و به شما امکان می دهد schema خود را در پایگاه داده مستند کنید:با استفاده از Data annotation :تنظیم COMMENT از طریق Data annotation در EF Core 5.0 معرفی شد.public class Blog { public int BlogId { get; set; } [Comment(&quotThe URL of the blog&quot)] public string Url { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .Property(b => b.Url) .HasComment(&quotThe URL of the blog&quot); }ـColumn order :این ویژگی در EF Core 6.0 معرفی شد.به‌طور پیش‌فرض هنگام ایجاد جدول با Migrations، EF Core ابتدا ستون‌های کلید اصلی را می گنجاند، سپس ... را می گنجاند. با این حال، می‌توانید ترتیب ستون متفاوتی را مشخص کنید:با استفاده از Data annotation :public class EntityBase { [Column(Order = 0)] public int Id { get; set; } } public class PersonBase : EntityBase { [Column(Order = 1)] public string FirstName { get; set; } [Column(Order = 2)] public string LastName { get; set; } } public class Employee : PersonBase { public string Department { get; set; } public decimal AnnualSalary { get; set; } }با استفاده از Fluent API :protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Employee>(x => { x.Property(b => b.Id) .HasColumnOrder(0); x.Property(b => b.FirstName) .HasColumnOrder(1); x.Property(b => b.LastName) .HasColumnOrder(2); }); }توجه داشته باشید که در حالت کلی، بیشتر پایگاه‌های داده تنها زمانی که جدول ایجاد می‌شود، از ستون‌های سفارشی پشتیبانی می‌کنند. این به این معنی است که از ویژگی نظم ستون نمی توان برای مرتب کردن مجدد ستون ها در جدول موجود استفاده کرد.بیشتر بخوانید : دوره آموزشی Entity FrameWork Core - قسمت ششمبیشتر بخوانید : دوره آموزشی Entity FrameWork Coreبیشتر بخوانید : نقشه راه توسعه دهندگان Asp.NET Corehttps://zarinp.al/farshidazizi