Skip to content

Instantly share code, notes, and snippets.

@mortezadalil
Created August 13, 2023 21:21
Show Gist options
  • Save mortezadalil/e8d4a0f513c8a6bdc880a703a793eee9 to your computer and use it in GitHub Desktop.
Save mortezadalil/e8d4a0f513c8a6bdc880a703a793eee9 to your computer and use it in GitHub Desktop.
// Defining a Shadow Property
public class ApplicationDbContext : DbContext
{
public DbSet<Book> Books { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Book>().Property<DateTime>("ModifiedDate");
}
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
}
// Using Shadow Properties in a Query
using (var context = new ApplicationDbContext())
{
var books = context.Books
.OrderByDescending(b => EF.Property<DateTime>(b, "ModifiedDate"))
.ToList();
}
//=======================================================
// Implementing TPH Inheritance
public abstract class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FullTimeEmployee : Employee
{
public decimal Salary { get; set; }
}
public class PartTimeEmployee : Employee
{
public decimal HourlyRate { get; set; }
}
// Configure DbContext
public class ApplicationDbContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<FullTimeEmployee>();
modelBuilder.Entity<PartTimeEmployee>();
}
}
// Querying TPH Inheritance
using (var context = new ApplicationDbContext())
{
// Returns a list of Employee objects (FullTimeEmployee and PartTimeEmployee instances)
var employees = context.Employees.ToList();
}
using (var context = new ApplicationDbContext())
{
var fullTimeEmployees = context.Employees.OfType<FullTimeEmployee>().ToList();
var partTimeEmployees = context.Employees.OfType<PartTimeEmployee>().ToList();
}
//=======================================================
// Eager Loading with Projections
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
public class BlogWithPostTitles
{
public string BlogTitle { get; set; }
public List<string> PostTitles { get; set; }
}
using (var context = new ApplicationDbContext())
{
var blogsWithPostTitles = context.Blogs
.Select(b => new BlogWithPostTitles
{
BlogTitle = b.Title,
PostTitles = b.Posts.Select(p => p.Title).ToList()
})
.ToList();
}
//=======================================================
// Batch Operations
// Install-Package EFCore.BulkExtensions
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Instead of inserting each Product individually, you can use the BulkInsert method to perform a batch operation:
using (var context = new ApplicationDbContext())
{
// Assume this method returns a list of products
List<Product> products = GetProducts();
context.BulkInsert(products);
}
//=======================================================
// Lazy Loading
// Install-Package Microsoft.EntityFrameworkCore.Proxies
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer("your_connection_string");
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public virtual Author Author { get; set; }
}
//=======================================================
// Powerful Custom Conventions
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
// Set table names to uppercase
entityType.SetTableName(entityType.GetTableName().ToUpper());
// Set column names to lowercase
foreach (var property in entityType.GetProperties())
{
property.SetColumnName(property.GetColumnName().ToLower());
}
}
}
//=======================================================
// Event Listeners for Tracing and Logging
public class SqlQueryLoggingListener : IDiagnosticsLogger<DbLoggerCategory.Query>
{
public bool IsEnabled(LogLevel logLevel) => logLevel == LogLevel.Information;
public void Log<TState>(LogLevel logLevel, DbLoggerCategory.Query eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (IsEnabled(logLevel))
{
Console.WriteLine(formatter(state, exception));
}
}
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(connectionString)
.AddInterceptors(new SqlQueryLoggingListener());
}
//=======================================================
// Optimizing Data Seeding
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
table: "MyTable",
columns: new[] { "Id", "Name" },
values: new object[] { 1, "My First Seed Data" });
}
//Using Bulk Inserts for Large Data Sets
using EFCore.BulkExtensions;
using MyProject.Data;
using (var context = new MyDbContext())
{
var data = new List<MyEntity>
{
new MyEntity { Id = 1, Name = "Data 1" },
// ...
new MyEntity { Id = 1000, Name = "Data 1000" }
};
context.BulkInsert(data);
}
//Applying Conditional Seeding
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#if DEBUG
modelBuilder.Entity<MyEntity>().HasData(
new MyEntity { Id = 1, Name = "Seed Data for Debug" });
#endif
}
//=======================================================
//Efficiently Mapping Complex Types
//Using Owned Entity Types
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
}
public class MyDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>().OwnsOne(c => c.Address);
}
}
//Using Value Converters
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Tags { get; set; }
}
public class MyDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.Property(p => p.Tags)
.HasConversion(
v => JsonConvert.SerializeObject(v),
v => JsonConvert.DeserializeObject<List<string>>(v));
}
}
//Using Custom Mappings
public class Order
{
public int Id { get; set; }
public string CustomerName { get; set; }
public decimal Total { get; set; }
public Money Currency { get; set; }
}
public class Money
{
public decimal Amount { get; set; }
public string CurrencyCode { get; set; }
}
public class MyDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.Property(o => o.Currency.Amount)
.HasColumnName("TotalAmount");
modelBuilder.Entity<Order>()
.Property(o => o.Currency.CurrencyCode)
.HasColumnName("CurrencyCode");
}
}
//=======================================================
//Custom Entity Materialization
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
// Custom constructor for materialization
public Product(int id, string name, decimal price)
{
Id = id;
Name = name;
Price = ApplyDiscount(price);
}
private decimal ApplyDiscount(decimal price)
{
// Apply a custom discount based on the price
return price * 0.9m;
}
}
using (var context = new MyDbContext())
{
var products = context.Products
.FromSqlRaw("SELECT Id, Name, Price FROM Products")
.ToList();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment