Coding around LINQ and EF Core

Coding around LINQ and EF Core

 

Filter values starting with "new" (LINQ)

Question:

Given a set of strings (array or list), return all values that start with "new" using LINQ.

Answer:

string[] items = { "newyork", "news", "oldtown", "newdelhi", "newton", "update" };

 

var result = items.Where(s => s.StartsWith("new", StringComparison.OrdinalIgnoreCase)).ToList();

 

foreach (var r in result)

{

    Console.WriteLine(r);

}

Output:

newyork

news

newdelhi

newton

 

 

Filter string values that start with the keyword "new"

string[] values = { "new item", "old item", "new product", "test", "news" };

 

// LINQ way

var result = values.Where(v => v.StartsWith("new", StringComparison.OrdinalIgnoreCase)).ToList();

 

foreach (var item in result)

{

    Console.WriteLine(item);

}

 

 

EF Core Variant of Same Question

Question:

From a table (say Cities), get all cities where the name starts with "new".

Assuming:

public class City

{

    public int Id { get; set; }

    public string Name { get; set; }

}

EF Core Query:

var cities = await _context.Cities

    .Where(c => EF.Functions.Like(c.Name, "new%"))

    .ToListAsync();

 

 

Return distinct values from a list of integers

var numbers = new List<int> { 1, 2, 2, 3, 4, 4, 5 };

var distinct = numbers.Distinct();

 

 

Get top 3 highest salaries from a list of employees

var topSalaries = employees

    .OrderByDescending(e => e.Salary)

    .Take(3)

    .ToList();

 

 

Group employees by department

var grouped = employees

    .GroupBy(e => e.Department)

    .Select(g => new {

        Department = g.Key,

        Count = g.Count()

    });

 

 

Join two lists (Employees and Departments)

var result = from e in employees

             join d in departments on e.DepartmentId equals d.Id

             select new { e.Name, Department = d.Name };

 

 

From EF Core: Find all customers with at least one invoice above 1000

var customers = _context.Customers

    .Where(c => c.Invoices.Any(i => i.Amount > 1000))

    .ToList();

 

 

Flatten nested collection using SelectMany

var allOrders = customers.SelectMany(c => c.Orders);

 

 

Project selected columns only (Anonymous Type)

var result = employees.Select(e => new {

    e.Id,

    e.Name

});

 

 

Count of records grouped by month

var monthlyCount = records

    .GroupBy(r => r.Date.Month)

    .Select(g => new { Month = g.Key, Count = g.Count() });

 

 

Use .Any(), .All() and .Contains() in LINQ

 

Use .Any(), .All() and .Contains() in LINQ

Any: Check if any employee is active

var hasActive = employees.Any(e => e.IsActive);

 

All: Check if all employees are full-time

var allFullTime = employees.All(e => e.IsFullTime);

 

Contains: Filter employees whose ID is in a given list

var selected = employees.Where(e => ids.Contains(e.Id));

 

Use EF.Functions.Like() in EF Core for LIKE queries

var search = _context.Users

    .Where(u => EF.Functions.Like(u.Email, "%@gmail.com"))

    .ToList();

 

 

Reverse a string array manually (without using Reverse())

string[] values = { "one", "two", "three", "four" };

string[] reversed = new string[values.Length];

 

for (int i = 0; i < values.Length; i++)

{

    reversed[i] = values[values.Length - 1 - i];

}

 

foreach (var item in reversed)

{

    Console.WriteLine(item);

}

 

 

Remove duplicates from a string list (without using Distinct)

List<string> list = new List<string> { "apple", "banana", "apple", "orange", "banana" };

List<string> unique = new List<string>();

 

foreach (var item in list)

{

    if (!unique.Contains(item))

    {

        unique.Add(item);

    }

}

 

foreach (var item in unique)

{

    Console.WriteLine(item);

}

 

 

Custom Grouping by First Character (without using GroupBy)

string[] names = { "Alice", "Aaron", "Bob", "Bella", "Charlie" };

var groupMap = new Dictionary<char, List<string>>();

 

foreach (var name in names)

{

    char firstChar = name[0];

    if (!groupMap.ContainsKey(firstChar))

        groupMap[firstChar] = new List<string>();

 

    groupMap[firstChar].Add(name);

}

 

