مطالب
استفاده از Sparse Columns در SQL Server 2012
مقدمه
مقدار null به معنی پوچ و هیچ می‌باشد اما زمانی که در مقدار دهی جداول از آن استفاده می‌نمایم با توجه به نوع آن ستون فضای متفاوتی اشتغال می‌نماید. شاید در پایگاه داده‌های کوچک زیاد مطرح نباشد اما زمانی که حداقل چند گیگ حجم آن باشد و فرضا 20 تا 30 درصد آن از مقادیر null پر شده باشد فضای زیای از پوچ گرفته شده است این در حالی است که خیلی از توسعه دهندگان اصلا به اهمیت استفاده از null توجهی نمی‌کنند و از مقادیری غیر معتبری مثل 0 یا 1- در آن ستون به جای null استفاده می‌کنند.
SQL Server Sparce Columns
sparse column یا ستون‌های تنک قابلیتی از که از SQL Server 2008 اضافه شده و به ستون‌های عادی امکان استفاده بهینه از فضای ذخیره شده برای مقادیر null را می‌دهد. در واقع sparse column فضای مورد نیاز برای مقادیر null نسبت به مقادیر غیر null را کاهش می‌دهد. با استفاده از sparse column فضای ذخیره شده حداقل 20 تا 40 درصد کمتر خواهد شد.

ویژگی‌های Sparse Columns
  • SQL Server Database Engine از کلمه کلیدی SPARSE برای تعریف یک ستون که مقادیر آن می‌بایست بهینه شود استفاده می‌نماید.
  • نمای Catalog  جداول با ستون sparse شبیه جداول معمولی می‌باشد.
  • مقدار برگشتی از تابع COLUMNS_UPDATED با ستون sparce متفاوت از ستون معمولی است.
در نوع داده‌های زیر امکان استفاده از sparce columns  را ندارند:
 geography  text
 geometry   timestamp 
 image   user-defined data types 
ntext  
sparse column فضای بیشتری برای ذخیره داده‌های غیر null نسبت به داده‌های نشانه گذاری نشده با SPARSE لازم دارد و این فضا4 بایت بیشتر از ستون معمولی است. برآورد فضای ذخیره شده براساس نوع داده با طول ثابت در جدول زیر آورده شده است:
 نوع داده  بایت بدون sparse  بایت sparse  درصد null
 bit   0.125   5  98%
 tinyint   1   5  86%
 smallint   2  6  76%
 int   4  8  64%
bigint  8  12  52%
 real   4  8  64%
 float   8  12  52%
 smallmoney   4  8  64%
 money   8  12  52%
 smalldatetime   4  8  64%
 datetime   8  12  52%
 uniqueidentifier   16  20  43%
 date   3  7  69%
