var profiles = typeof(UserMappingProfile).Assembly.GetTypes().Where(types => typeof(Profile).IsAssignableFrom(types)).Select(types => (Profile)Activator.CreateInstance(types)); services.AddAutoMapper(cfg => { foreach (var profile in profiles) cfg.AddProfile(profile); });
EF Code First #10
var changedEntityNames = ctx.ChangeTracker .Entries() .Where(x => x.State == EntityState.Added || x.State == EntityState.Modified || x.State == EntityState.Deleted) .Select(x => ObjectContext.GetObjectType(x.Entity.GetType()).FullName) .Distinct() .ToList();
public async Task<IHttpActionResult> LoginUserAsync(LoginUserBindingModel model) { var requestParams = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("grant_type", "password"), new KeyValuePair<string, string>("username", model.Username), new KeyValuePair<string, string>("password", model.Password) }; var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams); using (var client = new HttpClient()) { client.BaseAddress = new Uri("http://localhost:9577/"); client.DefaultRequestHeaders.Accept.Clear(); // client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); var response = await client.PostAsync("/login", requestParamsFormUrlEncoded); if (response.StatusCode == HttpStatusCode.OK) { var responseString = await response.Content.ReadAsStringAsync(); var jsSerializer = new JavaScriptSerializer(); var responseData = jsSerializer.Deserialize<Dictionary<string, string>>(responseString); return Content(HttpStatusCode.OK, responseData); } else { return BadRequest(response.ToString()); } } }
Column Store Index یکی از ویژگیهای جدید SQL Server 2012 می باشد، که کارایی Query های قایل اجرا روی دیتابیسهای با حجم داده ای بسیار بالا را (که اصطلاحا به آنها Data Warehouse یا انبار داده گویند)، چندین برابر بهبود بخشیده است.
قبل از توضیح در مورد Column Store مختصری در مورد نحوه ذخیره سازی دادهها در SQL Server می پردازیم. میتوان گفت در SQL Server دو روش ذخیره سازی وجود دارد،یکی بصورت ردیفی که اصطلاحا به آن Row Storeیا Row-Wise گویند، و دیگری بصورت ستونی که اصطلاحا به آن Column Store گویند.
در روش ذخیره سازی Row Store، مقادیر ستونها در یک سطر بصورت متوالی ذخیره میشوند، در این روش ذخیره سازی از ساختار B-Tree یا Heap استفاده میشود.
یادآوری: در ساختار B-Tree، یک گره Root وجود دارد، و گره بعد از Root گره ای است که آدرس گره راست بعدی و آدرس گره چپ بعدی را در خود نگه میدارد.
شکل زیر نمای یک درخت B-Tree میباشد:
جهت کسب اطلاعات بیشتر درمورد ساختار B-Tree
یادآوری: وقتی در یک جدول، ایندکسی از نوع Clustered ایجاد نماییم، SQL Server، در ابتدا یک کپی از جدول ایجاد و دادههای جدول را از نو مرتب مینماید، و ساختار صفحه ریشه و دیگر صفحات را ایجاد میکند و سپس جدول اصلی را حذف مینماید. به جدولی که Clustered Index ندارد، اصطلاحا Heap گویند.
برخلاف ذخیره سازی Row Store، در ذخیره سازی Column Store، دادهها بصورت ستونی ذخیره میشوند،در این روش داده ها، فشرده سازی میشوند و اینکار باعث میشود،در زمان درخواست یک Query، نیاز به Disk I/o به حداقل برسد، در نتیجه، زمان و سرعت پاسخگویی به پرس و جوها بسیار افزایش مییابد.
شکل زیر نحوه ذخیره سازی داده ها،بصورت Row Store را نمایش میدهد:
شکل بالا ذخیره سازی داده ها، در ساختار B-Tree یا Heap را نمایش میدهد، در شکل فوق یک جدول چهار ستونی با N سطر (Row) در نظر گرفته شده است.بطوریکه ستونهای هر Row بطور متوالی در یک صفحه (Page) یکسان ذخیره میشوند.
شکل زیر نحوه ذخیره سازی داده ها،بصورت Column Store را نمایش میدهد:
مطابق شکل،ستونهای مربوط به هر Row،همگی در یک صفحه (Page) یکسان ذخیره شده اند. به عنوان مثال ستون C1 که مربوط به سطر اول (Row1) میباشد، با ستون C1 که مربوط به سطر دوم (Row2) میباشد، در یک ستون و در یک صفحه (Page1) ذخیره شده اند، و الی آخر ...
سئوال: یکبار دیگر به هردو شکل با دقت نگاهی بیاندازید، عمده تفاوت آنها در چیست؟
جواب: درست حدس زدید، تفاوت بارز بین دو روش Column Store و Row Store در نحوه ذخیره سازی دادهها میباشد. بطور مثال، فرض کنید،در روش ذخیره سازی Row Store، به دنبال مقادیری از ستون C2 میباشید، SQL Server میبایست کل رکوردهای جدول (منظور همه Rowها در همه Page ها)را Scan نماید، تا مقادیر مربوط به ستون C2 را بدست آورد.درحالیکه در روش ذخیره سازی Column Store، جهت یافتن مقادیر ستون C2، نیازی به Scan نمودن کل جدول نیست،بلکه SQL Server فقط به Scan نمودن ستون دوم (C2) یا Page2 بسنده مینماید.همین امر باعث افزایش چندین برابری، زمان پاسخگویی به هر Query میشود.
سئوال: در روش ذخیره سازی Column Store، چگونه مصرف حافظه بهینه میشود؟
جواب: واضح است، که در روش SQL Server، Row Store مجبور است، برای بدست آوردن دادههای مورد نظرتان،کل اطلاعات جدول را وارد حافظه نماید(اطلاعات اضافه ای که به هیچ وجه بدرد، نتیجه پرس و جوی شما نمیخورد)، و شروع به Scan دادههای مد نظر شما مینماید.بطوریکه در روش SQL Server، Column Store، فقط ستون دادههای مورد پرس و جو را در حافظه قرار میدهد.(در واقع فقط داده هایی را در حافظه قرار میدهد، که شما به آن نیاز دارید)،بنابراین،طبیعی است که در روش Column Store مقدار حافظه کمتری نسبت به روش Row Store در هنگام اجرای Query استفاده میشود. به عبارت دیگر میتوان گفت که در روش Column Store به دلیل، به حداقل رساندن استفاده از Disk I/o سرعت و زمان پاسخگویی به پرس و جوها چندین برابر میشود.
برای درک بیشتر Row Store و Column Store مثالی میزنیم:
فرض کنید،قصد بدست آوردن ستونهای C1 و C2 از جدول A را داریم، بنابراین خواهیم داشت:
Select C1, C2 from A
روش Row Store:
در این روش همه صفحات دیسک (مربوط به جدول A) درون حافظه قرار داده میشود، یعنی علاوه بر ستونهای C1 و C2، اطلاعات مربوط به ستونهای C3 و C4 نیز درون حافظه قرار میگیرد،بطوریکه مقادیر ستونهای C3 و C4 به هیچ وجه مورد قبول ما نیست، و در خروجی پرس و جوی ما تاثیری ندارد، و فقط بی جهت حافظه اشغال مینماید.
روش Column Store:
در این روش فقط صفحات مروبط به ستون C1 و C2 در حافظه قرار میگیرد.(منظور Page1 و Page2 میباشد) بنابراین فقط اطلاعات مورد نیاز در خروجی، در حافظه قرار میگیرد.
- از دیگر مزایای استفاده از روش Column Store، فشرده سازی داده میباشد،برای درک بیشتر توضیح میدهم:
چه موقع میتوانیم از Column Store استفاده نماییم:
در تعریف Column Store گفته بودم، روش فوق، جهت بهبود بخشیدن به زمان و سرعت پاسخگویی به Queryهای اجرا شده روی دیتابیسهای با حجم داده ای بسیار بالا(Data Warehouse ) میباشد، به بیان سادهتر Column Store را روی دیتابیسهای offline یا دیتابیسهایی که صرفا جهت گزارش گیری مورد استفاده قرار میگیرند، تنظیم مینمایند.در واقع با تنظیم Column Store Index روی Databaseهای بزرگ مانند Databaseهای بانکها که حجم داده ای میلیونی در جداول آنها وجود دارد، سرعت پاسخگویی Query ها، چندین برابر افزایش مییابد.
- در یک جدول میتوانید، هم Column Store Index داشته باشید و هم یک Row Store Index (منظور یک Clustered Index می باشد)
- Syntax برای ایجاد Column Store Index به شرح ذیل میباشد:
CREATE [ NONCLUSTERED ] COLUMNSTORE INDEX index_name ON <object> ( column [ ,...n ] ) [ WITH ( <column_index_option> [ ,...n ] ) ] [ ON { { partition_scheme_name ( column_name ) } | filegroup_name | "default" } ] [ ; ] <object> ::= { [database_name. [schema_name ] . | schema_name . ] table_name { <column_index_option> ::= { DROP_EXISTING = { ON | OFF } | MAXDOP = max_degree_of_parallelism }
- یک Column Store Index میبایست از نوع NONCLUSTERED باشد.
CREATE NONCLUSTERED COLUMNSTORE INDEX [IX_MyFirstName_ColumnStore] ON [Test] (Firstname)
- زمانی که در یک جدول، یک Column Store Index ایجاد نماییم، جدول ما در حالت Read-only قرار میگیرد، بطوریکه از آن پس اختیار Delete،Update و Insert روی جدول فوق را نخواهیم داشت. برای اینکه بتوانید عملیات Insert، Update یا Delete را انجام دهید، میبایست Column Store Index جدول مربوطه را Disable نمایید، و برای فعال نمودن Column Store Index، میبایست آن را Rebuild نمایید، با کلیک راست روی ایندکس ایجاد شده در SQL Server2012 موارد Disable و Rebuild قابل مشاهده میباشد.
ALTER INDEX [IX_MyFirstName_ColumnStore] ON [Test] DISABLE ALTER INDEX [IX_MyFirstName_ColumnStore] ON [Test] Rebuild
- بیشتر از یک Column Store Index نمیتوانید روی یک جدول ایجاد نمایید.
- در صورتی که تمایل داشته باشید بوسیله Alter ، نوع فیلدی (Type)، را که Column Store Index روی آنها اعمال گردیده است، تغییر دهید، در ابتدا میبایست Column Store Index، خود را Drop یا حذف نمایید، سپس عملیات Alter را اعمال کنید، در غیر اینصورت با خطای SQL Server مواجه میشوید.
- یک Column Store Index میتواند روی 1024 ستون در یک جدول اعمال گردد.
- یک Column Store Index نمی توانند، Unique باشد و نمیتوان از آن به عنوان Primary Key یا Foreign Key استفاده نمود.
- در هم اکنون: هاست سرور SQL در ویندوز و استفاده از آن در کلاینتهای لینوکسی با SQL Client
- و یا اگر از یک ORM استفاده میکنید (مانند EF یا NH)، چون در این حالت کدهای شما وابستگی به بانک اطلاعاتی مورد استفاده ندارند، سوئیچ کردن به بانکهای اطلاعاتی دیگر، ساده خواهد بود؛ مگر اینکه از قابلیتهای ORM استفاده نکرده باشید و مستقیما SQL نویسی ویژهی آن بانک اطلاعاتی خاص را انجام داده باشید. در غیر اینصورت (استفاده از ORM؛ بدون SQL نویسی مستقیم و ویژه)، حداکثر کاری که باید انجام دهید، تغییر پروایدرهای ابتدای برنامه است؛ بدون تغییری در کدهای اصلی برنامه
public DateTime AddDate { set; get; } [NotMapped] // فیلد محاسباتی سمت برنامه که در بانک اطلاعاتی قرار نخواهد گرفت public string PersianDate { get { return MyDateConverter(AddDate); } }
در code first از ویژگی NotMapped استفاده کنید تا بتونید با استفاده از تابع کمکی تبدیل تاریخ خودتون راحت این تبدیلات رو انجام بدید. در بانک اطلاعاتی DateTime استاندارد رو ذخیره کنید، در سمت کدها برای مسایل نمایشی از خاصیت PersianDate که NotMapped تعریف شده، میشه استفاده کرد. به علاوه روی DateTime استاندارد راحت میشه کوئریهای LINQ رو اجرا کرد بدون محدودیت. زمانیکه مثلا یک List تهیه شد، قسمت بعدی، کار نمایشی است که از خاصیت NotMapped میشه کمک گرفت. این روش با تمام بانکهای اطلاعاتی کار میکنه.
EF Code First #12
عالی مثل همیشه.
مهندس شما فرمودین:
الگوی مخزنی که ارائه داده در این مثال ساده کار میکنه اما اگر قرار باشه با چند موجودیت کار کرد و نتیجه رو ترکیب، کارآیی خوبی نداره چون خیلی از قابلیتهای ذاتی EF مثل کوئریهای به تاخیر افتاده (deferred LINQ queries) در اینجا قابل پیاده سازی نیست. اگر هم بخوان این رو اضافه کنن باید به لایه مخزن خروجی IQueryable اضافه کنن که به یک طراحی نشتی دار خواهند رسید چون انتهای کار با خروجی IQueryable کاملا باز باقی میماند (نمونهاش متد Get ایی است که طراحی کرده).
البته (البته چندین جای دیگه هم گفتین) در مورد نشتی حافظه، کاربرد IQueryable پس توی کدام لایه از کار ما میتونه باشه با توجه به انعظاف پذیری که به کار ما میده؟
درخواست راهنمایی سیستم Decision
private static void LoadEntities(Assembly asm, DbModelBuilder modelBuilder, string nameSpace) { var entityTypes = asm.GetTypes() .Where(type => type.BaseType != null && type.BaseType != Type.GetType("System.Enum") && type.Name != "Entity" && type.Name != "BaseEntity" && type.Namespace != null && type.Namespace.Contains(nameSpace)) .ToList(); entityTypes.ForEach(modelBuilder.RegisterEntityType); }
1- توی قسمت where یک بار baseType رو مخالف null و یک بار هم برابر null خواسته بود که این خودش باعث میشد تا کوئری گرفته شده مقداری رو برنگردونه
2- شرطی که نوشته شده بود اگه مشکل بالا رو حل میشد باعث میشد تمام Classها و Enumerationها و Object هایی که جزء entity نبود رو باخودش بیاره و به عنوان یک Entity معرفی کنه
3- اینکه توی شرط نوشته شده بود Namespace==nameSpace و این یعنی اگر فضای نام کلاسی مثلا برابر DomainClasses.Entities.Common بود، توی لیست entityهای آورده نشه
خلاصه اینکه کوئری قبلی هیچ چیزی رو برنمیگردوند
من با کد بالایی مشکلم رو حل کردم ولی فکرکنم کدی دوستان در پستهای قبلی گذاشتن بهتر باشه
مقایسه رکوردهای دو جدول
+ اگر برنامه مالی است، احتمالا دسترسی کاملی به سرور و همچنین SQL Server (اگر با آن کار میکنید) دارید. در این حالت برای به روز رسانی زمانبندی شدهی چند رکورد شاید بهتر باشد از سرویس معروف و همیشه در حال اجرای SQL Server agent استفاده کنید. در اینجا نیز میشود یک job را که متشکل از دستورات T-SQL است، در فواصل زمانی مشخصی اجرا کرد.