// Print

foreach (var kv in groupMap)

{

    Console.WriteLine($"Group {kv.Key}: {string.Join(", ", kv.Value)}");

}

 

 

Check if two string arrays are equal (same elements, same order)

string[] a = { "one", "two", "three" };

string[] b = { "one", "two", "three" };

 

bool areEqual = true;

if (a.Length != b.Length)

{

    areEqual = false;

}

else

{

    for (int i = 0; i < a.Length; i++)

    {

        if (a[i] != b[i])

        {

            areEqual = false;

            break;

        }

    }

}

 

Console.WriteLine($"Arrays are equal: {areEqual}");

 

 

Sort a list of integers manually (Ascending - No OrderBy)

int[] numbers = { 5, 2, 9, 1, 5, 6 };

 

// Bubble sort

for (int i = 0; i < numbers.Length - 1; i++)

{

    for (int j = i + 1; j < numbers.Length; j++)

    {

        if (numbers[i] > numbers[j])

        {

            // Swap

            int temp = numbers[i];

            numbers[i] = numbers[j];

            numbers[j] = temp;

        }

    }

}

 

foreach (var n in numbers)

{

    Console.Write(n + " ");

}

 

 

Find the second highest number (No OrderBy, No Max)

int[] arr = { 10, 20, 5, 25, 8 };

 

int first = int.MinValue;

int second = int.MinValue;

 

foreach (int num in arr)

{

    if (num > first)

    {

        second = first;

        first = num;

    }

    else if (num > second && num != first)

    {

        second = num;

    }

}

 

Console.WriteLine($"Second highest: {second}");

 

 

Flatten a nested list of lists (Without SelectMany)

List<List<int>> nestedList = new List<List<int>> {

    new List<int> { 1, 2 },

    new List<int> { 3, 4 },

    new List<int> { 5 }

};

 

List<int> flatList = new List<int>();

 

foreach (var inner in nestedList)

{

    foreach (var item in inner)

    {

        flatList.Add(item);

    }

}

 

Console.WriteLine(string.Join(", ", flatList));

 

 

Convert list of objects to dictionary (No ToDictionary)

public class Product

{

    public int Id { get; set; }

    public string Name { get; set; }

}

 

List<Product> products = new List<Product>

{

    new Product { Id = 1, Name = "Pen" },

    new Product { Id = 2, Name = "Pencil" }

};

 

Dictionary<int, string> productDict = new Dictionary<int, string>();

 

foreach (var p in products)

{

    productDict[p.Id] = p.Name;

}

 

foreach (var kv in productDict)

{

    Console.WriteLine($"{kv.Key}: {kv.Value}");

}

 

 

EF Core - Get Budgets with Amount > 50000

var bigBudgets = await _context.Budgets

    .Where(b => b.Amount > 50000)

    .ToListAsync();

You could be asked to do projections (Select) or joins, e.g., budgets with project name.

 

 

EF Core Join: Get Invoice with Customer Name

var data = await _context.Invoices

    .Join(_context.Customers,

          invoice => invoice.CustomerId,

          customer => customer.Id,

          (invoice, customer) => new

          {

              invoice.Id,

              invoice.TotalAmount,

              CustomerName = customer.Name

          })

    .ToListAsync();

 

 

Count frequency of each character in a string

string input = "hello world";

Dictionary<char, int> frequency = new Dictionary<char, int>();

 

foreach (char c in input)

{

    if (c != ' ') // ignore spaces

    {

        if (frequency.ContainsKey(c))

            frequency[c]++;

        else

            frequency[c] = 1;

    }

}

 

foreach (var kv in frequency)

{

    Console.WriteLine($"{kv.Key} = {kv.Value}");

}

 

 

Check if two strings are anagrams (same letters, different order)

string a = "listen";

string b = "silent";

 

bool areAnagrams = true;

 

if (a.Length != b.Length)

{

    areAnagrams = false;

}

else

{

    char[] arrA = a.ToCharArray();

    char[] arrB = b.ToCharArray();

 

    Array.Sort(arrA);

    Array.Sort(arrB);

 

    for (int i = 0; i < arrA.Length; i++)

    {

        if (arrA[i] != arrB[i])

        {

            areAnagrams = false;

            break;

        }

    }

}

 

