نظرات نظرسنجی‌ها
نظر شما در رابطه با استفاده از کامپوننت های رایگان و آماده Blazor چیست؟
من درپروژه هام از mudblazor استفاده میکنم.نکته مثبتی که داره اینه که میتونین کلاس‌های هر کامپوننت رو با ارث بری دریک کلاس دیگه سفارشی سازی کنین
مطالب
استفاده از Unity در پیاده سازی الگوی Service locator
یکی از راهکارهای پیاده سازی IOC یا همان Inversion Of Control در پروژه‌های MVC استفاده از Unity و معرفی آن به DependencyResolver خود دات نت است.
برای آشنایی با Unity و قابلیت‌های آن میتوانید به اینجا و اینجا سر بزنید.
اما برای استفاده از Unity در پروژه‌های MVC کافی است در Global یا فایل راه انداز (bootstrapper ) تک تک انتزاع‌ها (Interface) را به کلاس‌های مرتبط شان معرفی کنید.
var container = new UnityContainer();  
container.RegisterType<ISomeService, SomeService>(new PerRequestLifetimeManager());
container.RegisterType<ISomeBusiness, SomeBusiness>(new PerRequestLifetimeManager());
container.RegisterType<ISomeController, SomeController>(new PerRequestLifetimeManager());
و بعد از ایجاد container از نوع UnityContainer میتوانیم آنرا به MVC معرفی کنیم:
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
تا به اینجا به‌راحتی میتوانید از سرویس‌های معرفی شده در پروژه MVC استفاده کنید.
var someService=(ISomeService)DependencyResolver.Current.GetService(typeof(ISomeService));
var data=someService.GetData();
اما اگر بخواهیم از کلاس‌های معرفی شده در Unity در لایه‌های دیگر (مثلا Business) استفاده کنیم چه باید کرد؟
برای هر این مشکل راهکارهای متفاوتی وجود دارد. من در لایه سرویس از Service locator بهره برده ام. برای آشنایی با این الگو اینجا را بخوانید. اکثر برنامه نویسان الگوهای IOC و Service Locator را با هم اشتباه میگیرند یا آنها را اشتباها بجای هم بکار میبرند.
برای درک تفاوت الگوی IOC و Service locator اینجا را بخوانید.

در لایه سرویس یک کلاس Service Factory داریم که قرار است همه سرویس‌ها، برای برقراری ارتباط با یکدیگر از آن استفاده کنند.این کلاس معمولا در لایه سرویس به اشکال گوناگونی پیاده سازی میشود که کارش وهه سازی از Interface‌های درخواستی است. اما برای یکپارچه کردن آن با Unity من آنرا به شکل زیر پیاده سازی کرده ام

public class ServiceFactory : MarshalByRefObject
    {
        static IUnityContainer uContainer = new UnityContainer();
        public static Type DataContextType { get; set; }

        public static void Initialise(IUnityContainer unityContainer, Type dbContextType)
        {
            uContainer = unityContainer;
            DataContextType = dbContextType;
            uContainer.RegisterType(typeof(BaseDataContext), DataContextType, new HierarchicalLifetimeManager());
        }
        public static T Create<T>()
        {
            return (T)Activator.CreateInstance<T>();
        }
        public static T Create<T>(string fullTypeName)
        {
            return (T)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullTypeName);
        }
        public static T Create<T>(Type entityType)
        {
            return (T)Activator.CreateInstance(entityType);
        }
        public static dynamic Create(Type entityType)
        {
            return Activator.CreateInstance(entityType);
        }

        public static T Get<T>()
        {
            return uContainer.Resolve<T>();
        }
        public static object Get(Type type)
        {
            return uContainer.Resolve(type);
        }
    }

در این کلاس ما بجای ایجاد داینامیک آبجکت‌ها، از Unity استفاده کرده‌ایم. در همان ابتدا که برنامه‌ی وب ما برای اولین بار اجرا میشود و بعد از Register کردن کلاس‌ها، می‌توانیم container را به صورت پارامتر سازنده به کلاس Service Factory ارسال کنیم. به این ترتیب برای استفاده از سرویس‌ها در لایه Business از Unity بهره میبریم.

