Skip to content

Commit

Permalink
What's new: queries (#4058)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcvickers committed Sep 27, 2022
1 parent 0a06aca commit 7b62d0c
Show file tree
Hide file tree
Showing 12 changed files with 1,586 additions and 1 deletion.
451 changes: 450 additions & 1 deletion entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md

Large diffs are not rendered by default.

125 changes: 125 additions & 0 deletions samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
namespace NewInEfCore7;

public static class GroupByEntityTypeSample
{
public static Task GroupBy_entity_type_SqlServer()
{
PrintSampleName();
return QueryTest<BookContextSqlServer>();
}

public static Task GroupBy_entity_type_Sqlite()
{
PrintSampleName();
return QueryTest<BookContextSqlServer>();
}

public static Task GroupBy_entity_type_InMemory()
{
PrintSampleName();
return QueryTest<BookContextInMemory>();
}

private static async Task QueryTest<TContext>()
where TContext : BookContext, new()
{
await using (var context = new TContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

var toast = new Author { Name = "Toast" };
var alice = new Author { Name = "Alice" };

await context.AddRangeAsync(
new Book { Author = alice, Price = 10 },
new Book { Author = alice, Price = 11 },
new Book { Author = toast, Price = 12 },
new Book { Author = toast, Price = 13 },
new Book { Author = toast, Price = 14 });

await context.SaveChangesAsync();
}

await using (var context = new TContext())
{
#region GroupByEntityType

var query = context.Books
.GroupBy(s => s.Author)
.Select(s => new { Author = s.Key, MaxPrice = s.Max(p => p.Price) });

#endregion

await foreach (var group in query.AsAsyncEnumerable())
{
Console.WriteLine($"Author: {group.Author.Name}; MaxPrice = {group.MaxPrice}");
}
}

await using (var context = new TContext())
{
#region GroupByEntityTypeReversed
var query = context.Authors
.Select(a => new { Author = a, MaxPrice = a.Books.Max(b => b.Price) });
#endregion

await foreach (var group in query.AsAsyncEnumerable())
{
Console.WriteLine($"Author: {group.Author.Name}; MaxPrice = {group.MaxPrice}");
}
}
}

private static void PrintSampleName([CallerMemberName] string? methodName = null)
{
Console.WriteLine($">>>> Sample: {methodName}");
Console.WriteLine();
}

public abstract class BookContext : DbContext
{
public DbSet<Book> Books => Set<Book>();
public DbSet<Author> Authors => Set<Author>();

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}

public class BookContextSqlServer : BookContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Books"));
}

public class BookContextSqlite : BookContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseSqlite("Data Source = books.db"));
}

public class BookContextInMemory : BookContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseInMemoryDatabase(nameof(BookContextInMemory)));
}

public class Author
{
public int Id { get; set; }
public string Name { get; set; } = default!;
public ICollection<Book> Books { get; } = new List<Book>();
}

public class Book
{
public int Id { get; set; }
public Author Author { get; set; } = default!;
public int Price { get; set; }
}
}
107 changes: 107 additions & 0 deletions samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
namespace NewInEfCore7;

public static class GroupByFinalOperatorSample
{
public static Task GroupBy_final_operator_SqlServer()
{
PrintSampleName();
return QueryTest<BookContextSqlServer>();
}

public static Task GroupBy_final_operator_Sqlite()
{
PrintSampleName();
return QueryTest<BookContextSqlServer>();
}

public static Task GroupBy_final_operator_InMemory()
{
PrintSampleName();
return QueryTest<BookContextInMemory>();
}

private static async Task QueryTest<TContext>()
where TContext : BookContext, new()
{
await using (var context = new TContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

var toast = new Author { Name = "Toast" };
var alice = new Author { Name = "Alice" };

await context.AddRangeAsync(
new Book { Author = alice, Price = 10 },
new Book { Author = alice, Price = 10 },
new Book { Author = toast, Price = 12 },
new Book { Author = toast, Price = 12 },
new Book { Author = toast, Price = 14 });

await context.SaveChangesAsync();
}

await using (var context = new TContext())
{
#region GroupByFinalOperator
var query = context.Books.GroupBy(s => s.Price);
#endregion

await foreach (var group in query.AsAsyncEnumerable())
{
Console.WriteLine($"Price: {group.Key}; Count = {group.Count()}");
}
}
}

private static void PrintSampleName([CallerMemberName] string? methodName = null)
{
Console.WriteLine($">>>> Sample: {methodName}");
Console.WriteLine();
}

public abstract class BookContext : DbContext
{
public DbSet<Book> Books => Set<Book>();
public DbSet<Author> Authors => Set<Author>();

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}

public class BookContextSqlServer : BookContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Books"));
}