Console.WriteLine($"Anagrams: {areAnagrams}");

 

 

Generate 6-digit random OTP

Random rnd = new Random();

int otp = rnd.Next(100000, 999999);

Console.WriteLine("OTP: " + otp);

 

 

Assume you have these models:

public class Invoice

{

    public int Id { get; set; }

    public decimal Total { get; set; }

    public int CustomerId { get; set; }

    public Customer Customer { get; set; }

}

 

public class Customer

{

    public int Id { get; set; }

    public string Name { get; set; }

}

 

 

Get total invoice amount per customer

var result = await _context.Invoices

    .GroupBy(i => i.CustomerId)

    .Select(g => new

    {

        CustomerId = g.Key,

        TotalAmount = g.Sum(x => x.Total)

    })

    .ToListAsync();

 

 

Get customers with no invoices (LEFT JOIN)

var result = await _context.Customers

    .GroupJoin(_context.Invoices,

        customer => customer.Id,

        invoice => invoice.CustomerId,

        (customer, invoices) => new

        {

            customer.Name,

            InvoiceCount = invoices.Count()

        })

    .Where(x => x.InvoiceCount == 0)

    .ToListAsync();

 

 

Manual pagination (skip + take)

int page = 2;

int pageSize = 10;

 

var pagedData = await _context.Invoices

    .Skip((page - 1) * pageSize)

    .Take(pageSize)

    .ToListAsync();

 

 

Group Employees by Department and count

var result = await _context.Employees

    .GroupBy(e => e.Department)

    .Select(g => new

    {

        Department = g.Key,

        Count = g.Count()

    })

    .ToListAsync();

 

 