نوع داده با دقت - وابسته به طول
 
 نوع داده  بایت بدون sparse  یابت sparse  درصد null 
 (datetime(2   6  10  57%
 (datetime(2   8  12  52%
 (time(0   3  7  69%
 (time(7   5  9  60%
 (datetimetoffset(0   8  12  52%
 (datetimetoffset (7   10  14  49%
 (decimal/numeric(1,s   5  9  60%
 (decimal/numeric(38,s   17  21  42%
 (vardecimal(p,s      
نوع داده - داده وابسته به طول
نوع داده 
بایت بدون sparse   یابت sparse  درصد null
 sql_variant   2*   2*   60% 
 varchar or char   2*  4*+   60% 
 nvarchar or nchar   2*   4*   60% 
 varbinary or binary   2*   4*   60% 
 xml   2*   4*   60% 
 hierarchyid   2*  4*   60% 

محدویت‌های استفاده از Sparse columns
  • sparse column می‌ بایست nullable باشد و نمی‌تواند ROWGUIDCOL یا IDENTITY باشد. 
  • sparse column مقدار پیش فرض نمی‌تواند داشته باشد 
  • ستون محاسبه ای نمی‌تواند sparse باشد
  • sparse column نمی‌تواند بخشی از clustered index یا  unique primary key index باشد
  • sparse column  نمی تواند بخشی از  user-defined table باشد

مثالی از کاربرد Sparse columns
CREATE TABLE Employees_sparse (
   EMP_ID INT IDENTITY(5001,1) PRIMARY KEY, 
   SSN CHAR(9) NOT NULL, 
   TITLE CHAR(10) SPARSE NULL, 
   FIRSTNAME VARCHAR(50) NOT NULL, 
   MIDDLEINIT CHAR(1) SPARSE NULL, 
   LASTNAME VARCHAR(50) NOT NULL, 
   EMAIL CHAR(50) SPARSE NULL)
GO
CREATE TABLE Employees (
   EMP_ID INT IDENTITY(5001,1) PRIMARY KEY, 
   SSN CHAR(9) NOT NULL, 
   TITLE CHAR(10) NULL, 
   FIRSTNAME VARCHAR(50) NOT NULL, 
   MIDDLEINIT CHAR(1) NULL, 
   LASTNAME VARCHAR(50) NOT NULL, 
   EMAIL CHAR(50) NULL)
GO
در این دو جدول یکی با سه ستون Sparse  و دیگری بدون Sparse ایجاد شده و با  50000 ردیف داده پر شده است حال با رویه ذخیره شده sp_spaceused می‌توان فضای ذخیره شده دو جدول را باهم مقایسه نمود.
sp_spaceused 'Employees'
GO
sp_spaceused 'Employees_sparse' 

البته ذکر این نکته گفتی است که بهتر است از این تکنیک برای جداولی که تعداد زیادی ستون null دارند استفاده شود. 
اشتراک‌ها
کتابخانه protobuf-net (پیاده سازی Protocol Buffers برای دات نت)

protobuf-net is a contract based serializer for .NET code, that happens to write data in the "protocol buffers" serialization format engineered by Google. The API, however, is very different to Google's, and follows typical .NET patterns (it is broadly comparable, in usage, to XmlSerializer, DataContractSerializer, etc). It should work for most .NET languages that write standard types and can use attributes. 

Nuget Package : https://www.nuget.org/packages/protobuf-net 


کتابخانه protobuf-net (پیاده سازی Protocol Buffers برای دات نت)
اشتراک‌ها
مروری بر ASP.NET Core View Component

Partial Views and Child Actions are one the most used features of ASP.NET MVC. Partial Views provides us a way to create a reusable component that can be used in multiple Views. There are Actions which can be marked as Child Actions and these cannot be invoked via URL but inside views or partial views. Child Actions are no more available with ASP.NET Core. View Components are new way to implement this feature in ASP.NET Core. 

مروری بر ASP.NET Core View Component
مطالب
راه اندازی دیتابیس postgresql در برنامه‌های ASP.NET Core – قسمت 2

در قسمت قبل به معرفی postgresql پرداختیم; در این قسمت قصد ایجاد و راه اندازی یک api با استفاده از دیتابیس postgresql و استفاده از تکنولوژی‌های آن را با استفاده از docker داریم.


ابتدا با استفاده از دستور زیر یک پروژه‌ی جدید asp.net core را ایجاد کنید:

dotnet new webapi --minimal -o YourDirectoryPath:\YourFolderName

سپس فایل docker-compose.yaml را به روت پروژه اضافه کنید که شامل کانفیگ‌های زیر میباشد: 

version: '3.1'

services:

  db:
    image: postgres
    container_name: db
    restart: always
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USERNAME: postgres
      POSTGRES_DB: BloggingDb
    ports:
        - "5432:5432"
    volumes:
      - postgres_data:/data/db

  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080
  
  pgadmin4:
    image: dpage/pgadmin4
    restart: always
    environment:
      PGADMIN_DEFAULT_EMAIL: pgadmin4@pgadmin.org
      PGADMIN_DEFAULT_PASSWORD: admin
      PGADMIN_CONFIG_SERVER_MODE: 'False'
    ports:
      - 5050:80
    volumes:
      - pgadmin:/var/lib/pgadmin
    depends_on:
      - db

volumes:
  postgres_data:
  pgadmin:

سپس با اجرای دستور زیر در روت پروژه، سرویس‌ها را راه اندازی کنید: 

docker compose up -d


معرفی سرویس‌های استفاده شده در تنظیمات فایل بالا: 

سرویس db

نمونه ایمیج اصلی، volume، تنظیمات connection string در آن استفاده شده است.

سرویس adminer :

https://hub.docker.com/_/adminer /

Adminer - Database management in a single PHP file

یک برنامه تحت وب مدیریت پایگاه داده ساده میباشد که ویژگی‌ها MySql را در کنار سرعت و امنیت ارائه میدهد و در آدرس http://localhost:8080 / اجرا خواهد شد.

سرویس pgadmin4 :

pgAdmin - PostgreSQL Tools

dpage/pgadmin4 - Docker Image | Docker Hub

در حال حاضر این برنامه محبوب‌ترین برنامه مدیریت پایگاه داده میباشد که ویژگی‌های پیشرفته‌ای را نیز پوشش میدهد و در آدرس http://localhost:5050 / اجرا خواهد شد. 


اکنون نوبت نوشتن کد‌ها میباشد. 

- تنظیم connection string در فایل appsettings.json:

"ConnectionStrings": {
    "BloggingContext": "Username=postgres;Password=postgres;Server=localhost;Database=BloggingDb”
}

- و همینطور پکیج‌های زیر را به برنامه خود رفرنس دهید: 

dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Design

- مدل‌های برنامه را در مسیر /Models ایجاد کنید: 

namespace NpgsqlAPI.Models;

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; } = null!;
    public string Content { get; set; } = null!;

    public int BlogId { get; set; }
    public Blog Blog { get; set; } = null!;
}

namespace NpgsqlAPI.Models;

public class Blog
{
    public int BlogId { get; set; }
    public string? Url { get; set; }

    public List<Post>? Posts { get; set; }
}

- سپس BloggingContext را در مسیر /Data ایجاد کنید:

using Microsoft.EntityFrameworkCore;
using NpgsqlAPI.Models;

namespace NpgsqlAPI.Data;

public class BloggingContext : DbContext
{
    public BloggingContext(DbContextOptions<BloggingContext> options)
        : base(options)
    {
    }
    public DbSet<Blog> Blogs => Set<Blog>();
    public DbSet<Post


- سپس اینترفیس IBlogServices را در مسیر  /Servicec/Blogs ایجاد کنید: 

using NpgsqlAPI.Models;

namespace NpgsqlAPI.Services.Blogs;
public interface IBlogServices
{
    Task<IEnumerable<Blog>> GetList();
    Task<Blog?> Get(uint id);
    Task<uint> Add(Blog obj);
    Task AddRange(Blog[] obj);
    Task Update(Blog obj);
    Task UpdateRange(Blog[] obj);
    Task Remove(uint id);
}


-  و سپس پیاده سازی آن را در فایل BlogEFServices و در کنار اینترفیس آن قرار دهید: 

using Microsoft.EntityFrameworkCore;
using NpgsqlAPI.Data;
using NpgsqlAPI.Models;

namespace NpgsqlAPI.Services.Blogs;
public sealed class BlogEFServices : IBlogServices
{
    private readonly BloggingContext _context;
    public BlogEFServices(BloggingContext context)
    {
        _context = context;
    }

    public async Task<uint> Add(Blog obj)
    {
        await _context.Blogs.AddAsync(obj);
        return (uint)await SaveChangesAsync();
    }

    public async Task AddRange(Blog[] obj)
    {
        await _context.Blogs.AddRangeAsync(obj);
        await SaveChangesAsync();
    }

    public async Task<Blog?> Get(uint id)
    {
        return await _context.Blogs.FirstOrDefaultAsync(x=>x.BlogId == id);
    }

    public async Task<IEnumerable<Blog>> GetList()
    {
       return await _context.Blogs.ToListAsync();
    }

    public async Task Remove(uint id)
    {
        var entity = await Get(id);
        _context.Blogs.Remove(entity!);
        await SaveChangesAsync();
    }

    public async Task Update(Blog obj)
    {
        _context.Blogs.Update(obj);
        await SaveChangesAsync();
    }

    public async Task UpdateRange(Blog[] obj)
    {
        _context.Blogs.UpdateRange(obj);
        await SaveChangesAsync();
    }

    private async Task<int> SaveChangesAsync()
    {
        return await _context.SaveChangesAsync();
    }
}


- اکنون  endpoint‌های api را در فایل program.cs ایجاد کنید:

using System.Data;
using Microsoft.EntityFrameworkCore;
using Npgsql;
using NpgsqlAPI.Services.Blogs;
using NpgsqlAPI.Data;
using NpgsqlAPI.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

string connectionString = builder.Configuration.GetConnectionString("BloggingContext")!;

builder.Services.AddDbContext<BloggingContext>(options =>
        options.UseNpgsql(connectionString));

builder.Services.AddTransient<IDbConnection>(_ => new NpgsqlConnection(connectionString));

// builder.Services.AddScoped<IBlogServices, BlogDapperServices>();
// builder.Services.AddScoped<IBlogServices, BlogEFRawQueryServices>();
builder.Services.AddScoped<IBlogServices, BlogEFServices>();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.MapGet("/blogs", async (IBlogServices service) => await service.GetList())
.WithName("GetBlogs")
.WithOpenApi();

app.MapGet("/blogs/{id}", async (IBlogServices service, uint id) => await service.Get(id))
.WithName("GetBlog")
.WithOpenApi();

app.MapPost("/blogs", async (IBlogServices service, Blog blog) => await service.Add(blog))
.WithName("AddBlog")
.WithOpenApi();

app.MapDelete("/blogs/{id}", async (IBlogServices service, uint id) => await service.Remove(id))
.WithName("RemoveBlog")
.WithOpenApi();

app.MapPut("/blogs", async (IBlogServices service, Blog blog) => await service.Update(blog))
.WithName("UpdateBlog")
.WithOpenApi();

app.MapPut("/blogs/Bulk", async (IBlogServices service, Blog[] blogs) =>
 await service.UpdateRange(blogs))
.WithName("UpdateBulkBlog")
.WithOpenApi();

app.MapPost("/blogs/Bulk", async (IBlogServices service, Blog[] blogs) =>
 await service.AddRange(blogs))
.WithName("AddBulkBlog")
.WithOpenApi();

app.Run();

تمامی کد‌های برنامه تا به اینجا نوشته شده‌اند. اکنون migration را پس از اطمینان از اجرا بودن داکر اجرا کنید 

dotnet ef migrations add Init
dotnet ef database update

و برنامه را اجرا و تست کنید. 


کد‌های کامل این مطلب

اشتراک‌ها
استفاده از FontAwesome در WPF

Font Awesome gives you scalable vector icons that can instantly be customized — size, color, drop shadow, and anything that can be done with the power of CSS. 

استفاده از FontAwesome در WPF
اشتراک‌ها
مزیت ارجاع به CDN ها برای کتابخانه های اسکریپتی

مطلب قدیمی می‌باشد ولی خالی از لطف نیست .

Use CDN's for scripts and media content to improve loading on the client side (i.e. Google CDN)

If everyone is using the same CDNs, odds are the client already has that script cached from some other site and the load time is zero   
مزیت ارجاع به CDN ها برای کتابخانه های اسکریپتی
اشتراک‌ها
کار با HubContext در ASP.NET Core SignalR

In this section, I’m going to cover how you can use SignalR outside of a Hub. In most asp.net core applications, you will likely want to communicate with the connect clients from within your application but outside of a Hub. You can accomplish this by using the HubContext.

For example, an ASP.NET Core MVC Controller or any other class that is instantiated by ASP.NET Core’s Dependency Injection.

The HubContext allows you to send messages to your connected clients. It has many of the same features to communicate with clients as when you are inside of a Hub.  

کار با HubContext در ASP.NET Core SignalR