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
Post a Comment