diff --git a/dotnet-efcore/VirtualKeywordInEFCore/Tests/Tests.csproj b/dotnet-efcore/VirtualKeywordInEFCore/Tests/Tests.csproj index f76aa1b039..836fde7b6c 100644 --- a/dotnet-efcore/VirtualKeywordInEFCore/Tests/Tests.csproj +++ b/dotnet-efcore/VirtualKeywordInEFCore/Tests/Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable @@ -10,10 +10,10 @@ - - - - + + + + diff --git a/dotnet-efcore/VirtualKeywordInEFCore/Tests/VirtualKeywordInEFCoreTests.cs b/dotnet-efcore/VirtualKeywordInEFCore/Tests/VirtualKeywordInEFCoreTests.cs index d3ceb85a0b..3f5b1ba88e 100644 --- a/dotnet-efcore/VirtualKeywordInEFCore/Tests/VirtualKeywordInEFCoreTests.cs +++ b/dotnet-efcore/VirtualKeywordInEFCore/Tests/VirtualKeywordInEFCoreTests.cs @@ -55,5 +55,40 @@ public void GivenLazyLoading_WithLazyLoadingEnabledPropertySetToFalse_WhenAuthor Assert.False(authorHollyJackson.Books.Any()); Assert.Empty(authorHollyJackson.Books); } + + [Fact] + public void GivenInjectedLazyLoader_WhenAuthorRetrievedInFreshContext_ThenBooksLazyLoadedWithoutProxy() + { + // Arrange + using (var seedContext = new DataContextInjected()) + { + DataSeeder.SeedInjected(seedContext); + } + + using var context = new DataContextInjected(); + + // Act + var author = context.AuthorsInjected.First(a => a.FullName == "Freida MCFADDEN"); + + // Assert + Assert.Equal(typeof(AuthorInjected), author.GetType()); + Assert.NotNull(author.Books); + Assert.Equal(2, author.Books.Count); + } + + [Fact] + public void GivenNoLazyLoading_WhenCollectionExplicitlyLoaded_ThenEmptyCollectionIsFilled() + { + // Arrange + using var context = new DataContextWithoutLazyLoading(); + var author = context.Authors.First(a => a.FullName == "Lucy FOLEY"); + Assert.Empty(author.Books); + + // Act + context.Entry(author).Collection(a => a.Books).Load(); + + // Assert + Assert.Equal(4, author.Books.Count); + } } } \ No newline at end of file diff --git a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/AuthorInjected.cs b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/AuthorInjected.cs new file mode 100644 index 0000000000..027978a624 --- /dev/null +++ b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/AuthorInjected.cs @@ -0,0 +1,24 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; + +namespace VirtualKeywordInEFCore.Models +{ + public class AuthorInjected + { + private ICollection? _books; + + public AuthorInjected() { } + + private AuthorInjected(ILazyLoader lazyLoader) => LazyLoader = lazyLoader; + + private ILazyLoader? LazyLoader { get; set; } + + public int AuthorInjectedId { get; set; } + public string? FullName { get; set; } + + public ICollection? Books + { + get => LazyLoader.Load(this, ref _books); + set => _books = value; + } + } +} diff --git a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/Book.cs b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/Book.cs index 7a1a4fa39d..9d98d08dd5 100644 --- a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/Book.cs +++ b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/Book.cs @@ -8,6 +8,6 @@ public class Book public int BookId { get; set; } public string? Title { get; set; } public int AuthorId { get; set; } - public Author Author { get; set; } + public Author Author { get; set; } = null!; } } diff --git a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/BookInjected.cs b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/BookInjected.cs new file mode 100644 index 0000000000..e0a057cb1d --- /dev/null +++ b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/BookInjected.cs @@ -0,0 +1,9 @@ +namespace VirtualKeywordInEFCore.Models +{ + public class BookInjected + { + public int BookInjectedId { get; set; } + public string? Title { get; set; } + public int AuthorInjectedId { get; set; } + } +} diff --git a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/BookLazy.cs b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/BookLazy.cs index 2f7b3d2734..386e754202 100644 --- a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/BookLazy.cs +++ b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/BookLazy.cs @@ -8,6 +8,6 @@ public class BookLazy public int BookId { get; set; } public string? Title { get; set; } public int AuthorId { get; set; } - public virtual AuthorLazy Author { get; set; } + public virtual AuthorLazy Author { get; set; } = null!; } } diff --git a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/DataContextInjected.cs b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/DataContextInjected.cs new file mode 100644 index 0000000000..f7a3829bfa --- /dev/null +++ b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/DataContextInjected.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; + +namespace VirtualKeywordInEFCore.Models +{ + public class DataContextInjected : DbContext + { + protected override void OnConfiguring(DbContextOptionsBuilder options) + { + options.UseSqlite("DataSource=LibraryInjected.db"); + + base.OnConfiguring(options); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .HasMany(a => a.Books) + .WithOne() + .HasForeignKey(b => b.AuthorInjectedId); + } + + public DbSet AuthorsInjected { get; set; } + public DbSet BooksInjected { get; set; } + } +} diff --git a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/DataSeeder.cs b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/DataSeeder.cs index 0c082c143b..1e382869a3 100644 --- a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/DataSeeder.cs +++ b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Models/DataSeeder.cs @@ -64,5 +64,27 @@ public static void SeedLazy(DataContextLazyLoading contextLazy) contextLazy.AddRange(booksLazy); contextLazy.SaveChanges(); } + + public static void SeedInjected(DataContextInjected contextInjected) + { + contextInjected.Database.EnsureCreated(); + if (contextInjected.AuthorsInjected.Any()) + { + return; + } + + var authorInjected = new AuthorInjected + { + FullName = "Freida MCFADDEN", + Books = new List + { + new () { Title = "The Housemaid" }, + new () { Title = "The Coworker" } + } + }; + + contextInjected.Add(authorInjected); + contextInjected.SaveChanges(); + } } } diff --git a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Program.cs b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Program.cs index 6eff34f975..dc49d46e64 100644 --- a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Program.cs +++ b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/Program.cs @@ -10,6 +10,9 @@ static void Main() LoadData(); LoadDataWithLazyLoading(); + + LoadDataWithInjectedLazyLoader(); + LoadDataWithExplicitLoading(); } public static void LoadData() @@ -21,15 +24,12 @@ public static void LoadData() Author author; author = contextWithoutLazyLoading.Authors.AsNoTracking().First(a => a.FullName == "Lucy FOLEY"); - if (author is not null) - { - Console.WriteLine($"Author Name: {author.FullName}"); - Console.WriteLine($"{author.FullName}'s Books number: {author.Books.Count}"); + Console.WriteLine($"Author Name: {author.FullName}"); + Console.WriteLine($"{author.FullName}'s Books number: {author.Books.Count}"); - foreach (var book in author.Books) - { - Console.WriteLine($"Book Title: {book.Title}"); - } + foreach (var book in author.Books) + { + Console.WriteLine($"Book Title: {book.Title}"); } } @@ -55,5 +55,38 @@ public static void LoadDataWithLazyLoading() } } } + + public static void LoadDataWithInjectedLazyLoader() + { + Console.WriteLine("\nLazy Loading with an injected ILazyLoader:"); + + using (var seedContext = new DataContextInjected()) + { + DataSeeder.SeedInjected(seedContext); + } + + using var context = new DataContextInjected(); + var author = context.AuthorsInjected.First(a => a.FullName == "Freida MCFADDEN"); + + Console.WriteLine($"{nameof(AuthorInjected)} datatype: {author.GetType()}"); + Console.WriteLine($"{author.FullName}'s Books number: {author.Books?.Count}"); + } + + public static void LoadDataWithExplicitLoading() + { + Console.WriteLine("\nExplicit Loading:"); + + using (var seedContext = new DataContextWithoutLazyLoading()) + { + DataSeeder.SeedWithoutLazy(seedContext); + } + + using var context = new DataContextWithoutLazyLoading(); + var author = context.Authors.First(a => a.FullName == "Lucy FOLEY"); + + context.Entry(author).Collection(a => a.Books).Load(); + + Console.WriteLine($"{author.FullName}'s Books number after Load(): {author.Books.Count}"); + } } } diff --git a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/VirtualKeywordInEFCore.csproj b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/VirtualKeywordInEFCore.csproj index 3a3baa353b..2e8acdf706 100644 --- a/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/VirtualKeywordInEFCore.csproj +++ b/dotnet-efcore/VirtualKeywordInEFCore/VirtualKeywordInEFCore/VirtualKeywordInEFCore.csproj @@ -2,15 +2,16 @@ Exe - net8.0 + net10.0 enable enable - - - + + + +