البته استفاده از Unity برای DataContext خیلی منطقی نیست و بهتر است نوع DataContext را در ابتدا بگیریم و هرجا نیاز داشتیم با استفاده از متد Create از آن وهله سازی بکنیم.

مطالب
کوئری نویسی در EF Core - قسمت هفتم - کار با رشته‌‌ها
هدف از این سری مثال‌ها، آشنایی با متدها و توابعی است که در حین کار با خواص رشته‌ای در LINQ to Entities، مجاز به استفاده‌ی از آن‌ها هستیم و همچنین اگر تابعی در EF-Core هنوز تعریف نشده بود، راه حل چیست.


مثال 1: نام تمام کاربران را با قالب 'Surname, Firstname'  نمایش دهید.

var members = context.Members
                                    .Select(member => new { Name = member.Surname + ", " + member.FirstName })
                                    .ToList();
متد Select می‌تواند به همراه اعمال محاسباتی ساده‌ای نیز باشد که نمونه‌ای از آن‌را در اینجا مشاهده می‌کنید.
با این خروجی:



مثال 2: تمام امکاناتی را که با Tennis شروع می‌شوند، لیست کنید.
این گزارش به همراه تمام ستون‌های جدول است.

var facilities = context.Facilities
                                        .Where(facility => facility.Name.StartsWith("Tennis"))
                                        .ToList();
متدهای استانداردی مانند StartsWith، EndsWith و Contains را می‌توان بر روی خواص رشته‌ای بکار برد.
با این خروجی:



مثال 3: تمام امکاناتی را که با tennis شروع می‌شوند، لیست کنید. این جستجو باید غیرحساس به بزرگی و کوچکی حروف باشد.
این گزارش به همراه تمام ستون‌های جدول است.

نیازی به انجام مجزای این تمرین نیست؛ چون پاسخ آن همان پاسخ مثال 2 است. Collation پیش‌فرض در SQL Server، غیرحساس به بزرگی و کوچکی حروف است. بنابراین چه tennis را جستجو کنیم و یا TeNnis را، تفاوتی نمی‌کند.


مثال 4: شماره تلفن‌های دارای پرانتز را لیست کنید.
این گزارش باید به همراه ستون‌های memid, telephone باشد.

روش اول: در اینجا دوبار از متد Contains استفاده شده‌است:
var members = context.Members
                                    .Select(member => new { member.MemId, member.Telephone })
                                    .Where(member => member.Telephone.Contains("(")
                                                    && member.Telephone.Contains(")"))
                                    .ToList();
با این خروجی:


روش دوم: اگر می‌خواهیم کنترل بیشتری را بر روی خروجی نهایی LIKE تولیدی داشته باشیم، می‌توان از متد سفارشی استاندارد EF.Functions.Like استفاده کرد که از حروف wild cards نیز پشتیبانی می‌کند:
members = context.Members
                                    .Select(member => new { member.MemId, member.Telephone })
                                    .Where(member => EF.Functions.Like(member.Telephone, "%[()]%"))
                                    .ToList();
با این خروجی:



مثال 5: کد پستی‌ها 5 رقمی هستند. گزارشی را تهیه کنید که در آن اگر کدپستی کمتر از 5 رقم بود، ابتدای آن با صفر شروع شود.
هدف اصلی از این مثال، اعمال متد PadLeft(5, '0') به خاصیت member.ZipCode است.

روش اول: EF-Core فعلا قابلیت ترجمه‌ی PadLeft(5, '0') را به معادل SQL آن‌را ندارد. به همین جهت مجبور هستیم ابتدا ZipCode‌ها را به صورت رشته‌ای بازگشت دهیم که در اینجا استفاده‌ی از Convert.ToString مجاز است.
با این خروجی:
SELECT   CONVERT (NVARCHAR (MAX), [m].[ZipCode]) AS [Zip]
FROM     [Members] AS [m]
ORDER BY CONVERT (NVARCHAR (MAX), [m].[ZipCode]);
 سپس می‌توان بر روی لیست آماده‌ی موجود در حافظه، از LINQ to Objects استفاده کرد و در این حالت دسترسی کاملی به تمام امکانات زبان #C وجود دارد:
var members = context.Members
                                    .Select(member => new { ZipCode = Convert.ToString(member.ZipCode) })
                                    .OrderBy(m => m.ZipCode)
                                    .ToList();
// Now using LINQ to Objects
members = members.Select(member => new { ZipCode = member.ZipCode.PadLeft(5, '0') })
                                                    .OrderBy(m => m.ZipCode)
                                                    .ToList();

روش دوم: SQL Server به همراه تابع استانداردی به نام Replicate است که از آن می‌توان برای شبیه سازی PadLeft، بدون متوسل شدن به LINQ to Objects، استفاده کرد. اما چون این تابع هنوز به EF-Core معرفی نشده‌است، نیاز است خودمان اینکار را انجام دهیم. در این روش، از متد SqlDbFunctionsExtensions.SqlReplicate استفاده می‌شود. روش تعریف این نوع متدها را در مطلب «امکان تعریف توابع خاص بانک‌های اطلاعاتی در EF Core» پیشتر بررسی کرده‌ایم که برای مثال در اینجا چنین شکلی را پیدا می‌کند:
namespace EFCorePgExercises.Utils
{
    public static class SqlDbFunctionsExtensions
    {
        public static string SqlReplicate(string expression, int count)
            => throw new InvalidOperationException($"{nameof(SqlReplicate)} method cannot be called from the client side.");

        private static readonly MethodInfo _sqlReplicateMethodInfo = typeof(SqlDbFunctionsExtensions)
            .GetRuntimeMethod(
                nameof(SqlDbFunctionsExtensions.SqlReplicate),
                new[] { typeof(string), typeof(int) }
            );


        public static void AddCustomSqlFunctions(this ModelBuilder modelBuilder)
        {
            modelBuilder.HasDbFunction(_sqlReplicateMethodInfo)
                .HasTranslation(args =>
                {
                    return SqlFunctionExpression.Create("REPLICATE",
                        args,
                        _sqlReplicateMethodInfo.ReturnType,
                        typeMapping: null);
                });
        }
    }
}
پس از آن فقط کافی است متد AddCustomSqlFunctions را به Context برنامه معرفی کنیم:
namespace EFCorePgExercises.DataLayer
{
    public class ApplicationDbContext : DbContext
    {
         // ...

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
         // ...
            modelBuilder.AddCustomSqlFunctions();
         // ...
        }
    }
}
اکنون می‌توان از تابع SqlDbFunctionsExtensions.SqlReplicate جهت شبیه سازی PadLeft به صورت زیر استفاده کرد:
var newMembers = context.Members
                                        .Select(member => new
                                        {
                                            ZipCode =
                                                SqlDbFunctionsExtensions.SqlReplicate(
                                                    "0", 5 - Convert.ToString(member.ZipCode).Length)
                                                + member.ZipCode
                                        })
                        .OrderBy(m => m.ZipCode)
                        .ToList();
با این خروجی:



مثال 6: اولین حرف نام خانوادگی کاربران در کل ردیف‌های جدول چندبار تکرار شده‌است؟
این گزارش باید به همراه ستون‌های letter,  count باشد.

var members = context.Members
                                    .Select(member => new { Letter = member.Surname.Substring(0, 1) })
                                    .GroupBy(m => m.Letter)
                                    .Select(g => new
                                    {
                                        Letter = g.Key,
                                        Count = g.Count()
                                    })
                                    .OrderBy(r => r.Letter)
                                    .ToList();
هدف از این مثال بیان مجاز بودن استفاده‌ی از متد Substring بر روی خواص رشته‌ای است که EF-Core امکان ترجمه‌ی آن‌ها را به کدهای SQL دارد.
با این خروجی:



مثال 7: حروف '-','(',')', ' ' را از شماره تلفن‌ها حذف کنید.
این گزارش باید به همراه ستون‌های memid, telephone باشد.

