mirror of
https://github.com/markjprice/cs11dotnet7.git
synced 2026-01-23 00:10:18 +01:00
Initial commit
This commit is contained in:
parent
dd097904c2
commit
2b1f5c1254
|
|
@ -0,0 +1,25 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Console" Static="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Northwind.db">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
40
vs4win/Chapter11/Ch11Ex02LinqQueries/Customer.cs
Normal file
40
vs4win/Chapter11/Ch11Ex02LinqQueries/Customer.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Customer
|
||||
{
|
||||
[StringLength(5)]
|
||||
public string CustomerId { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[StringLength(40)]
|
||||
public string CompanyName { get; set; } = null!;
|
||||
|
||||
[StringLength(30)]
|
||||
public string? ContactName { get; set; }
|
||||
|
||||
[StringLength(30)]
|
||||
public string? ContactTitle { get; set; }
|
||||
|
||||
[StringLength(60)]
|
||||
public string? Address { get; set; }
|
||||
|
||||
[StringLength(15)]
|
||||
public string? City { get; set; }
|
||||
|
||||
[StringLength(15)]
|
||||
public string? Region { get; set; }
|
||||
|
||||
[StringLength(10)]
|
||||
public string? PostalCode { get; set; }
|
||||
|
||||
[StringLength(15)]
|
||||
public string? Country { get; set; }
|
||||
|
||||
[StringLength(24)]
|
||||
public string? Phone { get; set; }
|
||||
|
||||
[StringLength(24)]
|
||||
public string? Fax { get; set; }
|
||||
}
|
||||
16
vs4win/Chapter11/Ch11Ex02LinqQueries/Northwind.cs
Normal file
16
vs4win/Chapter11/Ch11Ex02LinqQueries/Northwind.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using Microsoft.EntityFrameworkCore; // DbContext, DbSet<T>
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Northwind : DbContext
|
||||
{
|
||||
public DbSet<Customer> Customers { get; set; } = null!;
|
||||
|
||||
protected override void OnConfiguring(
|
||||
DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "Northwind.db");
|
||||
string connection = $"Filename={path}";
|
||||
optionsBuilder.UseSqlite(connection);
|
||||
}
|
||||
}
|
||||
BIN
vs4win/Chapter11/Ch11Ex02LinqQueries/Northwind.db
Normal file
BIN
vs4win/Chapter11/Ch11Ex02LinqQueries/Northwind.db
Normal file
Binary file not shown.
8722
vs4win/Chapter11/Ch11Ex02LinqQueries/Northwind4SQLite.sql
Normal file
8722
vs4win/Chapter11/Ch11Ex02LinqQueries/Northwind4SQLite.sql
Normal file
File diff suppressed because it is too large
Load diff
28
vs4win/Chapter11/Ch11Ex02LinqQueries/Program.cs
Normal file
28
vs4win/Chapter11/Ch11Ex02LinqQueries/Program.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Packt.Shared; // Northwind, Customer
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
IQueryable<string?> distinctCities =
|
||||
db.Customers.Select(c => c.City).Distinct();
|
||||
|
||||
WriteLine("A list of cities that at least one customer resides in:");
|
||||
WriteLine($"{string.Join(", ", distinctCities)}");
|
||||
WriteLine();
|
||||
|
||||
Write("Enter the name of a city: ");
|
||||
string city = ReadLine()!;
|
||||
|
||||
IQueryable<Customer> customersInCity = db.Customers.Where(c => c.City == city);
|
||||
|
||||
if (customersInCity is null)
|
||||
{
|
||||
WriteLine($"No customers found in {city}.");
|
||||
return;
|
||||
}
|
||||
|
||||
WriteLine($"There are {customersInCity.Count()} customers in {city}:");
|
||||
foreach (Customer c in customersInCity)
|
||||
{
|
||||
WriteLine($" {c.CompanyName}");
|
||||
}
|
||||
}
|
||||
43
vs4win/Chapter11/Chapter11.sln
Normal file
43
vs4win/Chapter11/Chapter11.sln
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32210.308
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinqWithObjects", "LinqWithObjects\LinqWithObjects.csproj", "{0712B93E-C502-4E33-8B92-698596682A76}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinqWithEFCore", "LinqWithEFCore\LinqWithEFCore.csproj", "{44EB1A3F-C3E2-4072-B336-61D61FE5BC59}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinqInParallel", "LinqInParallel\LinqInParallel.csproj", "{5962169C-AC14-4B9D-A079-0D8D293CD65C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch11Ex02LinqQueries", "Ch11Ex02LinqQueries\Ch11Ex02LinqQueries.csproj", "{F972829E-E7F1-4A1B-99EB-E582C5329BBC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0712B93E-C502-4E33-8B92-698596682A76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0712B93E-C502-4E33-8B92-698596682A76}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0712B93E-C502-4E33-8B92-698596682A76}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0712B93E-C502-4E33-8B92-698596682A76}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{44EB1A3F-C3E2-4072-B336-61D61FE5BC59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{44EB1A3F-C3E2-4072-B336-61D61FE5BC59}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{44EB1A3F-C3E2-4072-B336-61D61FE5BC59}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{44EB1A3F-C3E2-4072-B336-61D61FE5BC59}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5962169C-AC14-4B9D-A079-0D8D293CD65C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5962169C-AC14-4B9D-A079-0D8D293CD65C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5962169C-AC14-4B9D-A079-0D8D293CD65C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5962169C-AC14-4B9D-A079-0D8D293CD65C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F972829E-E7F1-4A1B-99EB-E582C5329BBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F972829E-E7F1-4A1B-99EB-E582C5329BBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F972829E-E7F1-4A1B-99EB-E582C5329BBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F972829E-E7F1-4A1B-99EB-E582C5329BBC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {6FFEB3ED-7D40-4114-AB17-601B64A8FCE5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
14
vs4win/Chapter11/LinqInParallel/LinqInParallel.csproj
Normal file
14
vs4win/Chapter11/LinqInParallel/LinqInParallel.csproj
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Console" Static="true" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
36
vs4win/Chapter11/LinqInParallel/Program.cs
Normal file
36
vs4win/Chapter11/LinqInParallel/Program.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System.Diagnostics; // Stopwatch
|
||||
|
||||
Write("Press ENTER to start. "); ReadLine();
|
||||
Stopwatch watch = Stopwatch.StartNew();
|
||||
|
||||
int max = 45;
|
||||
IEnumerable<int> numbers = Enumerable.Range(start: 1, count: max);
|
||||
|
||||
WriteLine($"Calculating Fibonacci sequence up to term {max}. Please wait...");
|
||||
|
||||
// int[] fibonacciNumbers = numbers
|
||||
// .Select(number => Fibonacci(number))
|
||||
// .ToArray();
|
||||
|
||||
int[] fibonacciNumbers = numbers.AsParallel()
|
||||
.Select(number => Fibonacci(number))
|
||||
.OrderBy(number => number)
|
||||
.ToArray();
|
||||
|
||||
watch.Stop();
|
||||
WriteLine("{0:#,##0} elapsed milliseconds.",
|
||||
arg0: watch.ElapsedMilliseconds);
|
||||
|
||||
Write("Results:");
|
||||
foreach (int number in fibonacciNumbers)
|
||||
{
|
||||
Write($" {number:N0}");
|
||||
}
|
||||
|
||||
static int Fibonacci(int term) =>
|
||||
term switch
|
||||
{
|
||||
1 => 0,
|
||||
2 => 1,
|
||||
_ => Fibonacci(term - 1) + Fibonacci(term - 2)
|
||||
};
|
||||
14
vs4win/Chapter11/LinqWithEFCore/Category.cs
Normal file
14
vs4win/Chapter11/LinqWithEFCore/Category.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Category
|
||||
{
|
||||
public int CategoryId { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(15)]
|
||||
public string CategoryName { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
28
vs4win/Chapter11/LinqWithEFCore/LinqWithEFCore.csproj
Normal file
28
vs4win/Chapter11/LinqWithEFCore/LinqWithEFCore.csproj
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Console" Static="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Northwind.db">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="settings.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
78
vs4win/Chapter11/LinqWithEFCore/MyLinqExtensions.cs
Normal file
78
vs4win/Chapter11/LinqWithEFCore/MyLinqExtensions.cs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
namespace System.Linq; // extend Microsoft's namespace
|
||||
|
||||
public static class MyLinqExtensions
|
||||
{
|
||||
// this is a chainable LINQ extension method
|
||||
public static IEnumerable<T> ProcessSequence<T>(
|
||||
this IEnumerable<T> sequence)
|
||||
{
|
||||
// you could do some processing here
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public static IQueryable<T> ProcessSequence<T>(
|
||||
this IQueryable<T> sequence)
|
||||
{
|
||||
// you could do some processing here
|
||||
return sequence;
|
||||
}
|
||||
|
||||
// these are scalar LINQ extension methods
|
||||
public static int? Median(
|
||||
this IEnumerable<int?> sequence)
|
||||
{
|
||||
var ordered = sequence.OrderBy(item => item);
|
||||
int middlePosition = ordered.Count() / 2;
|
||||
return ordered.ElementAt(middlePosition);
|
||||
}
|
||||
|
||||
public static int? Median<T>(
|
||||
this IEnumerable<T> sequence, Func<T, int?> selector)
|
||||
{
|
||||
return sequence.Select(selector).Median();
|
||||
}
|
||||
|
||||
public static decimal? Median(
|
||||
this IEnumerable<decimal?> sequence)
|
||||
{
|
||||
var ordered = sequence.OrderBy(item => item);
|
||||
int middlePosition = ordered.Count() / 2;
|
||||
return ordered.ElementAt(middlePosition);
|
||||
}
|
||||
|
||||
public static decimal? Median<T>(
|
||||
this IEnumerable<T> sequence, Func<T, decimal?> selector)
|
||||
{
|
||||
return sequence.Select(selector).Median();
|
||||
}
|
||||
|
||||
public static int? Mode(
|
||||
this IEnumerable<int?> sequence)
|
||||
{
|
||||
var grouped = sequence.GroupBy(item => item);
|
||||
var orderedGroups = grouped.OrderByDescending(
|
||||
group => group.Count());
|
||||
return orderedGroups.FirstOrDefault()?.Key;
|
||||
}
|
||||
|
||||
public static int? Mode<T>(
|
||||
this IEnumerable<T> sequence, Func<T, int?> selector)
|
||||
{
|
||||
return sequence.Select(selector)?.Mode();
|
||||
}
|
||||
|
||||
public static decimal? Mode(
|
||||
this IEnumerable<decimal?> sequence)
|
||||
{
|
||||
var grouped = sequence.GroupBy(item => item);
|
||||
var orderedGroups = grouped.OrderByDescending(
|
||||
group => group.Count());
|
||||
return orderedGroups.FirstOrDefault()?.Key;
|
||||
}
|
||||
|
||||
public static decimal? Mode<T>(
|
||||
this IEnumerable<T> sequence, Func<T, decimal?> selector)
|
||||
{
|
||||
return sequence.Select(selector).Mode();
|
||||
}
|
||||
}
|
||||
38
vs4win/Chapter11/LinqWithEFCore/Northwind.cs
Normal file
38
vs4win/Chapter11/LinqWithEFCore/Northwind.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
using Microsoft.EntityFrameworkCore; // DbContext, DbSet<T>
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Northwind : DbContext
|
||||
{
|
||||
public DbSet<Category> Categories { get; set; } = null!;
|
||||
public DbSet<Product> Products { get; set; } = null!;
|
||||
|
||||
protected override void OnConfiguring(
|
||||
DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
string path = Path.Combine(
|
||||
Environment.CurrentDirectory, "Northwind.db");
|
||||
|
||||
optionsBuilder.UseSqlite($"Filename={path}");
|
||||
|
||||
/*
|
||||
string connection = "Data Source=.;" +
|
||||
"Initial Catalog=Northwind;" +
|
||||
"Integrated Security=true;" +
|
||||
"MultipleActiveResultSets=true;";
|
||||
|
||||
optionsBuilder.UseSqlServer(connection);
|
||||
*/
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(
|
||||
ModelBuilder modelBuilder)
|
||||
{
|
||||
if (Database.ProviderName.Contains("Sqlite"))
|
||||
{
|
||||
modelBuilder.Entity<Product>()
|
||||
.Property(product => product.UnitPrice)
|
||||
.HasConversion<double>();
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
vs4win/Chapter11/LinqWithEFCore/Northwind.db
Normal file
BIN
vs4win/Chapter11/LinqWithEFCore/Northwind.db
Normal file
Binary file not shown.
8722
vs4win/Chapter11/LinqWithEFCore/Northwind4SQLite.sql
Normal file
8722
vs4win/Chapter11/LinqWithEFCore/Northwind4SQLite.sql
Normal file
File diff suppressed because it is too large
Load diff
27
vs4win/Chapter11/LinqWithEFCore/Product.cs
Normal file
27
vs4win/Chapter11/LinqWithEFCore/Product.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Product
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(40)]
|
||||
public string ProductName { get; set; } = null!;
|
||||
|
||||
public int? SupplierId { get; set; }
|
||||
public int? CategoryId { get; set; }
|
||||
|
||||
[StringLength(20)]
|
||||
public string? QuantityPerUnit { get; set; }
|
||||
|
||||
[Column(TypeName = "money")] // required for SQL Server provider
|
||||
public decimal? UnitPrice { get; set; }
|
||||
|
||||
public short? UnitsInStock { get; set; }
|
||||
public short? UnitsOnOrder { get; set; }
|
||||
public short? ReorderLevel { get; set; }
|
||||
public bool Discontinued { get; set; }
|
||||
}
|
||||
205
vs4win/Chapter11/LinqWithEFCore/Program.Functions.cs
Normal file
205
vs4win/Chapter11/LinqWithEFCore/Program.Functions.cs
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
using Packt.Shared; // Northwind, Category, Product
|
||||
using Microsoft.EntityFrameworkCore; // DbSet<T>
|
||||
using System.Xml.Linq; // XElement, XAttribute
|
||||
|
||||
partial class Program
|
||||
{
|
||||
static void FilterAndSort()
|
||||
{
|
||||
SectionTitle("Filter and sort");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
DbSet<Product> allProducts = db.Products;
|
||||
|
||||
IQueryable<Product> processedProducts = allProducts.ProcessSequence();
|
||||
|
||||
IQueryable<Product> filteredProducts =
|
||||
processedProducts.Where(product => product.UnitPrice < 10M);
|
||||
|
||||
IOrderedQueryable<Product> sortedAndFilteredProducts =
|
||||
filteredProducts.OrderByDescending(product => product.UnitPrice);
|
||||
|
||||
var projectedProducts = sortedAndFilteredProducts
|
||||
.Select(product => new // anonymous type
|
||||
{
|
||||
product.ProductId,
|
||||
product.ProductName,
|
||||
product.UnitPrice
|
||||
});
|
||||
|
||||
WriteLine(projectedProducts.ToQueryString());
|
||||
|
||||
WriteLine("Products that cost less than $10:");
|
||||
|
||||
foreach (var p in projectedProducts)
|
||||
{
|
||||
WriteLine("{0}: {1} costs {2:$#,##0.00}",
|
||||
p.ProductId, p.ProductName, p.UnitPrice);
|
||||
}
|
||||
WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
static void JoinCategoriesAndProducts()
|
||||
{
|
||||
SectionTitle("Join categories and products");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
// join every product to its category to return 77 matches
|
||||
var queryJoin = db.Categories.Join(
|
||||
inner: db.Products,
|
||||
outerKeySelector: category => category.CategoryId,
|
||||
innerKeySelector: product => product.CategoryId,
|
||||
resultSelector: (c, p) =>
|
||||
new { c.CategoryName, p.ProductName, p.ProductId })
|
||||
.OrderBy(cp => cp.CategoryName);
|
||||
|
||||
foreach (var item in queryJoin)
|
||||
{
|
||||
WriteLine("{0}: {1} is in {2}.",
|
||||
arg0: item.ProductId,
|
||||
arg1: item.ProductName,
|
||||
arg2: item.CategoryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GroupJoinCategoriesAndProducts()
|
||||
{
|
||||
SectionTitle("Group join categories and products");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
// group all products by their category to return 8 matches
|
||||
var queryGroup = db.Categories.AsEnumerable().GroupJoin(
|
||||
inner: db.Products,
|
||||
outerKeySelector: category => category.CategoryId,
|
||||
innerKeySelector: product => product.CategoryId,
|
||||
resultSelector: (c, matchingProducts) => new
|
||||
{
|
||||
c.CategoryName,
|
||||
Products = matchingProducts.OrderBy(p => p.ProductName)
|
||||
});
|
||||
|
||||
foreach (var category in queryGroup)
|
||||
{
|
||||
WriteLine("{0} has {1} products.",
|
||||
arg0: category.CategoryName,
|
||||
arg1: category.Products.Count());
|
||||
|
||||
foreach (var product in category.Products)
|
||||
{
|
||||
WriteLine($" {product.ProductName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void AggregateProducts()
|
||||
{
|
||||
SectionTitle("Aggregate products");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
WriteLine("{0,-25} {1,10}",
|
||||
arg0: "Product count:",
|
||||
arg1: db.Products.Count());
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
arg0: "Highest product price:",
|
||||
arg1: db.Products.Max(p => p.UnitPrice));
|
||||
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
arg0: "Sum of units in stock:",
|
||||
arg1: db.Products.Sum(p => p.UnitsInStock));
|
||||
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
arg0: "Sum of units on order:",
|
||||
arg1: db.Products.Sum(p => p.UnitsOnOrder));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
arg0: "Average unit price:",
|
||||
arg1: db.Products.Average(p => p.UnitPrice));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
arg0: "Value of units in stock:",
|
||||
arg1: db.Products
|
||||
.Sum(p => p.UnitPrice * p.UnitsInStock));
|
||||
}
|
||||
}
|
||||
|
||||
static void CustomExtensionMethods()
|
||||
{
|
||||
SectionTitle("Custom aggregate extension methods");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
"Mean units in stock:",
|
||||
db.Products.Average(p => p.UnitsInStock));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
"Mean unit price:",
|
||||
db.Products.Average(p => p.UnitPrice));
|
||||
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
"Median units in stock:",
|
||||
db.Products.Median(p => p.UnitsInStock));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
"Median unit price:",
|
||||
db.Products.Median(p => p.UnitPrice));
|
||||
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
"Mode units in stock:",
|
||||
db.Products.Mode(p => p.UnitsInStock));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
"Mode unit price:",
|
||||
db.Products.Mode(p => p.UnitPrice));
|
||||
}
|
||||
}
|
||||
|
||||
static void OutputProductsAsXml()
|
||||
{
|
||||
SectionTitle("Output products as XML");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
Product[] productsArray = db.Products.ToArray();
|
||||
|
||||
XElement xml = new("products",
|
||||
from p in productsArray
|
||||
select new XElement("product",
|
||||
new XAttribute("id", p.ProductId),
|
||||
new XAttribute("price", p.UnitPrice),
|
||||
new XElement("name", p.ProductName)));
|
||||
|
||||
WriteLine(xml.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessSettings()
|
||||
{
|
||||
string path = Path.Combine(
|
||||
Environment.CurrentDirectory, "settings.xml");
|
||||
|
||||
WriteLine($"Settings file path: {path}");
|
||||
XDocument doc = XDocument.Load(path);
|
||||
|
||||
var appSettings = doc.Descendants("appSettings")
|
||||
.Descendants("add")
|
||||
.Select(node => new
|
||||
{
|
||||
Key = node.Attribute("key")?.Value,
|
||||
Value = node.Attribute("value")?.Value
|
||||
}).ToArray();
|
||||
|
||||
foreach (var item in appSettings)
|
||||
{
|
||||
WriteLine($"{item.Key}: {item.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
12
vs4win/Chapter11/LinqWithEFCore/Program.Helpers.cs
Normal file
12
vs4win/Chapter11/LinqWithEFCore/Program.Helpers.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
partial class Program
|
||||
{
|
||||
static void SectionTitle(string title)
|
||||
{
|
||||
ConsoleColor previousColor = ForegroundColor;
|
||||
ForegroundColor = ConsoleColor.DarkYellow;
|
||||
WriteLine("*");
|
||||
WriteLine($"* {title}");
|
||||
WriteLine("*");
|
||||
ForegroundColor = previousColor;
|
||||
}
|
||||
}
|
||||
13
vs4win/Chapter11/LinqWithEFCore/Program.cs
Normal file
13
vs4win/Chapter11/LinqWithEFCore/Program.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// FilterAndSort();
|
||||
|
||||
// JoinCategoriesAndProducts();
|
||||
|
||||
// GroupJoinCategoriesAndProducts();
|
||||
|
||||
// AggregateProducts();
|
||||
|
||||
// CustomExtensionMethods();
|
||||
|
||||
// OutputProductsAsXml();
|
||||
|
||||
ProcessSettings();
|
||||
6
vs4win/Chapter11/LinqWithEFCore/settings.xml
Normal file
6
vs4win/Chapter11/LinqWithEFCore/settings.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<appSettings>
|
||||
<add key="color" value="red" />
|
||||
<add key="size" value="large" />
|
||||
<add key="price" value="23.99" />
|
||||
</appSettings>
|
||||
15
vs4win/Chapter11/LinqWithObjects/LinqWithObjects.csproj
Normal file
15
vs4win/Chapter11/LinqWithObjects/LinqWithObjects.csproj
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Console" Static="true" />
|
||||
<!--<Using Remove="System.Linq" />-->
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
9
vs4win/Chapter11/LinqWithObjects/Program.Functions.cs
Normal file
9
vs4win/Chapter11/LinqWithObjects/Program.Functions.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
partial class Program
|
||||
{
|
||||
static bool NameLongerThanFour(string name)
|
||||
{
|
||||
return name.Length > 4;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
23
vs4win/Chapter11/LinqWithObjects/Program.Helpers.cs
Normal file
23
vs4win/Chapter11/LinqWithObjects/Program.Helpers.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
partial class Program
|
||||
{
|
||||
static void SectionTitle(string title)
|
||||
{
|
||||
ConsoleColor previousColor = ForegroundColor;
|
||||
ForegroundColor = ConsoleColor.DarkYellow;
|
||||
WriteLine("*");
|
||||
WriteLine($"* {title}");
|
||||
WriteLine("*");
|
||||
ForegroundColor = previousColor;
|
||||
}
|
||||
|
||||
static void Output(IEnumerable<string> cohort, string description = "")
|
||||
{
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
{
|
||||
WriteLine(description);
|
||||
}
|
||||
Write(" ");
|
||||
WriteLine(string.Join(", ", cohort.ToArray()));
|
||||
WriteLine();
|
||||
}
|
||||
}
|
||||
97
vs4win/Chapter11/LinqWithObjects/Program.cs
Normal file
97
vs4win/Chapter11/LinqWithObjects/Program.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// a string array is a sequence that implements IEnumerable<string>
|
||||
string[] names = new[] { "Michael", "Pam", "Jim", "Dwight",
|
||||
"Angela", "Kevin", "Toby", "Creed" };
|
||||
|
||||
SectionTitle("Deferred execution");
|
||||
|
||||
// Question: Which names end with an M?
|
||||
// (written using a LINQ extension method)
|
||||
var query1 = names.Where(name => name.EndsWith("m"));
|
||||
|
||||
// Question: Which names end with an M?
|
||||
// (written using LINQ query comprehension syntax)
|
||||
var query2 = from name in names where name.EndsWith("m") select name;
|
||||
|
||||
// Answer returned as an array of strings containing Pam and Jim
|
||||
string[] result1 = query1.ToArray();
|
||||
|
||||
// Answer returned as a list of strings containing Pam and Jim
|
||||
List<string> result2 = query2.ToList();
|
||||
|
||||
// Answer returned as we enumerate over the results
|
||||
foreach (string name in query1)
|
||||
{
|
||||
WriteLine(name); // outputs Pam
|
||||
names[2] = "Jimmy"; // change Jim to Jimmy
|
||||
// on the second iteration Jimmy does not end with an M
|
||||
}
|
||||
|
||||
SectionTitle("Writing queries");
|
||||
|
||||
// Where requires a Func<T, T> delegate instance...
|
||||
// var query = names.Where(
|
||||
// new Func<string, bool>(NameLongerThanFour));
|
||||
|
||||
// ...but the compiler can create it for us...
|
||||
// var query = names.Where(NameLongerThanFour);
|
||||
|
||||
// ...or we can use a lambda expression.
|
||||
IOrderedEnumerable<string> query = names
|
||||
.Where(name => name.Length > 4)
|
||||
.OrderBy(name => name.Length)
|
||||
.ThenBy(name => name);
|
||||
|
||||
foreach (string item in query)
|
||||
{
|
||||
WriteLine(item);
|
||||
}
|
||||
|
||||
SectionTitle("Filtering by type");
|
||||
|
||||
List<Exception> exceptions = new()
|
||||
{
|
||||
new ArgumentException(),
|
||||
new SystemException(),
|
||||
new IndexOutOfRangeException(),
|
||||
new InvalidOperationException(),
|
||||
new NullReferenceException(),
|
||||
new InvalidCastException(),
|
||||
new OverflowException(),
|
||||
new DivideByZeroException(),
|
||||
new ApplicationException()
|
||||
};
|
||||
|
||||
IEnumerable<ArithmeticException> arithmeticExceptionsQuery =
|
||||
exceptions.OfType<ArithmeticException>();
|
||||
|
||||
foreach (ArithmeticException exception in arithmeticExceptionsQuery)
|
||||
{
|
||||
WriteLine(exception);
|
||||
}
|
||||
|
||||
string[] cohort1 = new[]
|
||||
{ "Rachel", "Gareth", "Jonathan", "George" };
|
||||
|
||||
string[] cohort2 = new[]
|
||||
{ "Jack", "Stephen", "Daniel", "Jack", "Jared" };
|
||||
|
||||
string[] cohort3 = new[]
|
||||
{ "Declan", "Jack", "Jack", "Jasmine", "Conor" };
|
||||
|
||||
SectionTitle("The cohorts");
|
||||
|
||||
Output(cohort1, "Cohort 1");
|
||||
Output(cohort2, "Cohort 2");
|
||||
Output(cohort3, "Cohort 3");
|
||||
|
||||
SectionTitle("Set operations");
|
||||
|
||||
Output(cohort2.Distinct(), "cohort2.Distinct()");
|
||||
Output(cohort2.DistinctBy(name => name.Substring(0, 2)),
|
||||
"cohort2.DistinctBy(name => name.Substring(0, 2)):");
|
||||
Output(cohort2.Union(cohort3), "cohort2.Union(cohort3)");
|
||||
Output(cohort2.Concat(cohort3), "cohort2.Concat(cohort3)");
|
||||
Output(cohort2.Intersect(cohort3), "cohort2.Intersect(cohort3)");
|
||||
Output(cohort2.Except(cohort3), "cohort2.Except(cohort3)");
|
||||
Output(cohort1.Zip(cohort2, (c1, c2) => $"{c1} matched with {c2}"),
|
||||
"cohort1.Zip(cohort2)");
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Console" Static="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Northwind.db">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
40
vscode/Chapter11/Ch11Ex02LinqQueries/Customer.cs
Normal file
40
vscode/Chapter11/Ch11Ex02LinqQueries/Customer.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Customer
|
||||
{
|
||||
[StringLength(5)]
|
||||
public string CustomerId { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[StringLength(40)]
|
||||
public string CompanyName { get; set; } = null!;
|
||||
|
||||
[StringLength(30)]
|
||||
public string? ContactName { get; set; }
|
||||
|
||||
[StringLength(30)]
|
||||
public string? ContactTitle { get; set; }
|
||||
|
||||
[StringLength(60)]
|
||||
public string? Address { get; set; }
|
||||
|
||||
[StringLength(15)]
|
||||
public string? City { get; set; }
|
||||
|
||||
[StringLength(15)]
|
||||
public string? Region { get; set; }
|
||||
|
||||
[StringLength(10)]
|
||||
public string? PostalCode { get; set; }
|
||||
|
||||
[StringLength(15)]
|
||||
public string? Country { get; set; }
|
||||
|
||||
[StringLength(24)]
|
||||
public string? Phone { get; set; }
|
||||
|
||||
[StringLength(24)]
|
||||
public string? Fax { get; set; }
|
||||
}
|
||||
16
vscode/Chapter11/Ch11Ex02LinqQueries/Northwind.cs
Normal file
16
vscode/Chapter11/Ch11Ex02LinqQueries/Northwind.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using Microsoft.EntityFrameworkCore; // DbContext, DbSet<T>
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Northwind : DbContext
|
||||
{
|
||||
public DbSet<Customer> Customers { get; set; } = null!;
|
||||
|
||||
protected override void OnConfiguring(
|
||||
DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
string path = Path.Combine(Environment.CurrentDirectory, "Northwind.db");
|
||||
string connection = $"Filename={path}";
|
||||
optionsBuilder.UseSqlite(connection);
|
||||
}
|
||||
}
|
||||
BIN
vscode/Chapter11/Ch11Ex02LinqQueries/Northwind.db
Normal file
BIN
vscode/Chapter11/Ch11Ex02LinqQueries/Northwind.db
Normal file
Binary file not shown.
8722
vscode/Chapter11/Ch11Ex02LinqQueries/Northwind4SQLite.sql
Normal file
8722
vscode/Chapter11/Ch11Ex02LinqQueries/Northwind4SQLite.sql
Normal file
File diff suppressed because it is too large
Load diff
28
vscode/Chapter11/Ch11Ex02LinqQueries/Program.cs
Normal file
28
vscode/Chapter11/Ch11Ex02LinqQueries/Program.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Packt.Shared; // Northwind, Customer
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
IQueryable<string?> distinctCities =
|
||||
db.Customers.Select(c => c.City).Distinct();
|
||||
|
||||
WriteLine("A list of cities that at least one customer resides in:");
|
||||
WriteLine($"{string.Join(", ", distinctCities)}");
|
||||
WriteLine();
|
||||
|
||||
Write("Enter the name of a city: ");
|
||||
string city = ReadLine()!;
|
||||
|
||||
IQueryable<Customer> customersInCity = db.Customers.Where(c => c.City == city);
|
||||
|
||||
if (customersInCity is null)
|
||||
{
|
||||
WriteLine($"No customers found in {city}.");
|
||||
return;
|
||||
}
|
||||
|
||||
WriteLine($"There are {customersInCity.Count()} customers in {city}:");
|
||||
foreach (Customer c in customersInCity)
|
||||
{
|
||||
WriteLine($" {c.CompanyName}");
|
||||
}
|
||||
}
|
||||
16
vscode/Chapter11/Chapter11.code-workspace
Normal file
16
vscode/Chapter11/Chapter11.code-workspace
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "LinqWithObjects"
|
||||
},
|
||||
{
|
||||
"path": "LinqWithEFCore"
|
||||
},
|
||||
{
|
||||
"path": "LinqInParallel"
|
||||
},
|
||||
{
|
||||
"path": "Ch11Ex02LinqQueries"
|
||||
}
|
||||
]
|
||||
}
|
||||
14
vscode/Chapter11/LinqInParallel/LinqInParallel.csproj
Normal file
14
vscode/Chapter11/LinqInParallel/LinqInParallel.csproj
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Console" Static="true" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
36
vscode/Chapter11/LinqInParallel/Program.cs
Normal file
36
vscode/Chapter11/LinqInParallel/Program.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System.Diagnostics; // Stopwatch
|
||||
|
||||
Write("Press ENTER to start. "); ReadLine();
|
||||
Stopwatch watch = Stopwatch.StartNew();
|
||||
|
||||
int max = 45;
|
||||
IEnumerable<int> numbers = Enumerable.Range(start: 1, count: max);
|
||||
|
||||
WriteLine($"Calculating Fibonacci sequence up to term {max}. Please wait...");
|
||||
|
||||
// int[] fibonacciNumbers = numbers
|
||||
// .Select(number => Fibonacci(number))
|
||||
// .ToArray();
|
||||
|
||||
int[] fibonacciNumbers = numbers.AsParallel()
|
||||
.Select(number => Fibonacci(number))
|
||||
.OrderBy(number => number)
|
||||
.ToArray();
|
||||
|
||||
watch.Stop();
|
||||
WriteLine("{0:#,##0} elapsed milliseconds.",
|
||||
arg0: watch.ElapsedMilliseconds);
|
||||
|
||||
Write("Results:");
|
||||
foreach (int number in fibonacciNumbers)
|
||||
{
|
||||
Write($" {number:N0}");
|
||||
}
|
||||
|
||||
static int Fibonacci(int term) =>
|
||||
term switch
|
||||
{
|
||||
1 => 0,
|
||||
2 => 1,
|
||||
_ => Fibonacci(term - 1) + Fibonacci(term - 2)
|
||||
};
|
||||
14
vscode/Chapter11/LinqWithEFCore/Category.cs
Normal file
14
vscode/Chapter11/LinqWithEFCore/Category.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Category
|
||||
{
|
||||
public int CategoryId { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(15)]
|
||||
public string CategoryName { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
28
vscode/Chapter11/LinqWithEFCore/LinqWithEFCore.csproj
Normal file
28
vscode/Chapter11/LinqWithEFCore/LinqWithEFCore.csproj
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Console" Static="true" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Northwind.db">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="settings.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
78
vscode/Chapter11/LinqWithEFCore/MyLinqExtensions.cs
Normal file
78
vscode/Chapter11/LinqWithEFCore/MyLinqExtensions.cs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
namespace System.Linq; // extend Microsoft's namespace
|
||||
|
||||
public static class MyLinqExtensions
|
||||
{
|
||||
// this is a chainable LINQ extension method
|
||||
public static IEnumerable<T> ProcessSequence<T>(
|
||||
this IEnumerable<T> sequence)
|
||||
{
|
||||
// you could do some processing here
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public static IQueryable<T> ProcessSequence<T>(
|
||||
this IQueryable<T> sequence)
|
||||
{
|
||||
// you could do some processing here
|
||||
return sequence;
|
||||
}
|
||||
|
||||
// these are scalar LINQ extension methods
|
||||
public static int? Median(
|
||||
this IEnumerable<int?> sequence)
|
||||
{
|
||||
var ordered = sequence.OrderBy(item => item);
|
||||
int middlePosition = ordered.Count() / 2;
|
||||
return ordered.ElementAt(middlePosition);
|
||||
}
|
||||
|
||||
public static int? Median<T>(
|
||||
this IEnumerable<T> sequence, Func<T, int?> selector)
|
||||
{
|
||||
return sequence.Select(selector).Median();
|
||||
}
|
||||
|
||||
public static decimal? Median(
|
||||
this IEnumerable<decimal?> sequence)
|
||||
{
|
||||
var ordered = sequence.OrderBy(item => item);
|
||||
int middlePosition = ordered.Count() / 2;
|
||||
return ordered.ElementAt(middlePosition);
|
||||
}
|
||||
|
||||
public static decimal? Median<T>(
|
||||
this IEnumerable<T> sequence, Func<T, decimal?> selector)
|
||||
{
|
||||
return sequence.Select(selector).Median();
|
||||
}
|
||||
|
||||
public static int? Mode(
|
||||
this IEnumerable<int?> sequence)
|
||||
{
|
||||
var grouped = sequence.GroupBy(item => item);
|
||||
var orderedGroups = grouped.OrderByDescending(
|
||||
group => group.Count());
|
||||
return orderedGroups.FirstOrDefault()?.Key;
|
||||
}
|
||||
|
||||
public static int? Mode<T>(
|
||||
this IEnumerable<T> sequence, Func<T, int?> selector)
|
||||
{
|
||||
return sequence.Select(selector)?.Mode();
|
||||
}
|
||||
|
||||
public static decimal? Mode(
|
||||
this IEnumerable<decimal?> sequence)
|
||||
{
|
||||
var grouped = sequence.GroupBy(item => item);
|
||||
var orderedGroups = grouped.OrderByDescending(
|
||||
group => group.Count());
|
||||
return orderedGroups.FirstOrDefault()?.Key;
|
||||
}
|
||||
|
||||
public static decimal? Mode<T>(
|
||||
this IEnumerable<T> sequence, Func<T, decimal?> selector)
|
||||
{
|
||||
return sequence.Select(selector).Mode();
|
||||
}
|
||||
}
|
||||
38
vscode/Chapter11/LinqWithEFCore/Northwind.cs
Normal file
38
vscode/Chapter11/LinqWithEFCore/Northwind.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
using Microsoft.EntityFrameworkCore; // DbContext, DbSet<T>
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Northwind : DbContext
|
||||
{
|
||||
public DbSet<Category> Categories { get; set; } = null!;
|
||||
public DbSet<Product> Products { get; set; } = null!;
|
||||
|
||||
protected override void OnConfiguring(
|
||||
DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
string path = Path.Combine(
|
||||
Environment.CurrentDirectory, "Northwind.db");
|
||||
|
||||
optionsBuilder.UseSqlite($"Filename={path}");
|
||||
|
||||
/*
|
||||
string connection = "Data Source=.;" +
|
||||
"Initial Catalog=Northwind;" +
|
||||
"Integrated Security=true;" +
|
||||
"MultipleActiveResultSets=true;";
|
||||
|
||||
optionsBuilder.UseSqlServer(connection);
|
||||
*/
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(
|
||||
ModelBuilder modelBuilder)
|
||||
{
|
||||
if (Database.ProviderName.Contains("Sqlite"))
|
||||
{
|
||||
modelBuilder.Entity<Product>()
|
||||
.Property(product => product.UnitPrice)
|
||||
.HasConversion<double>();
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
vscode/Chapter11/LinqWithEFCore/Northwind.db
Normal file
BIN
vscode/Chapter11/LinqWithEFCore/Northwind.db
Normal file
Binary file not shown.
8722
vscode/Chapter11/LinqWithEFCore/Northwind4SQLite.sql
Normal file
8722
vscode/Chapter11/LinqWithEFCore/Northwind4SQLite.sql
Normal file
File diff suppressed because it is too large
Load diff
27
vscode/Chapter11/LinqWithEFCore/Product.cs
Normal file
27
vscode/Chapter11/LinqWithEFCore/Product.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Packt.Shared;
|
||||
|
||||
public class Product
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(40)]
|
||||
public string ProductName { get; set; } = null!;
|
||||
|
||||
public int? SupplierId { get; set; }
|
||||
public int? CategoryId { get; set; }
|
||||
|
||||
[StringLength(20)]
|
||||
public string? QuantityPerUnit { get; set; }
|
||||
|
||||
[Column(TypeName = "money")] // required for SQL Server provider
|
||||
public decimal? UnitPrice { get; set; }
|
||||
|
||||
public short? UnitsInStock { get; set; }
|
||||
public short? UnitsOnOrder { get; set; }
|
||||
public short? ReorderLevel { get; set; }
|
||||
public bool Discontinued { get; set; }
|
||||
}
|
||||
205
vscode/Chapter11/LinqWithEFCore/Program.Functions.cs
Normal file
205
vscode/Chapter11/LinqWithEFCore/Program.Functions.cs
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
using Packt.Shared; // Northwind, Category, Product
|
||||
using Microsoft.EntityFrameworkCore; // DbSet<T>
|
||||
using System.Xml.Linq; // XElement, XAttribute
|
||||
|
||||
partial class Program
|
||||
{
|
||||
static void FilterAndSort()
|
||||
{
|
||||
SectionTitle("Filter and sort");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
DbSet<Product> allProducts = db.Products;
|
||||
|
||||
IQueryable<Product> processedProducts = allProducts.ProcessSequence();
|
||||
|
||||
IQueryable<Product> filteredProducts =
|
||||
processedProducts.Where(product => product.UnitPrice < 10M);
|
||||
|
||||
IOrderedQueryable<Product> sortedAndFilteredProducts =
|
||||
filteredProducts.OrderByDescending(product => product.UnitPrice);
|
||||
|
||||
var projectedProducts = sortedAndFilteredProducts
|
||||
.Select(product => new // anonymous type
|
||||
{
|
||||
product.ProductId,
|
||||
product.ProductName,
|
||||
product.UnitPrice
|
||||
});
|
||||
|
||||
WriteLine(projectedProducts.ToQueryString());
|
||||
|
||||
WriteLine("Products that cost less than $10:");
|
||||
|
||||
foreach (var p in projectedProducts)
|
||||
{
|
||||
WriteLine("{0}: {1} costs {2:$#,##0.00}",
|
||||
p.ProductId, p.ProductName, p.UnitPrice);
|
||||
}
|
||||
WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
static void JoinCategoriesAndProducts()
|
||||
{
|
||||
SectionTitle("Join categories and products");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
// join every product to its category to return 77 matches
|
||||
var queryJoin = db.Categories.Join(
|
||||
inner: db.Products,
|
||||
outerKeySelector: category => category.CategoryId,
|
||||
innerKeySelector: product => product.CategoryId,
|
||||
resultSelector: (c, p) =>
|
||||
new { c.CategoryName, p.ProductName, p.ProductId })
|
||||
.OrderBy(cp => cp.CategoryName);
|
||||
|
||||
foreach (var item in queryJoin)
|
||||
{
|
||||
WriteLine("{0}: {1} is in {2}.",
|
||||
arg0: item.ProductId,
|
||||
arg1: item.ProductName,
|
||||
arg2: item.CategoryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void GroupJoinCategoriesAndProducts()
|
||||
{
|
||||
SectionTitle("Group join categories and products");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
// group all products by their category to return 8 matches
|
||||
var queryGroup = db.Categories.AsEnumerable().GroupJoin(
|
||||
inner: db.Products,
|
||||
outerKeySelector: category => category.CategoryId,
|
||||
innerKeySelector: product => product.CategoryId,
|
||||
resultSelector: (c, matchingProducts) => new
|
||||
{
|
||||
c.CategoryName,
|
||||
Products = matchingProducts.OrderBy(p => p.ProductName)
|
||||
});
|
||||
|
||||
foreach (var category in queryGroup)
|
||||
{
|
||||
WriteLine("{0} has {1} products.",
|
||||
arg0: category.CategoryName,
|
||||
arg1: category.Products.Count());
|
||||
|
||||
foreach (var product in category.Products)
|
||||
{
|
||||
WriteLine($" {product.ProductName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void AggregateProducts()
|
||||
{
|
||||
SectionTitle("Aggregate products");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
WriteLine("{0,-25} {1,10}",
|
||||
arg0: "Product count:",
|
||||
arg1: db.Products.Count());
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
arg0: "Highest product price:",
|
||||
arg1: db.Products.Max(p => p.UnitPrice));
|
||||
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
arg0: "Sum of units in stock:",
|
||||
arg1: db.Products.Sum(p => p.UnitsInStock));
|
||||
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
arg0: "Sum of units on order:",
|
||||
arg1: db.Products.Sum(p => p.UnitsOnOrder));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
arg0: "Average unit price:",
|
||||
arg1: db.Products.Average(p => p.UnitPrice));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
arg0: "Value of units in stock:",
|
||||
arg1: db.Products
|
||||
.Sum(p => p.UnitPrice * p.UnitsInStock));
|
||||
}
|
||||
}
|
||||
|
||||
static void CustomExtensionMethods()
|
||||
{
|
||||
SectionTitle("Custom aggregate extension methods");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
"Mean units in stock:",
|
||||
db.Products.Average(p => p.UnitsInStock));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
"Mean unit price:",
|
||||
db.Products.Average(p => p.UnitPrice));
|
||||
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
"Median units in stock:",
|
||||
db.Products.Median(p => p.UnitsInStock));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
"Median unit price:",
|
||||
db.Products.Median(p => p.UnitPrice));
|
||||
|
||||
WriteLine("{0,-25} {1,10:N0}",
|
||||
"Mode units in stock:",
|
||||
db.Products.Mode(p => p.UnitsInStock));
|
||||
|
||||
WriteLine("{0,-25} {1,10:$#,##0.00}",
|
||||
"Mode unit price:",
|
||||
db.Products.Mode(p => p.UnitPrice));
|
||||
}
|
||||
}
|
||||
|
||||
static void OutputProductsAsXml()
|
||||
{
|
||||
SectionTitle("Output products as XML");
|
||||
|
||||
using (Northwind db = new())
|
||||
{
|
||||
Product[] productsArray = db.Products.ToArray();
|
||||
|
||||
XElement xml = new("products",
|
||||
from p in productsArray
|
||||
select new XElement("product",
|
||||
new XAttribute("id", p.ProductId),
|
||||
new XAttribute("price", p.UnitPrice),
|
||||
new XElement("name", p.ProductName)));
|
||||
|
||||
WriteLine(xml.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessSettings()
|
||||
{
|
||||
string path = Path.Combine(
|
||||
Environment.CurrentDirectory, "settings.xml");
|
||||
|
||||
WriteLine($"Settings file path: {path}");
|
||||
XDocument doc = XDocument.Load(path);
|
||||
|
||||
var appSettings = doc.Descendants("appSettings")
|
||||
.Descendants("add")
|
||||
.Select(node => new
|
||||
{
|
||||
Key = node.Attribute("key")?.Value,
|
||||
Value = node.Attribute("value")?.Value
|
||||
}).ToArray();
|
||||
|
||||
foreach (var item in appSettings)
|
||||
{
|
||||
WriteLine($"{item.Key}: {item.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
12
vscode/Chapter11/LinqWithEFCore/Program.Helpers.cs
Normal file
12
vscode/Chapter11/LinqWithEFCore/Program.Helpers.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
partial class Program
|
||||
{
|
||||
static void SectionTitle(string title)
|
||||
{
|
||||
ConsoleColor previousColor = ForegroundColor;
|
||||
ForegroundColor = ConsoleColor.DarkYellow;
|
||||
WriteLine("*");
|
||||
WriteLine($"* {title}");
|
||||
WriteLine("*");
|
||||
ForegroundColor = previousColor;
|
||||
}
|
||||
}
|
||||
13
vscode/Chapter11/LinqWithEFCore/Program.cs
Normal file
13
vscode/Chapter11/LinqWithEFCore/Program.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// FilterAndSort();
|
||||
|
||||
// JoinCategoriesAndProducts();
|
||||
|
||||
// GroupJoinCategoriesAndProducts();
|
||||
|
||||
// AggregateProducts();
|
||||
|
||||
// CustomExtensionMethods();
|
||||
|
||||
// OutputProductsAsXml();
|
||||
|
||||
ProcessSettings();
|
||||
6
vscode/Chapter11/LinqWithEFCore/settings.xml
Normal file
6
vscode/Chapter11/LinqWithEFCore/settings.xml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<appSettings>
|
||||
<add key="color" value="red" />
|
||||
<add key="size" value="large" />
|
||||
<add key="price" value="23.99" />
|
||||
</appSettings>
|
||||
15
vscode/Chapter11/LinqWithObjects/LinqWithObjects.csproj
Normal file
15
vscode/Chapter11/LinqWithObjects/LinqWithObjects.csproj
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Console" Static="true" />
|
||||
<!--<Using Remove="System.Linq" />-->
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
9
vscode/Chapter11/LinqWithObjects/Program.Functions.cs
Normal file
9
vscode/Chapter11/LinqWithObjects/Program.Functions.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
partial class Program
|
||||
{
|
||||
static bool NameLongerThanFour(string name)
|
||||
{
|
||||
return name.Length > 4;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
23
vscode/Chapter11/LinqWithObjects/Program.Helpers.cs
Normal file
23
vscode/Chapter11/LinqWithObjects/Program.Helpers.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
partial class Program
|
||||
{
|
||||
static void SectionTitle(string title)
|
||||
{
|
||||
ConsoleColor previousColor = ForegroundColor;
|
||||
ForegroundColor = ConsoleColor.DarkYellow;
|
||||
WriteLine("*");
|
||||
WriteLine($"* {title}");
|
||||
WriteLine("*");
|
||||
ForegroundColor = previousColor;
|
||||
}
|
||||
|
||||
static void Output(IEnumerable<string> cohort, string description = "")
|
||||
{
|
||||
if (!string.IsNullOrEmpty(description))
|
||||
{
|
||||
WriteLine(description);
|
||||
}
|
||||
Write(" ");
|
||||
WriteLine(string.Join(", ", cohort.ToArray()));
|
||||
WriteLine();
|
||||
}
|
||||
}
|
||||
97
vscode/Chapter11/LinqWithObjects/Program.cs
Normal file
97
vscode/Chapter11/LinqWithObjects/Program.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// a string array is a sequence that implements IEnumerable<string>
|
||||
string[] names = new[] { "Michael", "Pam", "Jim", "Dwight",
|
||||
"Angela", "Kevin", "Toby", "Creed" };
|
||||
|
||||
SectionTitle("Deferred execution");
|
||||
|
||||
// Question: Which names end with an M?
|
||||
// (written using a LINQ extension method)
|
||||
var query1 = names.Where(name => name.EndsWith("m"));
|
||||
|
||||
// Question: Which names end with an M?
|
||||
// (written using LINQ query comprehension syntax)
|
||||
var query2 = from name in names where name.EndsWith("m") select name;
|
||||
|
||||
// Answer returned as an array of strings containing Pam and Jim
|
||||
string[] result1 = query1.ToArray();
|
||||
|
||||
// Answer returned as a list of strings containing Pam and Jim
|
||||
List<string> result2 = query2.ToList();
|
||||
|
||||
// Answer returned as we enumerate over the results
|
||||
foreach (string name in query1)
|
||||
{
|
||||
WriteLine(name); // outputs Pam
|
||||
names[2] = "Jimmy"; // change Jim to Jimmy
|
||||
// on the second iteration Jimmy does not end with an M
|
||||
}
|
||||
|
||||
SectionTitle("Writing queries");
|
||||
|
||||
// Where requires a Func<T, T> delegate instance...
|
||||
// var query = names.Where(
|
||||
// new Func<string, bool>(NameLongerThanFour));
|
||||
|
||||
// ...but the compiler can create it for us...
|
||||
// var query = names.Where(NameLongerThanFour);
|
||||
|
||||
// ...or we can use a lambda expression.
|
||||
IOrderedEnumerable<string> query = names
|
||||
.Where(name => name.Length > 4)
|
||||
.OrderBy(name => name.Length)
|
||||
.ThenBy(name => name);
|
||||
|
||||
foreach (string item in query)
|
||||
{
|
||||
WriteLine(item);
|
||||
}
|
||||
|
||||
SectionTitle("Filtering by type");
|
||||
|
||||
List<Exception> exceptions = new()
|
||||
{
|
||||
new ArgumentException(),
|
||||
new SystemException(),
|
||||
new IndexOutOfRangeException(),
|
||||
new InvalidOperationException(),
|
||||
new NullReferenceException(),
|
||||
new InvalidCastException(),
|
||||
new OverflowException(),
|
||||
new DivideByZeroException(),
|
||||
new ApplicationException()
|
||||
};
|
||||
|
||||
IEnumerable<ArithmeticException> arithmeticExceptionsQuery =
|
||||
exceptions.OfType<ArithmeticException>();
|
||||
|
||||
foreach (ArithmeticException exception in arithmeticExceptionsQuery)
|
||||
{
|
||||
WriteLine(exception);
|
||||
}
|
||||
|
||||
string[] cohort1 = new[]
|
||||
{ "Rachel", "Gareth", "Jonathan", "George" };
|
||||
|
||||
string[] cohort2 = new[]
|
||||
{ "Jack", "Stephen", "Daniel", "Jack", "Jared" };
|
||||
|
||||
string[] cohort3 = new[]
|
||||
{ "Declan", "Jack", "Jack", "Jasmine", "Conor" };
|
||||
|
||||
SectionTitle("The cohorts");
|
||||
|
||||
Output(cohort1, "Cohort 1");
|
||||
Output(cohort2, "Cohort 2");
|
||||
Output(cohort3, "Cohort 3");
|
||||
|
||||
SectionTitle("Set operations");
|
||||
|
||||
Output(cohort2.Distinct(), "cohort2.Distinct()");
|
||||
Output(cohort2.DistinctBy(name => name.Substring(0, 2)),
|
||||
"cohort2.DistinctBy(name => name.Substring(0, 2)):");
|
||||
Output(cohort2.Union(cohort3), "cohort2.Union(cohort3)");
|
||||
Output(cohort2.Concat(cohort3), "cohort2.Concat(cohort3)");
|
||||
Output(cohort2.Intersect(cohort3), "cohort2.Intersect(cohort3)");
|
||||
Output(cohort2.Except(cohort3), "cohort2.Except(cohort3)");
|
||||
Output(cohort1.Zip(cohort2, (c1, c2) => $"{c1} matched with {c2}"),
|
||||
"cohort1.Zip(cohort2)");
|
||||
Loading…
Reference in a new issue