public class BookContextSqlite : BookContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseSqlite("Data Source = books.db"));
}

public class BookContextInMemory : BookContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseInMemoryDatabase(nameof(BookContextInMemory)));
}

public class Author
{
public int Id { get; set; }
public string Name { get; set; } = default!;
}

public class Book
{
public int Id { get; set; }
public Author Author { get; set; } = default!;
public int? Price { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
namespace NewInEfCore7;

public static class GroupJoinFinalOperatorSample
{
public static Task GroupJoin_final_operator_SqlServer()
{
PrintSampleName();
return QueryTest<GroupJoinContextSqlServer>();
}

public static Task GroupJoin_final_operator_Sqlite()
{
PrintSampleName();
return QueryTest<GroupJoinContextSqlServer>();
}

public static Task GroupJoin_final_operator_InMemory()
{
PrintSampleName();
return QueryTest<GroupJoinContextInMemory>();
}

private static async Task QueryTest<TContext>()
where TContext : GroupJoinContext, new()
{
await using (var context = new TContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();

var toast = new Customer { Name = "Toast" };
var alice = new Customer { Name = "Alice" };

await context.AddRangeAsync(
new Order { Customer = alice, Amount = 10 },
new Order { Customer = alice, Amount = 10 },
new Order { Customer = toast, Amount = 12 },
new Order { Customer = toast, Amount = 12 },
new Order { Customer = toast, Amount = 14 });

await context.SaveChangesAsync();
}

await using (var context = new TContext())
{
#region GroupJoinFinalOperator
var query = context.Customers.GroupJoin(
context.Orders, c => c.Id, o => o.CustomerId, (c, os) => new { Customer = c, Orders = os });
#endregion

await foreach (var group in query.AsAsyncEnumerable())
{
Console.WriteLine($"Customer: {group.Customer.Name}; Count = {group.Orders.Count()}");
}
}

await using (var context = new TContext())
{
var query = context.Customers
.GroupJoin(
context.Orders,
o => o.Id,
bt => bt.CustomerId,
(o, bt) => new { Customer = o, BotTasks = bt, });

await foreach (var group in query.AsAsyncEnumerable())
{
Console.WriteLine($"Customer: {group.Customer.Name}; Count = {group.BotTasks.Count()}");
}
}

await using (var context = new TContext())
{
var query =
from customer in context.Customers
join order in context.Orders on customer.Id equals order.CustomerId into orderDetails
select new CustomerWithNavigationProperties { Customer = customer, Orders = orderDetails.ToList() };

await foreach (var group in query.AsAsyncEnumerable())
{
Console.WriteLine($"Customer: {group.Customer.Name}; Count = {group.Orders.Count()}");
}
}
}

private static void PrintSampleName([CallerMemberName] string? methodName = null)
{
Console.WriteLine($">>>> Sample: {methodName}");
Console.WriteLine();
}

public abstract class GroupJoinContext : DbContext
{
public DbSet<Customer> Customers => Set<Customer>();
public DbSet<Order> Orders => Set<Order>();

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}

public class GroupJoinContextSqlServer : GroupJoinContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Customers"));
}

public class GroupJoinContextSqlite : GroupJoinContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseSqlite("Data Source = customers.db"));
}

public class GroupJoinContextInMemory : GroupJoinContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> base.OnConfiguring(
optionsBuilder.UseInMemoryDatabase(nameof(GroupJoinContextInMemory)));
}

public class Customer
{
public int Id { get; set; }
public string Name { get; set; } = default!;
public List<Order> Orders { get; } = new();
}

public class Order
{
public int Id { get; set; }

public int? CustomerId { get; set; }
public Customer? Customer { get; set; }

[Precision(18, 2)]
public decimal Amount { get; set; }
}

public class CustomerWithNavigationProperties
{
public Customer Customer { get; set; } = null!;
public List<Order> Orders { get; set; } = null!;
}
}
Loading

0 comments on commit 7b62d0c

Please sign in to comment.