بانک اطلاعاتی PostgreSQL به همراه تابع استاندارد regexp_replace است و می‌توان از آن برای حل یک چنین مسایلی استفاده کرد:
select memid, regexp_replace(telephone, '[^0-9]', '', 'g') as telephone
from members
order by memid;
اما SQL Server هنوز هم به همراه یک چنین تابعی نیست. بنابراین از روش زیر نیز می‌توان مثال جاری را حل کرد:
var members = context.Members
                                .Select(member => new
                                {
                                    member.MemId,
                                    Telephone = member.Telephone.Replace("-", "")
                                                        .Replace("(", "")
                                                        .Replace(")", "")
                                                        .Replace(" ", "")
                                })
                                .OrderBy(r => r.MemId)
                                .ToList();
با این خروجی:



کدهای کامل این قسمت را در اینجا می‌توانید مشاهده کنید.
نظرات مطالب
نمایش خطاهای اعتبارسنجی سمت سرور ASP.NET Core در برنامه‌های Angular
نکته تکمیلی
برای خلوت کردن قالب‌های مرتبط با فرم‌ها برای نمایش خطاهای اعتبارسنجی و همچنین برای جلوگیری از تکرار، می‌توان کامپوننت ValidationMessage را به شکل زیر نیز توسعه داد:
import { Component, Input, OnInit } from '@angular/core';
import { AbstractControl } from '@angular/forms';

@Component({
  selector: 'validation-message',
  template: `
    <ng-container *ngIf="control.invalid && control.touched">
      {{ message }}
    </ng-container>
  `
})
export class ValidationMessageComponent implements OnInit {
  @Input() control: AbstractControl;
  @Input() fieldDisplayName: string;
  @Input() rules: { [key: string]: string };

  get message(): string {
    return this.control.hasError('required')
      ? `${this.fieldDisplayName} را وارد نمائید.`
      : this.control.hasError('pattern')
      ? `${this.fieldDisplayName} را به شکل صحیح وارد نمائید.`
      : this.control.hasError('email')
      ? `${this.fieldDisplayName} را به شکل صحیح وارد نمائید.`
      : this.control.hasError('minlength')
      ? `${this.fieldDisplayName} باید بیشتر از  ${
          this.control.errors.minlength.requiredLength
        } کاراکتر باشد.`
      : this.control.hasError('maxlength')
      ? `${this.fieldDisplayName} باید کمتر از  ${
          this.control.errors.maxlength.requiredLength
        } کاراکتر باشد.`
      : this.control.hasError('min')
      ? `${this.fieldDisplayName} باید بیشتر از  ${
          this.control.errors.min.requiredLength
        } باشد.`
      : this.control.hasError('max')
      ? `${this.fieldDisplayName} باید کمتر از  ${
          this.control.errors.max.requiredLength
        } باشد.`
      : this.hasRule()
      ? this.findRule()
      : this.control.hasError('model')
      ? `${this.control.errors.model.messages[0]}`
      : '';
  }
  constructor() {}

  private hasRule() {
    return (
      this.rules &&
      Object.keys(this.control.errors).some(ruleKey =>
        this.rules[ruleKey] ? true : false
      )
    );
  }

  private findRule(): string {
    let message = '';
    Object.keys(this.control.errors).forEach(ruleKey => {
      if (this.rules[ruleKey]) {
        message += `${this.rules[ruleKey]} `;
      }
    });

    return message;
  }

  ngOnInit(): void {}
}

این کامپوننت، کنترل مورد نظر، یک نام نمایشی برای فیلد متناظر و یک شیء تحت عنوان rules را دریافت می‌کند. در بدنه پراپرتی message، به ترتیب اولویت validator، بررسی انجام شده و پیغام مناسب بازگشت داده خواهد شد. همچنین خطاهای سمت سروری هم که با کد "model" به لیست خطاهای کنترل اضافه شده اند نیز مورد بررسی قرار گرفته شده اند. 
 در اینجا اگر لازم باشد با یکسری قواعد سفارشی هم به صورت یکپارچه با اعتبارسنج‌های پیش فرض رفتار کنیم و از یک مسیر این پیغام‌ها نمایش داده شوند، می‌توان از خصوصیت rules بهره برد. به عنوان مثال:
 <mat-error *ngIf="form.controls['userName'].invalid && form.controls['userName'].touched" 
 class="mat-text-warn">
    <validation-message
        [control]="form.controls['userName']"
        fieldDisplayName="نام کاربری"
        [rules]="{rule1:'پیغام متناظر با rule1'}">
    </validation-message>
