نظرات مطالب
اصول برنامه نویسی موازی درNET. نسخه 4 بخش اول - 2
در برنامه بالا ابتدا Taskها را Start کرده و سپس کد زیر اجرا می‌شود:
Console.WriteLine("Main method complete. Press enter to finish.");

سوال من اینه که چرا عبارت Main Method Complete.Press Enter to finish اول از همه در خروجی نمایش داده می‌شود؟!
مطالب
دستکاری کردن عملیات Sort در SQL Server
گاهی اوقات لازم می‌باشد، در زمان Sort نمودن یک ستون، تمایل داشته باشیم Range خاصی از مقادیر آن ستون در ابتدا قرار گیرد، و عملیات Sort پس از آن Range، اعمال گردد. برای انجام چنین کاری می‌توانیداز روش زیر استفاده نمایید:
برای درک مطلب مثالی می‌زنیم:
در ابتدا Script زیر را اجرا نمایید، که شامل یک جدول و درج چند رکورد در آن می‌باشد:
Create Table TestSort
(ID  int identity(1,1),
Name nvarchar(30),
Color nvarchar(15)
)
درج رکورد:
Insert into TestSort (Name,color)
Values  ('Adjustable Race',null)
       ,('Bearing Ball',null)
       ,('Headset Ball Bearings',null)
       ,('LL Crankarm','Black')
       ,('ML Crankarm','Black')
       ,('Chainring','Black')
       ,('Front Derailleur Cage','Silver')
       ,('Front Derailleur Linkage','Silver')
       ,('Lock Ring','Silver')
       ,('HL Road Frame - Red, 62','Red')
       ,('HL Road Frame - Red, 48','Red')
       ,('LL Road Frame - Red, 44','Red')
       ,('Full-Finger Gloves, M','RED')
       ,('Road-550-W Yellow, 38','Yellow')
       ,('Road-550-W Yellow, 40','Yellow')
       ,('Road-550-W Yellow, 42','Yellow')
       ,('Classic Vest, S','Blue')
       ,('Classic Vest, M','Blue')
       ,('Classic Vest, L','Blue')
در جدول TestSort ستونی به نام Color داریم، که نام رنگها در آن درج شده است، رنگهایی همچون  Black ، Silver،Blue،Yellow و Red
درابتدا روی ستون Color بصورت نرمال Sort صعودی انجام می‌دهیم:
Select t.ID,t.Name,t.Color from TestSort as t order by t.Color
خروجی:

مطابق شکل،زمانی که Sort بصورت صعودی است، رکوردهایی را که ستون Color آنها دارای مقدار Null می‌باشند، در ابتدای جدول قرار گرفته اند.
در ادامه می‌خواهیم، عملیات Sort ی را روی ستون Color انجام دهیم، بطوریکه تمامی رکوردهایی که مقدار ستون Color شان Red است، در ابتدای جدول قرار گیرد، و پس از آن عملیات سورت روی رنگهای دیگر اعمال شود.
برای انجام چنین کاری کافیست Script زیر را اجرا نمایید:
Select t.ID,t.Name,t.Color from TestSort as t 
Where t.color is not null
order by  Case t.Color
When 'Red' Then Null
Else t.color 
End;
خروجی:

چطور اینکار انجام شد:
اگر بهScript ذکر شده دقت نمایید، در قسمت Order by اشاره کردیم، تمام مقادیر Red در ستون Color به Null تغییر کنند، بنابراین SQL Server، در ابتدا مقادیر Red را یافته آنها را به Null تغییر و سپس عملیات سورت را انجام می‌دهد،
برای درک بیشتر عملیاتی را که SQL Server پشت صحنه انجام می‌دهد با Script  زیر قابل شبیه سازی میباشد:
Select * into Simulation from 
(Select t.ID,t.Name,t.Color,
Case t.Color
When 'Red' Then Null
Else t.color 
End RedNull
from TestSort as t 
Where t.color is not null) A
سپس روی ستون RedNull از جدول Simulation سورت انجام می‌دهیم:
Select * from Simulation order by Rednull
خروجی:

