تغییر مجوز کتابخانهی Prism
مقایسه EF Core 2.1 vs NHibernate 5.1
CREATE TABLE Users ( id INT NOT NULL AUTO_INCREMENT, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL, gender ENUM('Male', 'Female') NOT NULL, PRIMARY KEY (id) ); CREATE TABLE BlogPosts ( id INT NOT NULL AUTO_INCREMENT, title VARCHAR(255) NOT NULL, user_id INT NOT NULL, KEY user_id (user_id), CONSTRAINT `blogposts_ibfk_1` FOREIGN KEY (user_id) REFERENCES Users (id), PRIMARY KEY (id) )
SELECT U.id, CONCAT_WS(' ', U.first_name, U.last_name) AS FullName, BP.title FROM Users AS U JOIN BlogPosts AS BP ON U.id = BP.user_id;
تبدیل یک ساختار Relational به JSON
میتوانیم خروجی موردنظر را در قالب JSON نیز کوئری بگیریم:
SELECT JSON_OBJECT('id', U.id, 'user', CONCAT_WS(' ', U.first_name, U.last_name), 'title', BP.title) FROM Users AS U JOIN BlogPosts AS BP ON U.id = BP.user_id;
به عنوان مثال میتوانیم لیست کاربران را به همراه بلاگ پستهایشان، اینگونه کوئری بگیریم:
SELECT JSON_OBJECT('user', CONCAT_WS(' ', U.first_name, U.last_name), 'blog_posts', JSON_ARRAYAGG(JSON_OBJECT('id', BP.id, 'title', BP.title))) AS JSON FROM Users AS U JOIN BlogPosts AS BP ON U.id = BP.user_id GROUP BY U.id;
خروجی کوئری فوق اینچنین خواهد بود:
تبدیل یک ساختار JSON به Relational
همچنین میتوانیم یک ساختار JSON را به صورت Relational تبدیل کنیم. اینکار توسط تابع JSON_TABLE قابل انجام است. کاری که این تابع انجام میدهد، ایجاد یک جدول موقت و کپی کردن دیتای موردنظر درون آن است. فرض کنید ساختار JSON زیر را به اینصورت درون دیتابیس ذخیره کردهایم:
{ "id": "1", "new": false, "sku": "asdf123", "tag": ["fashion", "men", "jacket", "full sleeve"], "name": "Lorem ipsum jacket", "image": [ "/assets/img/product/fashion/1.jpg", "/assets/img/product/fashion/3.jpg", "/assets/img/product/fashion/6.jpg", "/assets/img/product/fashion/8.jpg", "/assets/img/product/fashion/9.jpg" ], "price": 12.45, "rating": 4, "category": ["fashion", "men"], "discount": 10, "offerEnd": "October 5, 2020 12:11:00", "saleCount": 54, "description": { "fullDescription": "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?", "shortDescription": "Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur." } }
اکنون میخواهیم چنین خروجیای داشته باشیم:
کوئری موردنیاز برای تهیه خروجی فوق اینچنین خواهد بود:
SELECT newTable.* FROM experiments.productMetadata, JSON_TABLE( data, "$" COLUMNS ( id INT PATH "$.id", new CHAR(5) PATH "$.new", sku CHAR(20) PATH "$.sku", price FLOAT PATH "$.price", rating FLOAT PATH "$.rating", name CHAR(255) PATH "$.name", discount FLOAT PATH "$.discount", offerEnd TEXT PATH "$.offerEnd", saleCount INT PATH "$.saleCount", description TEXT PATH "$.description.shortDescription" ) ) AS newTable;
تابع JSON_TABLE دو ورودی نیاز خواهد داشت؛ ورودی اول ستون JSONی است که میخوایم از آن کوئری بگیریم. ورودی دوم با تعیین path شروع خواهد شد. از آنجائیکه محتوای داخل ستون data به صورت آبجکت ذخیره شدهاست، از $ استفاده کردهایم که به معنای داکیومنت جاری است. سپس توسط کلمه کلیدی COLUMNS ساختار جدول موقتمان را تعریف خواهیم کرد. این ساختار به صورت یک آرگومان به COLUMNS ارسال خواهد شد و شبیه به ساختار CREATE TABLE است؛ با این تفاوت که بعد از تعریف نوع دادهای هر ستون باید مسیر رسیدن به مقدار موردنظر را نیز تعیین کنیم که در واقع همان سینتکس pathی است که در مثالهای قبل نیز بررسی کردیم. به عنوان مثال برای رسیدن به مقدار پراپرتی name، مسیر را به صورت name.$ نوشتهایم. این path از آرایه نیز پشتیبانی میکند؛ مثلاً برای دسترسی به عنصر اول آرایه tag کافی است اینگونه عمل کنیم:
tag CHAR(20) PATH "$.tag[0]"
همچنین تابع JSON_TABLE، از ساختارهای تودرتو نیز پشتیبانی میکند. به عنوان مثال برای داشتن مقادیر tag, category, image در خروجی میتوانیم از کلمه کلیدی NESTED استفاده کنیم:
SELECT newTable.* FROM experiments.productMetadata, JSON_TABLE( data, "$" COLUMNS ( id INT PATH "$.id", new CHAR(5) PATH "$.new", sku CHAR(20) PATH "$.sku", price FLOAT PATH "$.price", rating FLOAT PATH "$.rating", NESTED PATH '$.tag[*]' COLUMNS (tag TEXT PATH '$'), name CHAR(255) PATH "$.name", discount FLOAT PATH "$.discount", offerEnd TEXT PATH "$.offerEnd", saleCount INT PATH "$.saleCount", description TEXT PATH "$.description.shortDescription", NESTED PATH '$.image[*]' COLUMNS (image TEXT PATH '$'), NESTED PATH '$.category[*]' COLUMNS (category TEXT PATH '$') ) ) AS newTable;
درون COLUMNS میتوانیم یک name FOR ORDINALITY نیز تعیین کنیم. این فیلد دقیقاً مشابه AUTO INCREMENT در ساختار CREATE TABLE میباشد. به این معنا که به ازای هر آیتم فیلد nested، یک واحد اضافه خواهد شد. از آن میتوانیم به عنوان rowId برای آیتم آرایه استفاده کنیم:
NESTED PATH '$.category[*]' COLUMNS (categoryRowId FOR ORDINALITY, category TEXT PATH '$')
همچنین از ON EMPTY برای پراپرتیهایی که در ساختار JSON وجود ندارند نیز میتوانیم استفاده کنیم. به عنوان مثال در کوئری زیر گفتهایم در صورت عدم وجود price، یک مقدار پیشفرض باید نمایش داده شود و همچنین در صورت عدم وجود name، یک خطا در خروجی نمایش داده شود:
name CHAR(255) PATH "$.name" ERROR ON EMPTY, price FLOAT PATH "$.price" DEFAULT "0" ON EMPTY,
همچنین میتوانیم مقدار NULL را در صورت عدم وجود name ست کنیم:
name CHAR(255) PATH "$.name" NULL ON EMPTY,
تاریخچهای مختصر از GC در NET.
ایده اولیه ایجاد Garbage Collector در NET.، در سال 1990 بود که در آن زمان، مایکروسافت مشغول پیاده سازی خود از JavaScript بنام JScript بود. در ابتدا JScript توسط تیمی چهار نفره توسعه داده میشد و در آن زمان یکی از اعضای این تیم به نام Patrick Dussud که بعنوان پدر Garbage Collector در NET. شناخته میشود، یک Conservative GC را داخل تیم توسعه داد. در آن زمان CLR ای وجود نداشت و Patrick Dussud برروی JVM کار میکرد.مایکروسافت سعی بر پیاده سازی نسخهای اختصاصی از JVM را برای خود بجای ایجاد چیزی شبیه به NET Runtime. فعلی داشت؛ اما بعد از شکل گیری تیم CLR، به این نتیجه رسیدند که JVM برای آنها محدودیتهایی را ایجاد میکند و به همین دلیل شروع به ایجاد Environment خود کردند.
با این تصمیم، Patrick Dussud مجددا یک GC جدید را با ایده "بهترین GC ممکن" با زبان LISP که در آن بیشترین مهارت را داشت، بصورت Prototype نوشت و سپس یک Transpiler از LISP را به ++C نوشت که کدهای آن قابل استفاده در Runtime مایکروسافت باشد.
کدهای فعلی مربوط به Garbage Collector مورد استفاده در NET. در این فایل از ریپازیتوری runtime مایکروسافت قابل دسترسی هستند. در حال حاضر خانم Maoni Stephens مدیر فنی تیم GC مایکروسافت هستند که کنفرانسها و مقالات زیادی نیز درباره نکات مختلف پیاده سازی GC در بلاگ خود نوشته و ارائه کردهاند.
در حال حاضر، سه حالت (flavor) از GC در NET. تعبیه شدهاست و هرکدام از این حالات برای انواع مختلفی از برنامهها بهینه شدهاست که در ادامه به بررسی آنها میپردازیم.
Server GC
این نوع GC برای برنامههای سمت سرور نظیر ASP.NET Core و WCF بهینه سازی شدهاست که تعداد ریکوئستهای زیادی به آنها وارد میشود و هر ریکوئست باعث allocate شدن اشیا مختلفی شده و بطور کلی، نرخ allocation و deallocation در آنها بالاست. Server GC به ازای هر پردازنده، از یک Heap و یک GC Thread مجزا استفاده میکند. این بدین معناست که اگر شما یک پردازنده را با هشت Core داشته باشید، در زمان Garbage Collection، روی هرکدام از Coreها یک Heap و GC Thread مستقل وجود دارد که عمل Garbage Collection را انجام میدهند.
این شکل عملکرد باعث میشود که Collection، در سریعترین زمان ممکن، بدون وقفه اضافه انجام شود و برنامه شما اصطلاحا ((Freeze)) نشود.
Server GC فقط روی پردازندههای چند هستهای قابل اجراست و اگر سعی کنید برنامه خود را روی یک سیستم با پردازنده تک هستهای در حالت Server GC اجرا کنید، بصورت خودکار برنامه شما از Non-Concurrent Workstation GC استفاده کرده و اصطلاحا Fallback خواهد شد.
اگر نیاز دارید که در برنامههایی بهغیر از Server-Side Applicationها، نظیر WPF و Windows Serviceها و ... از این نوع GC استفاده کنید (به شرط چند هسته بودن پردازنده)، میتوانید این تنظیمات را به فایل app.config یا web.config خود اضافه کنید:
<configuration> <runtime> <gcServer enabled="true"/> </runtime> </configuration>
همچنین در برنامههای NET Core.ای نیز میتوانید این تنظیمات را داخل فایل csproj. برنامه خود اضافه کنید:
<PropertyGroup> <ServerGarbageCollection>true</ServerGarbageCollection> </PropertyGroup>
Concurrent Workstation GC
این حالت، حالت پیشفرض مورد استفاده در برنامههای Windows Forms و Windows Service است. این حالت از GC برای برنامههایی بهینه شدهاست که در آنها، هنگام وقوع Garbage Collection، برنامه توقف و مکث حتی چند لحظهای نداشته و Collection باعث نشود که کاربر نتواند روی یک دکمه کلیک کند و اصطلاحا برنامه ((Unresponsive)) شود.
برای فعالسازی Concurrent Workstation GC این تنظیمات را داخل config برنامه خود باید اعمال کنید:
<configuration> <runtime> <gcConcurrent enabled="true" /> </runtime> </configuration>
Non-Concurrent Workstation GC
این حالت شبیه به حالت Server GC است؛ با این تفاوت که عمل Collection روی Thread ای که درخواست allocate کردن یک object را کرده است، صورت میگیرد.
برای مثال:
- Thread شماره یک درخواست allocate کردن یک string با طول 10000 کاراکتر را میدهد.
- حافظه، فضای کافی برای تخصیص این حجم از حافظه را نداشته و سعی میکند با اجرای Garbage Collector، این حجم فضای مورد نیاز از حافظه را خالی کند.
- CLR تمام Threadهای برنامه را متوقف میکند و Garbage Collector شروع به کار کرده و اشیا بلااستفاده «روی Thread ای که آن را فراخوانی کرده است» را Collect میکند.
- بعد از پایان Collection، تمامی Threadهای برنامه که در مرحله قبل متوقف شده بودند، مجددا شروع به کار خواهند کرد.
این حالت از GC برای برنامههای Server-Side ای که برروی پردازنده تک هستهای اجرا میشوند، پیشنهاد میشود. برای فعالسازی این حالت، تنظیمات داخل config برنامه به این صورت باید تغییر پیدا کند:
<configuration> <runtime> <gcConcurrent enabled="false" /> </runtime> </configuration>
این جدول، کمک خواهد کرد که بر اساس نوع برنامه خود، تنظیمات درستی را برای GC اعمال نمایید (در اکثر موارد، تنظیمات پیشفرض بهترین انتخاب بوده و نیازی به تغییر روند کار GC نیست):
Server GC | Non-Concurrent Workstation | Concurrent Workstation | |
Maximize throughput on multi-processor machines for server apps that create multiple threads to handle the same types of requests. | Maximize throughput on single-processor machines. | Balance throughput and responsiveness for client apps with UI. | Design Goal |
1 per processor ( hyper thread aware ) | 1 | 1 | Number of Heaps |
1 dedicated GC thread per processor | The thread which performs the allocation that triggers the GC. | The thread which performs the allocation that triggers the GC. | GC Threads |
EE is suspended during a GC. | EE is suspended during a GC. | EE is suspended much shorter but several times during a GC. | Execution Engine Suspension |
<gcServer enabled="true"> | <gcConcurrent enabled="false"> | <gcConcurrent enabled="true"> | Config Setting |
Non-Concurrent Workstation GC | On a single processor (fallback) |
J (J language) is a high-level, general-purpose, high-performance programming language. J is portable and runs on 32/64-bit Windows/Linux/Mac as well as iOS, Android, and other platforms. J source (required only if Jsoftware binaries don't meet your requirements) is available under both commercial and GPL 3 license. J systems can be installed and distributed for free.
J systems have:
- an integrated development environment
- standard libraries, utilities, and packages
- console, browser, and Qt front ends
- interfaces with other programming languages and applications
- integrated graphics
- memory mapped files for high performance data applications
- Jd
کتابخانه Hyprlinkr
Example
Imagine that you're using the standard route configuration created by the Visual Studio project template:
name: "API Default", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional }
In that case, you can create an URI to a the resource handled by the FooController.GetById Action Method like this:
var uri = linker.GetUri<FooController>(r => r.GetById(1337));
This will create a URI like this:
http://localhost/api/foo/1337