</mat-error>

به همراه یک Validator سفارشی
this.form = this.formBuilder.group({
      userName: [
        '',
        [Validators.required, UserNameValidators.rule1)]
      ],
      password: ['', Validators.required],
      rememberMe: [false]
    });

export class UserNameValidators{
   static rule1(control: AbstractControl) {
        if (control.value.indexOf(' ') >= 0) {
            return { rule1: true };
        }
        return null;
    }
}

مطالب
آموزش Linq - بخش ششم: عملگرهای پرس و جو قسمت چهارم
عملگر‌های تولید  Generation Operator

عملگر‌های تولید، برای ما توالی ایجاد می‌کنند و تفاوت‌های عمده‌ای با سایر عملگرهای پرس و جو دارند که در بخش زیر به آنها اشاره می‌کنیم:
 1- هیچ توالی ورودی را دریافت نمی‌کنند.
 2- این عملگر‌ها بصورت متد الحاقی پیاده سازی نشده‌اند و بصورت متد‌های استاتیک در کلاس Enumerable قرار گرفته‌اند.
امضاء زیر مربوط به متد Empty  می‌باشد:
 public static IEnumerable<TResult> Empty<TResult>()

Empty

عملگر Empty یک توالی بدون عنصر (Empty) را بر اساس نوع مشخص شده، ایجاد می‌کند.
در کد زیر نحوه ایجاد یک توالی خالی از نوع Ingredient نشان داده شده است.
IEnumerable<Ingredient> ingredients = Enumerable.Empty<Ingredient>();
Console.WriteLine(ingredients.Count());
خروجی کد بالا :
 0
پیاده سازی توسط عبارت‌های جستجو
معادل عملگر Empty، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

Range
عملگر پرس و جوی Range، یک توالی از مقادیر صحیح متوالی را برای ما ایجاد می‌کند. اولین پارامتر این عملگر عنصر آغاز کننده توالی است و دومین پارامتر این عملگر تعداد کل عناصر توالی تولید شده، با احتساب عنصر اول خواهد بود.
مثال:
IEnumerable<int> fiveToTen = Enumerable.Range(5,6);
foreach (var num in fiveToTen)
{
   Console.WriteLine(num);
}
خروجی مثال بالا:
5
6
7
8
9
10
همانطور که ملاحظه کردید مجموعا 6 عنصر برای توالی تولید شدند و اولین عنصر، با عدد 5 آغاز شده است.

پیاده سازی توسط عبارت‌های جستجو

معادل عملگر Range، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

Repeat
عملگر پرس و جوی Repeat یک عدد را به تعداد بار مشخصی در توالی خروجی تکرار می‌کند.
مثال:
IEnumerable<int> fiveToTen = Enumerable.Repeat(42, 6);
foreach (var num in fiveToTen)
{
    Console.WriteLine(num);
}
خروجی مثال بالا:
42
42
42
42
42
42
پیاده سازی توسط عبارت‌های جستجو
معادل عملگر Repeat، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.


عملگرهای  کمی (Quantifier Operators)
عملگرهای Quantifier یک توالی ورودی را گرفته، آن را ارزیابی کرده و یک مقدار منطقی را باز می‌گردانند.

عملگر Contains
عملگر Contains  عناصر یک توالی را ارزیابی می‌کند و در صورتیکه مقدار مورد نظر ما در توالی وجود داشته باشد، ارزش True باز می‌گرداند.
مثال:
int[] nums = {1, 2, 3};
bool isTowThere = nums.Contains(2);
bool isFiveThere = nums.Contains(5);

Console.WriteLine(isTowThere);
Console.WriteLine(isFiveThere);
خروجی مثال بالا :
True
False

پیاده سازی توسط عبارت‌های جستجو

معادل عملگر Contains، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

عملگر Any
عملگر Any دو امضاء مختلف را دارد:
 1- اولین امضاء: در صورتیکه توالی شامل حداقل یک عنصر باشد، ارزش True بازگردانده می‌شود.
 2- دومین امضاء: یک عبارت پیش بینی را قبول می‌کند. در صورتیکه حداقل یکی از عناصر توالی، عبارت پیش بینی را تامین کند، ارزش صحیح باز گردانده می‌شود.