مطابق شکل،پشت صحنه SQL Server چنین کاری را انجام می‌دهد، و در زمان نمایش ستون RedNull پنهان یا حذف می‌گردد، و ستون Color، Name و ID نمایش داده می‌شود.
امیدوارم مفید واقع شده باشد.
مطالب
امکان استفاده از یک هارد SSD بجای RAM در SQL Server 2014
Buffer Pool یکی از مصرف کنندگان اصلی حافظه در SQL Server است. برای مثال زمانیکه اطلاعاتی را از بانک اطلاعاتی دریافت می‌کنید، این داده‌ها در Buffer Pool کش می‌شوند. همچنین SQL Server اطلاعات کلیه Execution Plans را نیز در Plan Cache که جزئی از Buffer Pool است، برای استفاده‌ی مجدد نگهداری می‌کند. هر چقدر حافظه‌ی فیزیکی سرور شما بیشتر باشد، مقدار Buffer Pool نیز به همین میزان افزایش خواهد یافت که البته حداکثر آن‌را می‌توان در تنظیمات حافظه‌ی سرور محدود کرد (Max Server Memory setting).
در دنیای واقعی میزان حافظه‌ی فیزیکی سرورها محدود است. در SQL Server 2014 راه حلی برای این مشکل تحت عنوان Buffer Pool Extensions ارائه شده‌است که محل قرارگیری آن‌را در تصویر ذیل مشاهده می‌کنید:


Buffer Pool Extensions از یک فایل ساده که به آن Extension File نیز گفته می‌شود، تشکیل شده‌است و امکان ذخیره سازی آن بر روی هاردهای سریعی مانند SSD Driveها میسر است. این فایل، ساختاری را همانند page file، در سیستم عامل ویندوز دارد. در این حالت بجای اضافه کردن RAM بیشتر به سرور، یک Extension File را می‌توان بکار گرفت. هر زمان که Buffer Pool اصلی تحت فشار قرار گیرد (به میزان حافظه‌ای بیش از حافظه‌ی فیزیکی سرور نیاز باشد)، از این افزونه‌ی فایلی استفاده خواهد شد.
اطلاعات جزئیات Buffer Pool را توسط کوئری ذیل می‌توان بدست آورد:
 Select * from sys.dm_os_buffer_descriptors


نحوه‌ی فعال سازی و تنظیم Buffer Pool Extensions

قبل از هر کاری بهتر است وضعیت افزونه‌ی Buffer pool را بررسی کرد:
 select * from sys.dm_os_buffer_pool_extension_configuration


همانطور که ملاحظه می‌کنید، در حالت پیش فرض غیرفعال است.
سپس یک فایل یک گیگابایتی را به عنوان افزونه‌ی Buffer pool ایجاد می‌کنیم.
 ALTER SERVER CONFIGURATION
SET BUFFER POOL EXTENSION ON
 (FILENAME = 'd:\BufferPoolExt.BPE', SIZE = 1GB);
توصیه شده‌است که این فایل را در یک درایور پر سرعت SSD قرار دهید؛ ولی محدودیتی از لحاظ محل قرارگیری ندارد (هر چند به نظر فقط در حالتیکه از SSD Drive استفاده شود واقعا کار می‌کند).
اینبار اگر کوئری اول را اجرا کنیم، چنین خروجی قابل مشاهده است:


این فایل به صورت خودکار در حین ری‌استارت یا خاموش شدن سرور، حذف شده و با راه اندازی مجدد آن، باز تولید خواهد شد.


تغییر اندازه‌ی افزونه‌ی Buffer pool

اگر سعی کنیم، یک گیگابایت را مثلا به 10 گیگابایت افزایش دهیم:
 ALTER SERVER CONFIGURATION
SET BUFFER POOL EXTENSION ON
 (FILENAME = 'd:\BufferPoolExt.BPE', SIZE = 10GB);
با خطای ذیل مواجه خواهیم شد:
 Could not change the value of the 'BPoolExtensionPath' property
برای رفع این مشکل، ابتدا باید افزونه‌ی Buffer pool را غیرفعال کرد:
 ALTER SERVER CONFIGURATION
SET BUFFER POOL EXTENSION OFF
سپس می‌توان مجددا اندازه و یا مسیر دیگری را مشخص کرد. بهتر است اندازه‌ی این فایل را حدود 16 برابر حداکثر میزان حافظه‌ی سرور (Max Server Memory) تعیین کنید.
همچنین توصیه شده‌است که پس از غیرفعال کردن این افزونه، بهتر است یکبار instance جاری را ری استارت کنید.


چه زمانی بهتر است از افزونه‌ی Buffer pool استفاده شود؟
در محیط‌های read-heavy OLTP، استفاده از یک چنین افزونه‌ای می‌تواند میزان کارآیی و پاسخگویی سیستم را به شدت افزایش دهد (تا 50 درصد).


