Skip to content

Commit

Permalink
feat(employees-earning-more-than-their-managers): solve with C# and SQL
Browse files Browse the repository at this point in the history
  • Loading branch information
HamidMolareza committed Nov 2, 2024
1 parent 9f3fe82 commit a95a027
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<RootNamespace>ConsoleSharpTemplate</RootNamespace>
</PropertyGroup>

<ItemGroup>
<Content Include="..\.dockerignore">
<Link>.dockerignore</Link>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.10">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
<PackageReference Include="MySql.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Npgsql" Version="8.0.5" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.10" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;

namespace ConsoleSharpTemplate.Data;

public partial class AppDbContext : DbContext
{
public AppDbContext()
{
}

public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}

public virtual DbSet<Employee> Employees { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see https://go.microsoft.com/fwlink/?LinkId=723263.
=> optionsBuilder.UseSqlServer();

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>(entity =>
{
entity.HasKey(e => e.EmpId).HasName("PK__Employee__AFB3EC0D97B476C6");

entity.ToTable("Employee");

entity.Property(e => e.EmpId)
.ValueGeneratedNever()
.HasColumnName("empId");
entity.Property(e => e.ManagerId).HasColumnName("managerId");
entity.Property(e => e.Name)
.HasMaxLength(50)
.HasColumnName("name");
entity.Property(e => e.Salary).HasColumnName("salary");
});

OnModelCreatingPartial(modelBuilder);
}

partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;

namespace ConsoleSharpTemplate.Data;

public partial class Employee
{
public int EmpId { get; set; }

public string? Name { get; set; }

public int? Salary { get; set; }

public int? ManagerId { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace ConsoleSharpTemplate.Helpers;

public static class PrintHelpers {
public static void Print(this IEnumerable<object> table) {
var objects = table.ToList();
var props = objects.First().GetType().GetProperties();

//Print header
var headers = props.Select(prop => prop.Name);
var header = string.Join('\t', headers);
Console.WriteLine(header);
var separator = string.Join(string.Empty, Enumerable.Repeat("-", header.Length));
Console.WriteLine(separator);

//Print Items
var allItems = objects.Select(obj =>
props.Select(prop => prop.GetValue(obj)));
foreach (var rowItems in allItems) {
Console.WriteLine(string.Join('\t', rowItems));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Diagnostics;
using System.Text;

namespace ConsoleSharpTemplate.Helpers;

public static class RunTime {
public static TResult Print<TResult>(Func<TResult> func, string title) {
var stopWatch = new Stopwatch();
stopWatch.Start();

var result = func();

stopWatch.Stop();
var elapsedTime = stopWatch.Elapsed.Format();
Console.WriteLine($"{title}: {elapsedTime}");

return result;
}

public static async Task<TResult> Print<TResult>(Func<Task<TResult>> funcAsync, string title) {
var stopWatch = new Stopwatch();
stopWatch.Start();

var result = await funcAsync();

stopWatch.Stop();
var elapsedTime = stopWatch.Elapsed.Format();
Console.WriteLine($"{title}: {elapsedTime}");

return result;
}

public static void Print(Action action, string title) {
var stopWatch = new Stopwatch();
stopWatch.Start();

action();

stopWatch.Stop();
var elapsedTime = stopWatch.Elapsed.Format();
Console.WriteLine($"{title}: {elapsedTime}");
}

private static string Format(this TimeSpan timeSpan) {
var formattedTime = new StringBuilder();
if (timeSpan.Hours > 0)
formattedTime.Append($"{timeSpan.Hours:00}h ");
if (timeSpan.Minutes > 0)
formattedTime.Append($"{timeSpan.Minutes:00}m ");
if (timeSpan.Seconds > 0)
formattedTime.Append($"{timeSpan.Seconds:00}s ");
formattedTime.Append($"{timeSpan.Milliseconds}ms");

return formattedTime.ToString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using ConsoleSharpTemplate.Data;
using ConsoleSharpTemplate.Helpers;
using Microsoft.Data.SqlClient;

Console.WriteLine("Application Starting...");

try {
var result = RunTime.Print(Solution, "Query");
result.Print();
}
catch (InvalidOperationException ex) {
Console.WriteLine($"Error: {ex.Message}");
}
catch (SqlException ex) {
Console.WriteLine($"Database error occurred: {ex}");
}


return;
static IQueryable<object> Solution() {
var db = new AppDbContext();

var result = db.Employees
.Where(e => e.ManagerId.HasValue)
.Join(
db.Employees,
e => e.ManagerId,
m => m.EmpId,
(e, m) => new { Employee = e, Manager = m }
)
.Where(em => em.Employee.Salary > em.Manager.Salary)
.Select(em => new {Employee = em.Employee.Name});

return result;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/bash

# Function to display the help message
show_help() {
echo "Usage: $(basename "$0") <connection_string> [output_models] [dbcontext_name]"
echo
echo "Arguments:"
echo " connection_string The database connection string."
echo " output_models (Optional) Directory to output the scaffolded models. Defaults to 'Data'."
echo " dbcontext_name The name of the DbContext. Defaults: AppDbContext"
echo
echo "Sample Connection Strings:"
echo " SqlServer: Server=localhost,1433;Database=LeetCode;User Id=SA;Password=PASS; TrustServerCertificate=True;"
echo " Postgresql: Host=localhost;Port=5432;Database=LeetCode;Username=myusername;Password=PASS;"
echo " MySQL: Server=localhost;Port=3306;Database=LeetCode;User=myusername;Password=PASS;"
echo " Sqlite: Data Source=app.db"
exit 1
}

# Check if the connection string is provided
connection_string="$1"
if [ -z "$connection_string" ]; then
echo "Error: Connection string is required."
show_help
fi

# Set the output directory for the models, default to 'Data' if not provided
output_models="${2:-Data}"

dbcontext_name="${3:-AppDbContext}"

# Check if 'dotnet ef' is installed
if ! command -v dotnet &> /dev/null || ! dotnet ef &> /dev/null; then
echo "Error: 'dotnet ef' is not installed or not available in the PATH."
echo "Please install the EF Core tools by running: dotnet tool install --global dotnet-ef"
exit 1
fi

# Scaffold the DbContext and models
dotnet ef dbcontext scaffold "$connection_string" Microsoft.EntityFrameworkCore.SqlServer -o "$output_models" -c "$dbcontext_name"

# Check if the command was successful
if [ $? -eq 0 ]; then
echo "Scaffolding completed successfully. Models output in '$output_models'."
else
echo "Error: Scaffolding failed."
exit 1
fi

0 comments on commit a95a027

Please sign in to comment.