مثال: بررسی امضاء اول عملگر Any
int[] nums = { 1, 2, 3 };
IEnumerable<int> noNums = Enumerable.Empty<int>();

Console.WriteLine(nums.Any());
Console.WriteLine(noNums.Any());
خروجی مثال بالا:
True
False
مثال: بررسی امضاء دوم عملگر Any
int[] nums = { 1, 2, 3 };
bool areAnyEvenNumbers = nums.Any(x => x % 2 == 0);
Console.WriteLine(areAnyEvenNumbers);
خروجی مثال بالا:
 True
در مثال بالا، عبارت پیش بینی مشخص می‌کند که اعداد زوج در توالی وجود داشته باشند یا خیر.

پیاده سازی توسط عبارت‌های جستجو
معادل عملگر Any، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

عملگر All
عملگر پرس و جوی All، یک عبارت پیش بینی را دریافت می‌کند و عناصر توالی ورودی را بر مبنای آن ارزیابی می‌کند تا مشخص شود همه عناصر، شرط پیش بینی را تامین می‌کنند.
در کد زیر بررسی می‌کنیم که آیا همه عناصر توالی مواد غذایی، جزء مواد غذایی کم چرب می‌باشند یا خیر .
Ingredient[] ingredients =
{
new Ingredient { Name = "Sugar", Calories = 500 },
new Ingredient { Name = "Egg", Calories = 100 },
new Ingredient { Name = "Milk", Calories = 150 },
new Ingredient { Name = "Flour", Calories = 50 },
new Ingredient { Name = "Butter", Calories = 400 }
};
bool isLowFatRecipe = ingredients.All(x => x.Calories < 200);
Console.WriteLine(isLowFatRecipe);
خروحی کد بالا :
False

نکته : عملگر All به محض پیدا کردن عنصری که شرط مشخص شده را نقض کند، ارزش False را باز می‌گرداند و ادامه بررسی عناصر باقی مانده را متوقف می‌کند.

پیاده سازی توسط عبارت‌های جستجو
معادل عملگر Any، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

عملگر SequenceEqual
عملگر SequenceEqual دو توالی را با هم مقایسه کرده و در صورتیکه عناصر هر دو توالی برابر و ترتیب قرار گیری آنها نیز یکسان باشند، ارزش True باز گردانده می‌شود.
مثال:
IEnumerable<int> sequence1 = new[] {1, 2, 3};
IEnumerable<int> sequence2 = new[] { 1, 2, 3 };
bool isSeqEqual = sequence1.SequenceEqual(sequence2);
Console.WriteLine(isSeqEqual);
خروجی مثال بالا:
 True

در صورتی که دو توالی عناصر یکسانی داشته باشند، ولی ترتیب قرار گیری عناصر با هم یکسان نباشند، عملگر ارزش False را باز می‌گرداند.
مثال :
IEnumerable<int> sequence1 = new[] { 1, 2, 3 };
IEnumerable<int> sequence2 = new[] { 3, 2, 1 };
bool isSeqEqual = sequence1.SequenceEqual(sequence2);
Console.WriteLine(isSeqEqual);
خروجی مثال بالا:
False
پیاده سازی توسط عبارت‌های جستجو
معادل عملگر SequenceEqual، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.
 
عملگر‌های تجمیع/تجمعی Aggregate Operators
عملگرهای Aggregate یک توالی ورودی را دریافت و یک مقدار عددی (Scalar Value) را باز می‌گردانند. مقدار بازگردانده شده، حاصل یک عملیات محاسباتی می‌باشد.
لیستی از عملگر‌های تجمیع ( Aggregate Operators ):
 • Count
 • LongCount
 • Sum
 • Min
 • Max
 • Average
 • Aggregate

عملگر Count
عملگر Count، تعداد عناصر توالی ورودی را باز می‌گرداند. عملگر Count، دو امضاء مختلف دارد. یکی از این امضاء‌ها یک عبارت پیش بینی را می‌پذیرد.
کد زیر، امضاء اول عملگر Count را نشان می‌دهد:
int[] nums = { 1, 2, 3 };
int numberOfElements = nums.Count();
Console.WriteLine(numberOfElements);
خروجی کد بالا:
 3