سؤال: آیا غیرفعال کردن افزونه‌ی Buffer pool سبب از دست رفتن اطلاعات می‌شود؟
خیر. BPE، تنها clean pages را در خود ذخیره می‌کند؛ یعنی تنها اطلاعاتی که Commit شده‌اند در آن حضور خواهند داشت و در این حالت حذف آن یا ری استارت کردن سرور، سبب از دست رفتن اطلاعات نخواهند شد.


برای مطالعه بیشتر

Buffer Pool Extension
SQL Server 2014 Buffer Pool Extensions
Do you require a SSD to use the Buffer Pool Extension feature in SQL Server 2014
Buffer Pool Extensions in SQL Server 2014
SQL Server 2014 – Buffer Pool Extension
مطالب
کوئری نویسی در EF Core - قسمت چهارم - اعمال تغییرات در داده‌ها
نوع دیگری از کوئری‌های پرکاربرد، کوئری‌های مرتبط با ثبت، حذف و ویرایش اطلاعات هستند که در این قسمت آن‌ها را بررسی می‌کنیم. البته این مثال‌ها از یکسری مثال کوئری‌های مرتبط با PostgreSQL، به EF-Core تبدیل و ترجمه شده‌اند. به همین جهت تطابق یک به یکی در اینجا وجود نداشته و روش شیءگرایی که ORMها برای کار با داده‌ها بکار می‌گیرند، الزاما کوئری‌های یکسانی را تولید نمی‌کنند؛ اما نتیجه‌ی نهایی آن‌ها یکی است.


مثال 1: افزودن ردیفی به یک جدول بانک اطلاعاتی

امکان و ویژگی جدیدی به نام SPA قرار است به مجموعه اضافه شود. اطلاعات آن که شامل موارد ذیل است، نیاز است به جدول facilities اضافه شود:
facid: 9, Name: 'Spa', membercost: 20, guestcost: 30, initialoutlay: 100000, monthlymaintenance: 800.
اگر قرار باشد چنین کاری را توسط دستورات SQL انجام دهیم، عموما به یکی از دو روش زیر عمل می‌شود:
insert into facilities
    (facid, name, membercost, guestcost, initialoutlay, monthlymaintenance)
    values (9, 'Spa', 20, 30, 100000, 800);
-- OR
insert into facilities values (9, 'Spa', 20, 30, 100000, 800);
که معادل آن در EF-Core به صورت زیر است:
context.Facilities.Add(new Facility
                {
                    Name = "Spa",
                    MemberCost = 20,
                    GuestCost = 30,
                    InitialOutlay = 100000,
                    MonthlyMaintenance = 800
                });
context.SaveChanges();
ابتدا وهله‌ای از موجودیت Facility به DbSet مرتبط با آن اضافه می‌شود و در آخر SaveChanges فراخوانی خواهد شد تا کوئری متناظر با آن ساخته شده و به بانک اطلاعاتی اعمال شود.


مثال 2: افزودن چندین ردیف از اطلاعات به یک جدول بانک اطلاعاتی

همان مثال قبلی را درنظر بگیرید. اینبار می‌خواهیم دو ردیف را به آن اضافه کنیم:
facid: 9, Name: 'Spa', membercost: 20, guestcost: 30, initialoutlay: 100000, monthlymaintenance: 800.
facid: 10, Name: 'Squash Court 2', membercost: 3.5, guestcost: 17.5, initialoutlay: 5000, monthlymaintenance: 80.
معادل کدهای SQL چنین عملی، می‌تواند کوئری زیر باشد:
insert into facilities
    (facid, name, membercost, guestcost, initialoutlay, monthlymaintenance)
    values
        (9, 'Spa', 20, 30, 100000, 800),
        (10, 'Squash Court 2', 3.5, 17.5, 5000, 80);
و روش انجام آن در EF-Core تفاوتی با مثال قبلی ندارد:
context.Facilities.Add(new Facility
                {
                    Name = "Spa",
                    MemberCost = 20,
                    GuestCost = 30,
                    InitialOutlay = 100000,
                    MonthlyMaintenance = 800
                });

context.Facilities.Add(new Facility
                {
                    Name = "Squash Court 2",
                    MemberCost = 3.5M,
                    GuestCost = 17.5M,
                    InitialOutlay = 5000,
                    MonthlyMaintenance = 80
                });