Print a matrix in spiral order (C# coding)

int[,] matrix = {

    { 1, 2, 3 },

    { 4, 5, 6 },

    { 7, 8, 9 }

};

 

int top = 0, bottom = matrix.GetLength(0) - 1;

int left = 0, right = matrix.GetLength(1) - 1;

 

while (top <= bottom && left <= right)

{

    for (int i = left; i <= right; i++) Console.Write(matrix[top, i] + " ");

    top++;

 

    for (int i = top; i <= bottom; i++) Console.Write(matrix[i, right] + " ");

    right--;

 

    if (top <= bottom)

    {

        for (int i = right; i >= left; i--) Console.Write(matrix[bottom, i] + " ");

        bottom--;

    }

 

    if (left <= right)

    {

        for (int i = bottom; i >= top; i--) Console.Write(matrix[i, left] + " ");

        left++;

    }

}

 

 

EF Core - Many-to-Many Query (e.g., Employee ↔ Projects)

Models:

public class Employee

{

    public int Id { get; set; }

    public string Name { get; set; }

    public ICollection<Project> Projects { get; set; }

}

 

public class Project

{

    public int Id { get; set; }

    public string Title { get; set; }

    public ICollection<Employee> Employees { get; set; }

}

Get all employees with their assigned project names:

var employeesWithProjects = await _context.Employees

    .Include(e => e.Projects)

    .Select(e => new

    {

        e.Name,

        Projects = e.Projects.Select(p => p.Title)

    })

    .ToListAsync();

 

 

Controller Logic – Add & Get Projects

[ApiController]

[Route("api/[controller]")]

public class ProjectsController : ControllerBase

{

    private readonly AppDbContext _context;

    public ProjectsController(AppDbContext context) => _context = context;

 

    [HttpPost]

    public async Task<IActionResult> AddProject([FromBody] Project project)

    {

        _context.Projects.Add(project);

        await _context.SaveChangesAsync();

        return Ok(project);

    }

 

    [HttpGet("{id}")]

    public async Task<IActionResult> GetProjectWithEmployees(int id)

    {

        var project = await _context.Projects

            .Include(p => p.Employees)

            .FirstOrDefaultAsync(p => p.Id == id);

 

        if (project == null)

            return NotFound();

 

        return Ok(project);

    }

}

 

 

Date Filter Example (Last 30 Days Invoices)

DateTime fromDate = DateTime.Now.AddDays(-30);

 

var recentInvoices = await _context.Invoices

    .Where(i => i.CreatedDate >= fromDate)

    .ToListAsync();

 

 

Dynamic Filter using Predicate Builder (Advanced LINQ)

Install: System.Linq.Dynamic.Core (optional)

var query = _context.Employees.AsQueryable();

 

if (!string.IsNullOrEmpty(name))

    query = query.Where(e => e.Name.Contains(name));

 

if (!string.IsNullOrEmpty(department))

    query = query.Where(e => e.Department == department);

 

if (minSalary.HasValue)

    query = query.Where(e => e.Salary >= minSalary);

 

var result = await query.ToListAsync();

 

 

Search API with Filters (Controller Example)

[HttpGet("search")]

public async Task<IActionResult> SearchEmployees(string? name, string? dept, decimal? minSalary)

{

    var result = await _employeeService.Search(name, dept, minSalary);

    return Ok(result);

}

 

 

Define a DTO (e.g., BudgetDto.cs)

public class BudgetDto

{

    public string ProjectName { get; set; }

    public decimal Amount { get; set; }

    public DateTime PlannedDate { get; set; }

}

 

 

Create a Validator (e.g., BudgetDtoValidator.cs)

using FluentValidation;

 

public class BudgetDtoValidator : AbstractValidator<BudgetDto>

{

    public BudgetDtoValidator()

    {

        RuleFor(x => x.ProjectName)

            .NotEmpty().WithMessage("Project name is required")

            .MinimumLength(3);

 

        RuleFor(x => x.Amount)

            .GreaterThan(0).WithMessage("Amount must be greater than zero");

 

        RuleFor(x => x.PlannedDate)

            .Must(date => date >= DateTime.Today)

            .WithMessage("Planned date cannot be in the past");

    }

}

 

 

Validate Manually in Service Layer

using FluentValidation;

 

public class BudgetService : IBudgetService

{

    private readonly IValidator<BudgetDto> _validator;

 

    public BudgetService(IValidator<BudgetDto> validator)

    {

        _validator = validator;

    }

 

    public async Task<Budget> CreateBudgetAsync(BudgetDto dto)

    {

        var validationResult = await _validator.ValidateAsync(dto);

 

        if (!validationResult.IsValid)

        {

            var errors = string.Join("; ", validationResult.Errors.Select(e => e.ErrorMessage));

            throw new AppException($"Validation failed: {errors}");

        }

 

        // Continue with DB logic after validation passes

        var budget = new Budget

        {

            ProjectName = dto.ProjectName,

            Amount = dto.Amount,

            PlannedDate = dto.PlannedDate

        };

 

        // Save to DB

        // _dbContext.Budgets.Add(budget);

        // await _dbContext.SaveChangesAsync();

 

        return budget;

    }

}

 

 

Register Validators in Program.cs

builder.Services.AddScoped<IValidator<BudgetDto>, BudgetDtoValidator>();

 

 Use in Controller (Simplified)

[HttpPost]

public async Task<IActionResult> Post([FromBody] BudgetDto dto)

{

    var budget = await _budgetService.CreateBudgetAsync(dto);

    return Ok(budget);

}

 

 

 

EmployeeDto + Validator

EmployeeDto.cs

public class EmployeeDto

{

    public string Name { get; set; }

    public string Email { get; set; }

    public string Mobile { get; set; }

    public DateTime JoiningDate { get; set; }

}

EmployeeDtoValidator.cs

using FluentValidation;

 

public class EmployeeDtoValidator : AbstractValidator<EmployeeDto>

{

    public EmployeeDtoValidator()

    {

        RuleFor(x => x.Name)

            .NotEmpty().WithMessage("Employee name is required")

            .MaximumLength(100);

 

        RuleFor(x => x.Email)

            .NotEmpty().WithMessage("Email is required")

            .EmailAddress().WithMessage("Invalid email format");

 

        RuleFor(x => x.Mobile)

            .Matches(@"^[6-9]\d{9}$").WithMessage("Invalid Indian mobile number");

 

        RuleFor(x => x.JoiningDate)

            .LessThanOrEqualTo(DateTime.Today).WithMessage("Joining date cannot be in the future");

    }

}

Register in DI

builder.Services.AddScoped<IValidator<EmployeeDto>, EmployeeDtoValidator>();

 

 

InvoiceDto + Validator

InvoiceDto.cs

public class InvoiceDto

{

    public string InvoiceNumber { get; set; }

    public DateTime Date { get; set; }

    public decimal TotalAmount { get; set; }

    public string CustomerName { get; set; }

}

InvoiceDtoValidator.cs

using FluentValidation;

 

public class InvoiceDtoValidator : AbstractValidator<InvoiceDto>

{

    public InvoiceDtoValidator()

    {

        RuleFor(x => x.InvoiceNumber)

            .NotEmpty().WithMessage("Invoice number is required");

 

        RuleFor(x => x.Date)

            .LessThanOrEqualTo(DateTime.Now).WithMessage("Invoice date cannot be in the future");

 

        RuleFor(x => x.TotalAmount)

            .GreaterThan(0).WithMessage("Invoice amount must be positive");

 

        RuleFor(x => x.CustomerName)

            .NotEmpty().WithMessage("Customer name is required");

    }

}

 

Global Registration for All Validators

In Program.cs:

// Automatically register all validators in the project assembly

builder.Services.AddValidatorsFromAssemblyContaining<BudgetDtoValidator>();

 

 

Unified Validation Error Response (Optional)

To customize validation error messages globally (like show property + error), update your ErrorHandlerMiddleware:

Update this block:

case FluentValidation.ValidationException e:

    response.StatusCode = 422;

    var errors = e.Errors.Select(x => new { field = x.PropertyName, error = x.ErrorMessage });

    result = JsonSerializer.Serialize(new { message = "Validation failed", errors });

    break;

Example JSON Output:

{

  "message": "Validation failed",

  "errors": [

    { "field": "Email", "error": "Invalid email format" },

    { "field": "Mobile", "error": "Invalid Indian mobile number" }

  ]

}

 

 

ErrorHandlerMiddleware.cs (Global Exception Handling)

using FluentValidation;

using Microsoft.AspNetCore.Http;

using Microsoft.EntityFrameworkCore;

using System;

using System.Linq;

using System.Net;

using System.Text.Json;

using System.Threading.Tasks;

 

namespace ConstructionWebAPI.Domain.Middleware

{

    public class ErrorHandlerMiddleware

    {

        private readonly RequestDelegate _next;

 

        public ErrorHandlerMiddleware(RequestDelegate next)

        {

            _next = next;

        }

 

        public async Task Invoke(HttpContext context)

        {

            try

            {

                await _next(context);

            }

            catch (Exception error)

            {

                var response = context.Response;

                response.ContentType = "application/json";

 

                string result;

                switch (error)

                {

                    case AppException e:

                        response.StatusCode = (int)HttpStatusCode.BadRequest;

                        result = JsonSerializer.Serialize(new { message = e.Message });

                        break;

                    case KeyNotFoundException:

                        response.StatusCode = (int)HttpStatusCode.NotFound;

                        result = JsonSerializer.Serialize(new { message = error.Message });

                        break;

                    case UnauthorizedAccessException:

                        response.StatusCode = (int)HttpStatusCode.Unauthorized;

                        result = JsonSerializer.Serialize(new { message = "Unauthorized" });

                        break;

                    case DbUpdateException:

                        response.StatusCode = (int)HttpStatusCode.Conflict;

                        result = JsonSerializer.Serialize(new { message = "Database update error" });

                        break;

                    case FluentValidation.ValidationException e:

                        response.StatusCode = 422;

                        result = JsonSerializer.Serialize(new

                        {

                            message = "Validation failed",

                            errors = e.Errors.Select(x => new { x.PropertyName, x.ErrorMessage })

                        });

                        break;

                    default:

                        response.StatusCode = (int)HttpStatusCode.InternalServerError;

                        result = JsonSerializer.Serialize(new { message = "An error occurred" });

                        break;

                }

 

                await response.WriteAsync(result);

            }

        }

    }

}

 

Startup Configuration (Program.cs)

builder.Services.AddValidatorsFromAssemblyContaining<BudgetDtoValidator>(); // Scan all validators

app.UseMiddleware<ErrorHandlerMiddleware>(); // Plug global error middleware early

  

Comments

Popular posts from this blog

Debouncing & Throttling in RxJS: Optimizing API Calls and User Interactions

Promises in Angular

Comprehensive Guide to C# and .NET Core OOP Concepts and Language Features