وقتی عبارت پیش بینی بکار گرفته می‌شود، عملگر Count تنها عناصری را که شرط را تامین کنند، شمارش می‌کند.
در کد زیر عملگر Count، همه عناصر زوج توالی ورودی را شمارش می‌کند:
int[] nums = { 1, 2, 3 };
int numberOfEvenElements = nums.Count(x => x % 2 == 0);
Console.WriteLine(numberOfEvenElements);
خروجی کد بالا :
1

پیاده سازی توسط عبارت‌های جستجو

معادل عملگر Count ، کلمه‌ی کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

عملگر LongCount
این عملگر مثل عملگر Count عمل می‌کند، اما با این تفاوت که خروجی آن به جای نوع int از نوع long می‌باشد. این عملگر برای شمارش توالی‌های  ورودی بسیار بزرگ مورد استفاده قرار می‌گیرد.

پیاده سازی توسط عبارت‌های جستجو

معادل عملگر LongCount، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

عملگر Sum

این عملگر  مجموع تمامی عناصر یک توالی را باز می‌گرداند.
در کد زیر جمع عناصر یک توالی از نوع int را مشاهده می‌کنید:
int[] nums = { 1, 2, 3 };
int total = nums.Sum();
Console.WriteLine(total);
خروجی کد بالا :
 6

عملگر Sum می‌تواند بر روی توالی‌هایی از نوع <IEnumerable<T و بر روی اعضای عددی آنها اعمال شود.
مثال:
Ingredient[] ingredients =
{
new Ingredient { Name = "Sugar", Calories = 500 },
new Ingredient { Name = "Egg", Calories = 100 },
new Ingredient { Name = "Milk", Calories = 150 },
new Ingredient { Name = "Flour", Calories = 50 },
new Ingredient { Name = "Butter", Calories = 400 }
};
int totalCalories = ingredients.Sum(x => x.Calories);
Console.WriteLine(totalCalories);
خروحی مثال بالا :
 1200

پیاده سازی توسط عبارت‌های جستجو

معادل عملگر Sum، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

عملگر Average

این عملگر میانگین عناصر توالی‌های عددی را محاسبه می‌کند.
مثال:
int[] nums = { 1, 2, 3 };
var avg = nums.Average();
Console.WriteLine(avg);
خروجی مثلا بالا :
 2

همانطور که در کد بالا مشاهده می‌کنید، نوع متغیر avg صراحتا مشخص نشده و از نوع var استفاده شده است. تابع average بر اساس توالی ورودی، انواع مختلفی از نوع داده‌های عددی را به خروجی ارسال می‌کند (double,float,decimal).
همانند عملگر Sum، عملگر Average می‌تواند بر روی اعضای عددی توالی‌هایی که از نوع<IEnumarable<T هستند، اعمال شود.
مثال:
Ingredient[] ingredients =
{
new Ingredient { Name = "Sugar", Calories = 500 },
new Ingredient { Name = "Egg", Calories = 100 },
new Ingredient { Name = "Milk", Calories = 150 },
new Ingredient { Name = "Flour", Calories = 50 },
new Ingredient { Name = "Butter", Calories = 400 }
};
var avgCalories = ingredients.Average(x => x.Calories);
Console.WriteLine(avgCalories);
خروجی مثال بالا :
 240

پیاده سازی توسط عبارت‌های جستجو

معادل عملگر Average، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

عملگر Min

عملگر Min کوچکترین عنصر توالی را باز می‌گرداند.
مثال:
int[] nums = { 3, 2, 1 };
var smallest = nums.Min();
Console.WriteLine(smallest);
خروجی مثال بالا:
 1
امضاء دیگر Min می‌تواند یک عبارت پیش بینی را بپذیرد:
مثال:
Ingredient[] ingredients =
{
new Ingredient { Name = "Sugar", Calories = 500 },
new Ingredient { Name = "Egg", Calories = 100 },
new Ingredient { Name = "Milk", Calories = 150 },
new Ingredient { Name = "Flour", Calories = 50 },
new Ingredient { Name = "Butter", Calories = 400 }
};
var smallestCalories = ingredients.Min(x => x.Calories);
Console.WriteLine(smallestCalories);