context.SaveChanges();
در اینجا می‌توان به هر تعدادی که نیاز است وهله‌های جدیدی از Facility را به context افزودن و سپس SaveChanges را در آخر کار فراخوانی کرد. اینکه EF-Core دستورات insert معادل را به یکباره و یا به صورت مجزایی اجرا می‌کند، به مفهومی به نام batching مرتبط است. اطلاعات بیشتر


مثال 3: افزودن اطلاعات محاسبه شده به یک جدول بانک اطلاعاتی

اطلاعات زیر را درنظر بگیرید:
Name: 'Spa', membercost: 20, guestcost: 30, initialoutlay: 100000, monthlymaintenance: 800.
در مثال اصلی عنوان شده که می‌خواهیم ID آن‌را یکی بیشتر از ردیف قبلی ثبت کنیم. در EF-Core و تنظیمات موجودیت‌هایی که داریم:
namespace EFCorePgExercises.Entities
{
    public class FacilityConfiguration : IEntityTypeConfiguration<Facility>
    {
        public void Configure(EntityTypeBuilder<Facility> builder)
        {
            builder.HasKey(facility => facility.FacId);
            builder.Property(facility => facility.FacId).IsRequired().UseIdentityColumn(seed: 0, increment: 1);
چون ستون ID به صورت خود افزایش یابنده معرفی شده‌است که از صفر شروع می‌شود و به صورت خودکار توسط بانک اطلاعاتی یکی یکی افزایش می‌یابد، نیازی به حل این مساله وجود ندارد. چون ID افزایش یابنده را خود بانک اطلاعاتی محاسبه می‌کند. همچنین به همین علت در مثال‌های قبلی نیز ID را به صورت مستقیمی مقدار دهی نکردیم. اگر نیاز به انجام چنین کاری وجود داشته باشد (ذکر صریح ID خاصی)، با توجه به طراحی بانک اطلاعاتی حاصل از این تنظیمات:
CREATE TABLE [dbo].[Facilities](
[FacId] [int] IDENTITY(0,1) NOT NULL,
--- ...
 CONSTRAINT [PK_Facilities] PRIMARY KEY CLUSTERED 
(
[FacId] ASC
);
باید مانند مثال ثبت اطلاعات اولیه‌ی در بانک اطلاعاتی در قسمت اول این سری، از روش SET IDENTITY_INSERT Facilities ON استفاده کرد تا بتوان مجوز ثبت دستی این ID کنترل شده‌ی توسط بانک اطلاعاتی را پیدا کرد.


مثال 4: به روز رسانی اطلاعاتی از پیش موجود

می‌خواهیم مقدار InitialOutlay دومین زمین تنیس را از 8000 موجود به 10000 تغییر دهیم. با توجه به اینکه ID این زمین شماره 1 است، در حالت متداول SQL نویسی، به کدهای زیر خواهیم رسید:
update facilities
    set initialoutlay = 10000
    where facid = 1;
که معادل EF-Core آن به صورت زیر است:
var facility1 = context.Facilities.Find(1);
facility1.InitialOutlay = 10000;
context.SaveChanges();
این دستورات کوئری مشابهی را تولید نمی‌کنند. ابتدا موجودیت متناظر با ID شماره‌ی 1 از بانک اطلاعاتی واکشی شده و سپس مقدار خاصیتی از آن تغییر کرده‌است. در آخر SaveChanges بر روی آن فراخوانی می‌شود.
EF-Core برای اینکه بتواند تغییرات اعمالی به یک شیء را محاسبه کند، نیاز دارد تا آن شیء را به نحوی در سیستم change tracking خودش موجود داشته باشد. هر نوع کوئری که در EF-Core نوشته می‌شود و به همراه متد AsNoTracking نیست، خروجی تک تک اشیاء حاصل از آن پیش از ارائه‌ی نهایی، وارد سیستم change tracking آن می‌شوند. یعنی اگر مقادیر خواص این اشیاء را تغییر داده و بر روی آن‌ها SaveChanges را فراخوانی کنیم، کوئری‌های متناظر با به روز رسانی تنها این خواص تغییر یافته به صورت خودکار محاسبه شده و به بانک اطلاعاتی اعمال می‌شوند.
فراخوانی متد AsNoTracking بر روی کوئری‌های EF-Core، تولید پروکسی‌های change tracking را غیرفعال می‌کند. یک چنین کوئری‌هایی صرفا کاربردهای گزارشگیری فقط خواندنی را دارند و نسبت به کوئری‌های معمولی، سریعتر و با مصرف حافظه‌ی کمتری هستند. بنابراین نتایج حاصل از کوئری‌های متداول EF-Core، به صورت پیش‌فرض (یعنی بدون داشتن متد AsNoTracking) هم خواندنی و هم نوشتنی با قابلیت اعمال به بانک اطلاعاتی هستند.


مثال 5: به روز رسانی چندین ردیف و چندین جدول در یک زمان

می‌خواهیم مقادیر MemberCost  و GuestCost دو زمین تنیس را به 6 و 30 تغییر دهیم. روش انجام اینکار با SQL نویسی معمولی به صورت زیر است:
update cd.facilities
    set
        membercost = 6,
        guestcost = 30
    where facid in (0,1);
اما همانطور که عنوان شد در EF-Core ابتدا باید اشیاء متناظر با این زمین‌های تنیس را در سیستم change tacking موجود داشت و سپس نسبت به ویرایش آن‌ها اقدام نمود. یکی از روش‌های وارد کردن اشیاء به سیستم change tacking، نوشتن کوئری‌های بدون متد AsNoTracking است و سپس به روز رسانی نتایج حاصل از آن‌ها که اکنون توسط پروکسی‌های change tracking محصور شده‌اند و در آخر فراخوانی SaveChanges بر روی context جاری:
int[] facIds = { 0, 1 };
var tennisCourts = context.Facilities.Where(x => facIds.Contains(x.FacId)).ToList();
foreach (var tennisCourt in tennisCourts)
{
     tennisCourt.MemberCost = 6;
     tennisCourt.GuestCost = 30;
}

context.SaveChanges();


مثال 6: به روز رسانی اطلاعات یک ردیف بر اساس اطلاعات ردیفی دیگر

می‌خواهیم هزینه‌ی دومین زمین تنیس را به نحوی ویرایش کنیم که 10 درصد بیشتر از هزینه‌ی اولین زمین تنیس باشد.
روش پیشنهادی انجام اینکار با SQL نویسی مستقیم به صورت زیر است:
update cd.facilities facs
    set
        membercost = (select membercost * 1.1 from cd.facilities where facid = 0),
        guestcost = (select guestcost * 1.1 from cd.facilities where facid = 0)
    where facs.facid = 1;
در EF-Core می‌توان اشیاء متناظر با این دو زمین تنیس را ابتدا واکشی کرد، سپس تغییر داد و در نهایت ذخیره کرد:
var fac0 = context.Facilities.Where(x => x.FacId == 0).First();
var fac1 = context.Facilities.Where(x => x.FacId == 1).First();
fac1.MemberCost = fac0.MemberCost * 1.1M;
fac1.GuestCost = fac0.GuestCost * 1.1M;

context.SaveChanges();


مثال 7: حذف تمام اطلاعات یک جدول

می‌خواهیم تمام اطلاعات جدول bookings را حذف کنیم.
روش انجام اینکار با SQL نویسی مستقیم به صورت زیر است:
delete from bookings
اما ... این تک کوئری، معادلی را در EF-Core استاندارد ندارد. چون EF-Core نیاز دارد مدام تمام اطلاعات ویرایشی/حذف و به روز رسانی را در context و سیستم change tracking خودش داشته باشد، ابتدا باید توسط یک کوئری لیست اشیاء مدنظر را تهیه کرد و سپس آن‌را به متد RemoveRange معرفی کرد تا حذف تک تک آن‌ها که شامل صدها کوئری خواهد شد، صورت گیرد:
context.Bookings.RemoveRange(context.Bookings.ToList());
context.SaveChanges();
این روش سریع نیست؛ اما کار می‌کند!
البته هستند کتابخانه‌های ثالثی (^ و ^) که انجام به روز رسانی دسته‌ای و یا حذف دسته‌ای از رکوردها را تنها با یک کوئری SQL میسر می‌کنند؛ اما ... هنوز جزئی از EF استاندارد نشده‌اند و مهم‌ترین مشکل احتمالی این روش‌ها، همگام نبودن context و سیستم change tacking، با نتیجه‌ی حاصل از به روز رسانی یکباره‌ی صدها ردیف است.



مثال 8: حذف یک کاربر از جدول کاربران

می‌خواهیم کاربر شماره‌ی 37 را حذف کنیم.
روش انجام اینکار با SQL نویسی به صورت زیر است:
delete from members where memid = 37;
و در EF-Core برای انجام اینکار می‌توان ابتدا شیء متناظر با کاربر 37 را از طریق یک کوئری به سیستم change tracking وارد کرد و سپس آن‌را حذف نمود:
var mem37 = context.Members.Where(x => x.MemId == 37).First();
context.Members.Remove(mem37);

context.SaveChanges();

یک نکته: امکان ساده‌تر حذف یک ردیف با داشتن ID آن

کوئری گرفتن از بانک اطلاعاتی، یک روش وارد کردن شیءای به context و سیستم change tacking آن است. در این حالت عموما فرض بر این است که ID شیء را نمی‌دانیم. اما اگر این ID مانند مثال جاری از پیش مشخص بود، نیازی نیست تا ابتدا از بانک اطلاعاتی کوئری گرفت و کل شیء را در حافظه وارد کرد. در این حالت خاص می‌توان با استفاده از روش زیر، این ID را وارد سیستم tracking کرد و سپس حالت آن‌را به Deleted تغییر داد و در آخر آن‌را ذخیره کرد:
var entry = context.Entry(new Member { MemId = 37 });
entry.State = EntityState.Deleted;
context.SaveChanges();
در کدهای فوق می‌توان سطر entry.State = EntityState.Deleted را با context.Remove(entry) نیز جایگزین کرد و هر دو به یک معنا هستند.
روش فوق چنین کوئری‌هایی را ایجاد می‌کند:
SET NOCOUNT ON;
DELETE FROM [Members]
WHERE [MemId] = @p0;
SELECT @@ROWCOUNT;


مثال 9: حذف بر اساس یک sub-query

می‌خواهیم تمام کاربرانی را که هیچگاه رزروی را انجام نداده‌اند، حذف کنیم.
این مورد نیز با SQL نویسی مستقیم نیز توسط یک کوئری دسته‌ای قابل انجام است:
delete from members where memid not in (select memid from cd.bookings);
اما همانطور که عنوان شد، EF-Core این نوع اعمال ویرایش دسته‌ای را در طی یک تک کوئری پشتیبانی نمی‌کند. به همین جهت ابتدا آن‌ها را توسط یک کوئری به context وارد کرده و سپس حذف می‌کنیم:
var mems = context.Members.Where(x =>
  !context.Bookings.Select(x => x.MemId).Contains(x.MemId)).ToList();
context.Members.RemoveRange(mems);

context.SaveChanges();


کدهای کامل این قسمت را در اینجا می‌توانید مشاهده کنید.
نظرات مطالب
EF Code First #1
1 و 3 - در انتهای بحث عرض کردم در قسمت‌های بعدی خیلی از موارد رو توضیح خواهم داد. این قسمت اول و فقط یک «مقدمه» ابتدایی بود.
2 - EF با بانک‌های اطلاعاتی NoSQL کار نمی‌کند. ضمنا هستند بانک‌های اطلاعاتی NoSQL ایی که برای دات نت نوشته‌ شده‌اند و از همان روز اول با کلاس‌ها و LINQ کار می‌کنید مانند RavenDB . طراحی فوق ‌العاده‌ای داره (^).
استفاده از EF Code first با سایر بانک‌های اطلاعاتی بجز مشتقات SQL Server نیز میسر است. برای آن‌ها نیاز به پروایدر مخصوص وجود دارد؛ مثلا: (^)
مطالب
لینک‌های هفته‌ی اول بهمن

وبلاگ‌ها ، سایت‌ها و مقالات ایرانی (داخل و خارج از ایران)

Visual Studio


ASP. Net


طراحی و توسعه وب


اس‌کیوال سرور


سی شارپ


عمومی دات نت


ویندوز


مسایل اجتماعی و انسانی برنامه نویسی


متفرقه

اشتراک‌ها
نگاهی به نوع‌های جدید DateOnly و TimeOnly در NET 6.

In .NET 6 (preview 4), two long-awaited types have been introduced as part of the core library. DateOnly and TimeOnly allow developers to represent either the date or time portion of a DateTime. These two new types are structs (value types) and may be used when your code deals with date or time concepts independently. Both types can be found in the System namespace. Using these new types may align well with how databases allow similar data to be represented. Specifically, these types align well with the SQL Server date and time data types. 

نگاهی به نوع‌های جدید DateOnly و TimeOnly در NET 6.