-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c02dcae
commit 76236fc
Showing
12 changed files
with
1,583 additions
and
1 deletion.
There are no files selected for viewing
448 changes: 447 additions & 1 deletion
448
entity-framework/core/what-is-new/ef-core-7.0/whatsnew.md
Large diffs are not rendered by default.
Oops, something went wrong.
125 changes: 125 additions & 0 deletions
125
samples/core/Miscellaneous/NewInEFCore7/GroupByEntityTypeSample.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
107
samples/core/Miscellaneous/NewInEFCore7/GroupByFinalOperatorSample.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } | ||
} | ||
} |
147 changes: 147 additions & 0 deletions
147
samples/core/Miscellaneous/NewInEFCore7/GroupJoinFinalOperatorSample.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!; | ||
} | ||
} |
Oops, something went wrong.