پیاده سازی توسط عبارت‌های جستجو
معادل عملگر Min ، کلمه کلیدی در عبارت‌های جستجو وجود ندارد.ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

عملگر Max
عملگر Max بزرگترین عنصر توالی را باز می‌گرداند.
مثال:
int[] nums = { 1 ,3, 2 };
var largest = nums.Max();
Console.WriteLine(largest);
خروجی مثال بالا:
 3
همچون عملگر Min، عملگر Max نیز یک امضاء دارد که می‌توان از طریق آن یک عبارت پیش بینی را مشخص کرد.

پیاده سازی توسط عبارت‌های جستجو

معادل عملگر Max، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.

Aggregate
عملگر‌های تجمعی که  تا اینجا معرفی شدند، تنها یک کار را انجام می‌دادند. اما عملگر Aggregate امکان تعریف یک پرس و جوی تجمیع سفارشی و پیشرفته‌تر را که بر روی توالی ورودی اعمال می‌شود نیز مهیا می‌کند.
عملگر Aggregate  دو نسخه دارد:
 1- نسخه‌ای که اجازه استفاده از یک عدد را به عنوان مقدار Seed، به ما می‌دهد (مقدار آغازین یا Seed).
 2- نسخه‌ای که از عنصر ابتدایی توالی به عنوان مقدار Seed استفاده می‌کند.
هر دو نسخه این عملگر به یک تابع  انباره (accumulator function) جهت نگهداری نتیجه نیاز دارند.
کد زیر شبیه سازی عملگر Sum  توسط عملگر Aggregate می‌باشد:
int[] nums = {1, 2, 3};
var result = nums.Aggregate(0,
(currentElement, runningTotal) => runningTotal + currentElement);
Console.WriteLine(result);
خروجی قطعه کد بالا:
 6
در قطعه کد بالا، نسخه‌ای از عملگر aggregate استفاده شد که مقدار شروع آن با عدد صفر مقدار دهی اولیه شد‌ه‌است.
کد زیر شبیه سازی عملیات فاکتوریل را با در نظر گرفتن عنصر اول توالی، به عنوان مقدار Seed نشان می‌دهد:
 int[] nums = { 1, 2, 3 ,4,5};
var result = nums.Aggregate((runningProduct, nextfactor) => runningProduct * nextfactor);
Console.WriteLine(result);
خروجی کد بالا:
 120

پیاده سازی توسط عبارت‌های جستجو

معادل عملگر Aggregate، کلمه کلیدی در عبارت‌های جستجو وجود ندارد. ترکیب دو روش می‌تواند خروجی دلخواه را تولید کند.
نظرات مطالب
EF Code First #12
طبق مطالبی که فرمودید جلو رفتم ولی یه سوال داشتم :
من یک کلاس پایه دارم و دو تا زیر کلاس . یک اینترفیس نوشتم که عملیات CRUD رو برای این دو کلاس انجام میده :
UnitOfWork رو طبق چیزی که گفتید نوشتم .
و اما اینترفیس رو به صورت زیر نوشتم :
  interface IPostService
    {
        void AddPost(Post post);
        IList<Post> GetPosts();
        Post GetPost(int PostId);
        int RemovePost(Post post);
        int UpdatePost(Post post);
    }
و کلاس زیر رو برای پیاده سازی اینترفیس بالا:
 public  class PostService<T>:IPostService where T:Post
    {
      private readonly IUnitOfWork _uow;
      private readonly IDbSet<T> _post;
      public PostService(IUnitOfWork uow)
      {
          _uow = uow;
          _post = _uow.Set<T>();
      }
        public void AddPost(T post)
        {}

        public IList<T> GetPosts()
        {}
//...
{
حال سوال من اینه : آیا به نظر شما بیام برای هر کدوم از زیر کلاس‌های یک کلاس جداگانه تعریف کنم یا همین چیزی که نوشتم درسته . مثلا یک کلاس برای subClassService, یکی برای Subclass2Service ؟