EF Core technical coding interview questions

EF Core technical coding interview questions


1. How do you configure a one-to-many relationship in EF Core?

Question:

How would you configure a one-to-many relationship between Author and Book in EF Core, where one author can have many books, but a book can only have one author?

Answer:

In EF Core, a one-to-many relationship can be configured using the HasMany and WithOne methods in the OnModelCreating method.

public class Author
{
    public int AuthorId { get; set; }
    public string Name { get; set; }
    public ICollection<Book> Books { get; set; }
}

public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }
    public int AuthorId { get; set; }
    public Author Author { get; set; }
}

public class AppDbContext : DbContext
{
    public DbSet<Author> Authors { get; set; }
    public DbSet<Book> Books { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Author>()
            .HasMany(a => a.Books)
            .WithOne(b => b.Author)
            .HasForeignKey(b => b.AuthorId);
    }
}

2. How do you implement lazy loading in EF Core?

Question:

You need to implement lazy loading in EF Core for a scenario where each Customer has many Orders. How would you set this up?

Answer:

EF Core supports lazy loading using proxy objects. To enable lazy loading, you need to install the Microsoft.EntityFrameworkCore.Proxies package and enable it in OnConfiguring.

  1. Install the necessary package:

    dotnet add package Microsoft.EntityFrameworkCore.Proxies
    
  2. Enable lazy loading in the DbContext:

    public class AppDbContext : DbContext
    {
        public DbSet<Customer> Customers { get; set; }
        public DbSet<Order> Orders { get; set; }
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder
                .UseSqlServer("YourConnectionString")
                .UseLazyLoadingProxies(); // Enables lazy loading
        }
    }
    
  3. Ensure navigation properties are virtual:

    public class Customer
    {
        public int CustomerId { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Order> Orders { get; set; } // Navigation property must be virtual
    }
    
    public class Order
    {
        public int OrderId { get; set; }
        public string OrderDetails { get; set; }
        public int CustomerId { get; set; }
        public virtual Customer Customer { get; set; } // Navigation property must be virtual
    }
    

With this configuration, EF Core will automatically load the Orders collection when you access customer.Orders for the first time.


3. How would you write a custom query using raw SQL in EF Core?

Question:

Write a custom query using raw SQL to fetch all customers who have placed orders worth more than $500.

Answer:

You can use FromSqlRaw or ExecuteSqlRaw to execute raw SQL queries in EF Core.

var customers = dbContext.Customers
    .FromSqlRaw("SELECT * FROM Customers c WHERE EXISTS (SELECT 1 FROM Orders o WHERE o.CustomerId = c.CustomerId AND o.TotalAmount > 500)")
    .ToList();

Here, we use a SQL subquery to find customers who have placed orders with a total amount greater than $500.


4. How do you handle concurrency in EF Core using a RowVersion?

Question:

You have a Product entity with a Price property. You want to ensure that changes to the Price are made in a way that prevents concurrency issues (e.g., two users editing the same Price at the same time). How would you implement this in EF Core?

Answer:

You can implement optimistic concurrency control by adding a RowVersion property to the entity, which is a byte array that EF Core automatically updates whenever the row is modified.

  1. Add the RowVersion property to the Product entity:

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public byte[] RowVersion { get; set; } // Concurrency token
    }
    
  2. Configure the RowVersion property in OnModelCreating:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .Property(p => p.RowVersion)
            .IsRowVersion(); // Mark as concurrency token
    }
    
  3. Handle concurrency exception when saving changes:

    try
    {
        dbContext.SaveChanges();
    }
    catch (DbUpdateConcurrencyException)
    {
        // Handle concurrency exception (e.g., prompt user to refresh or merge changes)
    }
    

When SaveChanges is called, EF Core checks the value of RowVersion. If the row has been modified since it was retrieved, EF Core throws a DbUpdateConcurrencyException.


5. How do you configure a many-to-many relationship in EF Core?

Question:

You have two entities, Student and Course. A student can enroll in multiple courses, and a course can have multiple students. How would you configure this many-to-many relationship in EF Core?

Answer:

Starting with EF Core 5, many-to-many relationships are handled without needing to explicitly define a join entity. However, you can still configure it using HasMany and WithMany.

  1. Define the Student and Course entities:

    public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }
        public ICollection<Course> Courses { get; set; }
    }
    
    public class Course
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
        public ICollection<Student> Students { get; set; }
    }
    
  2. Configure the many-to-many relationship in OnModelCreating:

    public class AppDbContext : DbContext
    {
        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>()
                .HasMany(s => s.Courses)
                .WithMany(c => c.Students)
                .UsingEntity<StudentCourse>(); // Configure the join table (optional, for explicit control)
        }
    }
    
    public class StudentCourse
    {
        public int StudentId { get; set; }
        public int CourseId { get; set; }
        public Student Student { get; set; }
        public Course Course { get; set; }
    }
    

In EF Core 5+, the UsingEntity method simplifies the process by automatically creating a join table.


6. How do you handle batch updates in EF Core?

Question:

You need to update the Status of all orders placed more than 30 days ago to "Expired". How would you achieve this using EF Core?

Answer:

EF Core does not support batch updates natively, but you can use raw SQL to perform a batch update or use third-party libraries such as EFCore.BulkExtensions to handle bulk operations efficiently.

  1. Using raw SQL:

    var sql = "UPDATE Orders SET Status = 'Expired' WHERE OrderDate < @p0";
    dbContext.Database.ExecuteSqlRaw(sql, DateTime.UtcNow.AddDays(-30));
    
  2. Using a third-party library (e.g., EFCore.BulkExtensions):

    dbContext.Orders
        .Where(o => o.OrderDate < DateTime.UtcNow.AddDays(-30))
        .BatchUpdate(o => new Order { Status = "Expired" });
    

7. How do you create and apply a migration in EF Core?

Question:

You have made changes to your model (added a new PhoneNumber property to the Customer entity). How would you create and apply the migration?

Answer:

  1. Create the migration using the EF Core CLI:

    dotnet ef migrations add AddPhoneNumberToCustomer
    
  2. Apply the migration to the database:

    dotnet ef database update
    

EF Core will generate migration files in the Migrations folder and apply the changes to the database.


8. How do you optimize the performance of EF Core queries with large datasets?

Question:

You are querying a large dataset (e.g., 100,000 records). How would you optimize the performance of this query in EF Core?

Answer:

  1. Use AsNoTracking() for read-only queries to disable change tracking, which improves performance:

    var products = dbContext.Products.AsNoTracking().ToList();
    
  2. Paginate results to load data in smaller chunks:

    var pageSize = 100;
    var pageNumber = 1;
    var products = dbContext.Products
       
    

.Skip((pageNumber - 1) * pageSize) .Take(pageSize) .ToList();


3. **Use `Select` for projections** to load only the required fields instead of entire entities:
```csharp
var productNames = dbContext.Products
    .Where(p => p.Price > 50)
    .Select(p => p.Name)
    .ToList();
  1. Ensure indexes on frequently queried fields (e.g., ProductName).



9. How do you perform a left join in EF Core using LINQ?

Question:

You have two entities: Author and Book. An author may have multiple books, but some authors may have no books. Write a query using LINQ to get all authors and their books, including those without books (left join).

Answer:

You can perform a left join in LINQ using DefaultIfEmpty() to include authors without books.

var query = from author in dbContext.Authors
            join book in dbContext.Books
            on author.AuthorId equals book.AuthorId into booksGroup
            from book in booksGroup.DefaultIfEmpty() // Left join
            select new
            {
                AuthorName = author.Name,
                BookTitle = book != null ? book.Title : "No books"
            };

var result = query.ToList();

In this query, DefaultIfEmpty() ensures that authors without books are included in the result.


10. How do you implement a stored procedure call in EF Core?

Question:

You want to execute a stored procedure named GetOrdersByCustomer that takes a customerId parameter and returns a list of orders. How would you implement this in EF Core?

Answer:

EF Core allows you to execute raw SQL queries, including stored procedures, using FromSqlRaw or ExecuteSqlRaw for non-query procedures.

  1. For a stored procedure that returns data:

    var customerId = 1;
    var orders = dbContext.Orders
        .FromSqlRaw("EXECUTE GetOrdersByCustomer @customerId", 
                     new SqlParameter("@customerId", customerId))
        .ToList();
    
  2. For a stored procedure that doesn't return data (non-query):

    var customerId = 1;
    dbContext.Database.ExecuteSqlRaw("EXECUTE DeleteOrdersByCustomer @customerId", 
                                      new SqlParameter("@customerId", customerId));
    

Ensure that your stored procedure is correctly defined in the database, and parameters are passed as SqlParameter to avoid SQL injection.


11. How do you handle soft deletes in EF Core?

Question:

You need to implement soft deletes in EF Core where the IsDeleted flag is set to true instead of actually deleting a record. How would you implement this in EF Core?

Answer:

To handle soft deletes in EF Core, you can use a flag like IsDeleted on your entity and override the SaveChanges method to filter out soft-deleted records in queries.

  1. Add an IsDeleted property:

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public bool IsDeleted { get; set; } // Soft delete flag
    }
    
  2. Override SaveChanges to set the flag instead of deleting:

    public class AppDbContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
    
        public override int SaveChanges()
        {
            foreach (var entry in ChangeTracker.Entries().Where(e => e.Entity is Product && e.State == EntityState.Deleted))
            {
                entry.State = EntityState.Modified;
                ((Product)entry.Entity).IsDeleted = true;
            }
    
            return base.SaveChanges();
        }
    }
    
  3. Filter soft-deleted records in queries:

    var products = dbContext.Products
        .Where(p => !p.IsDeleted)
        .ToList();
    

This approach ensures that when you delete a record, it is only marked as deleted, and future queries will filter out these records.


12. How do you configure cascading updates in EF Core?

Question:

You have a Customer entity with a related Address entity. If the Customer name changes, you want the Address entity's CustomerName property to update automatically. How would you configure cascading updates in EF Core?

Answer:

EF Core supports cascading updates by configuring relationships in the OnModelCreating method using the OnDelete method for cascading behavior. For cascading updates, you can manually update related entities or use custom logic.

  1. Define entities:

    public class Customer
    {
        public int CustomerId { get; set; }
        public string Name { get; set; }
        public Address Address { get; set; }
    }
    
    public class Address
    {
        public int AddressId { get; set; }
        public string CustomerName { get; set; }
        public int CustomerId { get; set; }
    }
    
  2. Set up cascading behavior (automatic propagation):

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>()
            .HasOne(c => c.Address)
            .WithOne(a => a.Customer)
            .HasForeignKey<Address>(a => a.CustomerId)
            .OnDelete(DeleteBehavior.Cascade); // Cascade delete
    
        modelBuilder.Entity<Customer>()
            .Property(c => c.Name)
            .IsRequired();
    }
    
  3. Handle cascading updates manually: EF Core doesn’t support cascading updates automatically, so you'll need to update the related Address entity manually before saving changes:

    var customer = dbContext.Customers.Include(c => c.Address).FirstOrDefault(c => c.CustomerId == customerId);
    customer.Name = "Updated Name";
    customer.Address.CustomerName = "Updated Name";
    dbContext.SaveChanges();
    

13. How do you implement pagination in EF Core?

Question:

You have a list of Products and need to implement pagination to fetch only a specific page of results. How would you do this in EF Core?

Answer:

Pagination can be implemented by using Skip and Take in LINQ, which allows you to skip a specific number of records and take a defined number.

int pageNumber = 1;
int pageSize = 10;

var products = dbContext.Products
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize)
    .ToList();

This will fetch the records for the given page, where pageNumber is the current page, and pageSize is the number of records per page. Adjust Skip to calculate the correct number of records to skip.


14. How do you handle multi-tenant data in EF Core?

Question:

You are working with a multi-tenant application where data for each tenant should be isolated. How would you implement multi-tenancy in EF Core?

Answer:

There are multiple approaches to handle multi-tenancy in EF Core:

  1. Single database, separate schema per tenant: Each tenant gets its own schema in the same database. You can configure this dynamically in the OnModelCreating method based on the tenant.

    public class AppDbContext : DbContext
    {
        private readonly string _tenantSchema;
    
        public AppDbContext(DbContextOptions<AppDbContext> options, string tenantSchema) : base(options)
        {
            _tenantSchema = tenantSchema;
        }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema(_tenantSchema); // Set the schema dynamically
        }
    }
    
  2. Single schema with a tenant identifier: Add a TenantId field to your entities and filter queries by TenantId for multi-tenancy isolation.

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public int TenantId { get; set; } // Tenant identifier
    }
    
    var tenantId = 1;
    var products = dbContext.Products
        .Where(p => p.TenantId == tenantId)
        .ToList();
    
  3. Use separate DbContext for each tenant: You could also instantiate a different DbContext for each tenant if you want to isolate databases for each tenant, but this comes with more overhead.


15. How would you perform a batch insert in EF Core?

Question:

You want to insert multiple Order entities into the database in a single operation. How would you perform this batch insert efficiently in EF Core?

Answer:

EF Core does not support batch inserts natively, but you can insert multiple entities at once using AddRange and SaveChanges.

var orders = new List<Order>
{
    new Order { OrderDate = DateTime.Now, TotalAmount = 100 },
    new Order { OrderDate = DateTime.Now, TotalAmount = 150 },
    new Order { OrderDate = DateTime.Now, TotalAmount = 200 }
};

dbContext.Orders.AddRange(orders);
dbContext.SaveChanges();

This inserts all orders in one transaction, which is more efficient than inserting them one by one.

For large datasets, you can use a third-party library such as EFCore.BulkExtensions to perform bulk inserts, which can be much faster than standard AddRange.



Certainly! Below are more EF Core technical coding interview questions with solutions, focusing on advanced use cases and concepts that experienced developers should be familiar with.


16. How do you perform conditional loading in EF Core?

Question:

You have a Customer entity with a SalesOrders collection. You want to load the SalesOrders only if a specific condition (e.g., OrderDate > DateTime.Now) is met. How would you implement conditional loading in EF Core?

Answer:

Conditional loading can be achieved using Where() in combination with Include() to filter the related entities. EF Core allows you to apply conditions before loading related data.

var customerId = 1;
var orders = dbContext.Customers
    .Where(c => c.CustomerId == customerId)
    .Include(c => c.SalesOrders.Where(o => o.OrderDate > DateTime.Now))
    .FirstOrDefault();

var salesOrders = orders?.SalesOrders.ToList();

In this case, the SalesOrders are filtered based on the condition (OrderDate > DateTime.Now) during loading. Note that this does not fetch unrelated SalesOrders when the condition isn't met.


17. How do you apply indexes in EF Core?

Question:

You have a User entity with properties Username and Email. You want to improve query performance by indexing these properties. How would you define indexes for these properties in EF Core?

Answer:

Indexes can be applied in EF Core using the HasIndex method inside the OnModelCreating method.

public class User
{
    public int UserId { get; set; }
    public string Username { get; set; }
    public string Email { get; set; }
}

public class AppDbContext : DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>()
            .HasIndex(u => u.Username)
            .HasDatabaseName("Idx_Username");

        modelBuilder.Entity<User>()
            .HasIndex(u => u.Email)
            .HasDatabaseName("Idx_Email");
    }
}

Here, indexes are added to the Username and Email columns, which will improve query performance for these properties. EF Core will generate the appropriate SQL commands during migration to create these indexes.


18. How do you handle a scenario where you need to query a many-to-many relationship but also filter on a property in the join table?

Question:

You have a Student entity and a Course entity, with a join table StudentCourse. The StudentCourse table also has an EnrollmentDate property. How would you retrieve all students enrolled in courses after a specific date?

Answer:

To query many-to-many relationships with properties in the join table, you can use Join() in LINQ, or you can navigate through the join table explicitly.

var date = DateTime.Now.AddMonths(-1); // Filter for students enrolled in the last month

var students = dbContext.Students
    .Join(dbContext.StudentCourses,
          student => student.StudentId,
          studentCourse => studentCourse.StudentId,
          (student, studentCourse) => new { student, studentCourse })
    .Where(sc => sc.studentCourse.EnrollmentDate > date)
    .Select(sc => sc.student)
    .ToList();

In this query, we explicitly join Students and StudentCourses using LINQ. The EnrollmentDate property from the join table is used to filter the results.


19. How do you handle data seeding in EF Core?

Question:

You need to seed initial data (like default Roles and Users) when the database is created or migrated. How would you implement data seeding in EF Core?

Answer:

EF Core provides an easy way to seed data through the HasData method in the OnModelCreating method.

  1. Seeding data for Roles and Users:

    public class AppDbContext : DbContext
    {
        public DbSet<Role> Roles { get; set; }
        public DbSet<User> Users { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Role>().HasData(
                new Role { RoleId = 1, Name = "Admin" },
                new Role { RoleId = 2, Name = "User" }
            );
    
            modelBuilder.Entity<User>().HasData(
                new User { UserId = 1, Username = "admin", RoleId = 1 },
                new User { UserId = 2, Username = "user", RoleId = 2 }
            );
        }
    }
    
  2. Running the migration: After adding the seed data, you can apply the migration:

    dotnet ef migrations add SeedInitialData
    dotnet ef database update
    

EF Core will automatically insert the seed data during the database creation or migration process.


20. How do you handle changes to the model (e.g., adding a new property) after seeding data?

Question:

You have seeded some initial data, but you need to update the model by adding a new property (IsActive) to an existing User entity. How would you handle this change in EF Core after seeding data?

Answer:

If you modify your model, EF Core will require a migration to apply the schema changes. To handle the seeding with the new model property:

  1. Add the IsActive property to the User entity:

    public class User
    {
        public int UserId { get; set; }
        public string Username { get; set; }
        public int RoleId { get; set; }
        public bool IsActive { get; set; } // New property
    }
    
  2. Update the seeding logic to include the IsActive property:

    modelBuilder.Entity<User>().HasData(
        new User { UserId = 1, Username = "admin", RoleId = 1, IsActive = true },
        new User { UserId = 2, Username = "user", RoleId = 2, IsActive = true }
    );
    
  3. Create and apply a migration:

    dotnet ef migrations add AddIsActiveToUser
    dotnet ef database update
    

EF Core will apply the schema change to the database, including the new IsActive property and the updated seed data.


21. How do you configure a unique constraint on a property or a set of properties in EF Core?

Question:

You need to ensure that the combination of Username and Email in the User entity is unique. How would you configure this in EF Core?

Answer:

EF Core supports defining unique constraints using HasIndex in the OnModelCreating method. You can specify a unique constraint on a single column or a combination of columns.

  1. Configure a unique constraint on Username and Email:
    public class User
    {
        public int UserId { get; set; }
        public string Username { get; set; }
        public string Email { get; set; }
    }
    
    public class AppDbContext : DbContext
    {
        public DbSet<User> Users { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>()
                .HasIndex(u => new { u.Username, u.Email })
                .IsUnique();
        }
    }
    

This will ensure that the combination of Username and Email is unique in the database.


22. How do you manage schema migrations when working with multiple environments (e.g., development, staging, production)?

Question:

You have different environments (development, staging, production), and you need to manage database migrations across these environments. How would you handle this scenario in EF Core?

Answer:

To manage migrations across different environments, you can use separate connection strings for each environment and control when migrations are applied by using the dotnet ef CLI or programmatically.

  1. Use environment-specific connection strings: Store connection strings in appsettings.Development.json, appsettings.Staging.json, and appsettings.Production.json.

    // appsettings.Development.json
    {
      "ConnectionStrings": {
        "DefaultConnection": "Server=localhost;Database=DevDb;Trusted_Connection=True;"
      }
    }
    
  2. Apply migrations to specific environments: You can specify the connection string when running the migration commands for different environments:

    dotnet ef migrations add InitialMigration --environment Development
    dotnet ef database update --environment Production
    
  3. Programmatically applying migrations: In production, you might want to apply migrations programmatically when the application starts (after validating that migrations are needed).

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            
            using (var scope = host.Services.CreateScope())
            {
                var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
                dbContext.Database.Migrate(); // Automatically apply migrations
            }
    
            host.Run();
        }
    }
    

23. How would you configure a custom database function in EF Core?

Question:

You need to use a custom SQL function `GetFull

Name` in EF Core, which concatenates a user's first and last names. How would you configure and use this custom function?

Answer:

EF Core allows you to map custom database functions to LINQ queries using HasDbFunction.

  1. Define the custom function in the OnModelCreating method:

    public class AppDbContext : DbContext
    {
        public DbSet<User> Users { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasDbFunction(() => GetFullName(default, default));
        }
    
        public static string GetFullName(string firstName, string lastName)
        {
            throw new NotImplementedException("This function will be translated to SQL.");
        }
    }
    
  2. Use the custom function in a query:

    var fullName = dbContext.Users
        .Where(u => EF.Functions.GetFullName(u.FirstName, u.LastName) == "John Doe")
        .ToList();
    

EF Core will translate GetFullName into the corresponding SQL function when executing the query.



Certainly! Below are even more EF Core technical coding interview questions with answers, targeting more advanced scenarios and real-world use cases. These are geared toward experienced developers who need to demonstrate deep knowledge of EF Core.


24. How do you handle database transactions in EF Core?

Question:

You want to ensure that two operations—updating a Product and inserting an Order—either both succeed or both fail. How would you handle this in EF Core using transactions?

Answer:

EF Core supports transactions natively through IDbContextTransaction. You can use BeginTransaction() to explicitly control transactions.

using var transaction = dbContext.Database.BeginTransaction();

try
{
    // Operation 1: Update Product
    var product = dbContext.Products.FirstOrDefault(p => p.ProductId == 1);
    product.Stock -= 10;
    dbContext.SaveChanges();

    // Operation 2: Insert Order
    var order = new Order { ProductId = 1, Quantity = 10 };
    dbContext.Orders.Add(order);
    dbContext.SaveChanges();

    // Commit transaction if both operations succeed
    transaction.Commit();
}
catch (Exception)
{
    // Rollback transaction if any operation fails
    transaction.Rollback();
    throw;
}

In this example, if any operation fails, the transaction is rolled back to ensure data consistency.


25. How do you prevent or resolve circular references in EF Core during serialization?

Question:

You have two entities, Author and Book, with a circular reference (i.e., Author has a collection of Books and Book has an Author property). How do you prevent infinite loops during serialization (e.g., when returning these entities as JSON)?

Answer:

Circular references can be prevented during serialization by using the JsonIgnore attribute or the ReferenceHandler property in System.Text.Json configuration.

  1. Use JsonIgnore attribute: Apply the JsonIgnore attribute on the navigation property that causes the circular reference:

    public class Author
    {
        public int AuthorId { get; set; }
        public string Name { get; set; }
        public ICollection<Book> Books { get; set; }
    }
    
    public class Book
    {
        public int BookId { get; set; }
        public string Title { get; set; }
        [JsonIgnore] // Prevent circular reference
        public Author Author { get; set; }
    }
    
  2. Using ReferenceHandler in the Program.cs file (for .NET 6 and beyond):

    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            builder.Services.AddControllers()
                .AddJsonOptions(options =>
                {
                    options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
                });
    
            var app = builder.Build();
            app.MapControllers();
            app.Run();
        }
    }
    

This will prevent infinite recursion during serialization by ignoring circular references.


26. How would you implement optimistic concurrency control in EF Core?

Question:

You have a Product entity with a Version property that is an integer. You want to implement optimistic concurrency control to ensure that a Product is not updated by multiple users simultaneously. How would you implement this in EF Core?

Answer:

Optimistic concurrency control can be implemented using a row version (e.g., a Timestamp or Version property) in EF Core. This property is marked as a concurrency token, and EF Core will automatically check if the value has changed during an update operation.

  1. Define the Version property in your entity:

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        
        [Timestamp] // Mark as concurrency token
        public byte[] Version { get; set; } // Row version
    }
    
  2. Configure the Version property in OnModelCreating (optional, EF Core can also detect it automatically):

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .Property(p => p.Version)
            .IsRowVersion();
    }
    
  3. Handle concurrency exceptions: If another user has updated the product in the meantime, EF Core will throw a DbUpdateConcurrencyException. You can catch and handle it as follows:

    try
    {
        dbContext.SaveChanges();
    }
    catch (DbUpdateConcurrencyException ex)
    {
        var entry = ex.Entries.Single();
        var clientValue = (byte[])entry.Property("Version").CurrentValue;
        var databaseValue = (byte[])entry.Property("Version").OriginalValue;
    
        // Handle concurrency conflict, e.g., reload the entity or notify the user
    }
    

In this example, if another user updates the Product in between, the DbUpdateConcurrencyException is triggered, and you can handle it accordingly (e.g., reload the entity or prompt the user for resolution).


27. How do you deal with loading large datasets in EF Core efficiently?

Question:

You are querying a large dataset (e.g., thousands of Products). How can you improve performance when loading this data into memory using EF Core?

Answer:

When dealing with large datasets, several strategies can improve performance in EF Core:

  1. Use AsNoTracking(): If you do not need to track changes (e.g., for read-only operations), use AsNoTracking() to disable change tracking, improving performance.

    var products = dbContext.Products.AsNoTracking().ToList();
    
  2. Paging: For large result sets, use paging to load data in chunks instead of all at once.

    int pageNumber = 1;
    int pageSize = 100;
    
    var products = dbContext.Products
        .Skip((pageNumber - 1) * pageSize)
        .Take(pageSize)
        .ToList();
    
  3. Select Only Required Columns: Avoid loading unnecessary columns by selecting only the needed fields.

    var productNames = dbContext.Products
        .Where(p => p.Price > 100)
        .Select(p => p.Name)
        .ToList();
    
  4. Asynchronous Queries: Use async methods to avoid blocking the thread, especially when dealing with large amounts of data.

    var products = await dbContext.Products.ToListAsync();
    
  5. Batch Queries: If you need to process a large dataset, consider fetching the data in smaller batches and processing them one at a time.


28. How do you handle soft deletes and filtering in EF Core?

Question:

You have a Product entity with an IsDeleted flag to indicate soft deletes. You want to filter out the soft-deleted records globally. How do you implement this in EF Core?

Answer:

To filter out soft-deleted records globally, you can use a global query filter in EF Core.

  1. Define the IsDeleted flag in the entity:

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public bool IsDeleted { get; set; } // Soft delete flag
    }
    
  2. Configure the global query filter in OnModelCreating:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .HasQueryFilter(p => !p.IsDeleted); // Global filter for soft deletes
    }
    

Now, any query to Products will automatically exclude soft-deleted records unless explicitly overridden.

  1. Override the filter for a specific query (if needed):

    var allProductsIncludingDeleted = dbContext.Products
        .IgnoreQueryFilters() // Ignores global query filters
        .Where(p => p.IsDeleted)
        .ToList();
    

This way, soft deletes are managed efficiently without needing to manually filter out IsDeleted in each query.


29. How do you manage relationships when migrating from one-to-many to many-to-many in EF Core?

Question:

You initially designed a one-to-many relationship between Student and Course, but now you need to refactor it to a many-to-many relationship. How would you implement this change in EF Core?

Answer:

In EF Core, changing a one-to-many relationship to a many-to-many relationship requires creating a join entity for the many-to-many relationship.

  1. Initial One-to-Many Relationship:

    public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }
        public int CourseId { get; set; } // Foreign key
        public Course Course { get; set; }
    }
    
    public class Course
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
        public ICollection<Student> Students { get; set; }
    }
    
  2. Refactor to Many-to-Many Relationship: EF Core 5.0+ supports direct many-to-many relationships without needing an explicit join entity. You just define a DbSet and EF Core automatically manages the join table.

    public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }
        public ICollection<Course> Courses { get; set; }
    }
    
    public class Course
    {
        public int CourseId { get; set; }
        public string CourseName {
    

get; set; } public ICollection Students { get; set; } }


3. **Migration Changes**:
After refactoring your model, run a migration to update the schema.

```bash
dotnet ef migrations add RefactorToManyToMany
dotnet ef database update

EF Core will create a join table behind the scenes (e.g., StudentCourse) to manage the many-to-many relationship.


30. How do you handle cascading deletes in EF Core?

Question:

You have a Blog entity that contains multiple Posts. When a Blog is deleted, you want all related Posts to be deleted automatically. How do you configure cascading deletes in EF Core?

Answer:

EF Core supports cascading deletes, which can be configured using the OnDelete method in OnModelCreating.

  1. Define the entities:

    public class Blog
    {
        public int BlogId { get; set; }
        public string Title { get; set; }
        public ICollection<Post> Posts { get; set; }
    }
    
    public class Post
    {
        public int PostId { get; set; }
        public string Content { get; set; }
        public int BlogId { get; set; }
        public Blog Blog { get; set; }
    }
    
  2. Configure cascading deletes in OnModelCreating:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .OnDelete(DeleteBehavior.Cascade); // Cascade delete configuration
    }
    

Now, when a Blog is deleted, all related Posts will be automatically deleted as well.



Here are more EF Core technical coding interview questions for experienced developers:


31. How do you implement custom queries that are not supported by EF Core directly?

Question:

You want to perform a custom query, such as using a stored procedure or custom SQL, that EF Core does not directly support. How would you implement this?

Answer:

EF Core allows executing raw SQL queries or stored procedures via FromSqlRaw or ExecuteSqlRaw. Here's how you can handle this:

  1. Executing a Raw SQL Query (SELECT): Use FromSqlRaw to execute a custom SQL query and return the result.

    var products = dbContext.Products
        .FromSqlRaw("SELECT * FROM Products WHERE Price > {0}", 100)
        .ToList();
    
  2. Executing a Stored Procedure: If you have a stored procedure that returns data, you can call it like this:

    var products = dbContext.Products
        .FromSqlRaw("EXEC GetProductsByPrice @p0", 100)
        .ToList();
    
  3. Non-Query SQL Execution (UPDATE, DELETE, etc.): Use ExecuteSqlRaw for commands that do not return data (e.g., UPDATE, DELETE).

    dbContext.Database.ExecuteSqlRaw("UPDATE Products SET Price = Price * 1.1 WHERE Category = 'Electronics'");
    
  4. Stored Procedure with Parameters: You can pass parameters using the FromSqlRaw or ExecuteSqlRaw method:

    var productId = 1;
    var result = dbContext.Products
        .FromSqlRaw("EXEC GetProductDetails @p0", productId)
        .ToList();
    

EF Core will map the results of the query to the appropriate entity class.


32. What is the difference between SaveChanges() and SaveChangesAsync() in EF Core?

Question:

Explain the difference between SaveChanges() and SaveChangesAsync(), and when would you use each one?

Answer:

SaveChanges() is a synchronous method that blocks the calling thread until all changes are persisted to the database. In contrast, SaveChangesAsync() is an asynchronous method that runs the same operation but does not block the thread while waiting for the database operations to complete.

  • Use SaveChanges():
    • When performing short-running database operations.
    • In console or desktop applications where asynchronous execution is not critical.
  • Use SaveChangesAsync():
    • In web applications (e.g., ASP.NET Core), where it is essential to avoid blocking the thread, especially when handling many requests simultaneously.
    • In scenarios where responsiveness and scalability are important, particularly with long-running queries or high-latency databases.

Example:

// Synchronous
dbContext.SaveChanges();

// Asynchronous
await dbContext.SaveChangesAsync();

33. How would you implement pagination in a large dataset using EF Core?

Question:

You need to implement pagination for a large dataset of Products to avoid loading everything into memory at once. How would you achieve this in EF Core?

Answer:

To implement pagination in EF Core, you can use the Skip() and Take() methods to fetch a subset of data for each page. This is especially useful when dealing with large datasets to reduce memory consumption and improve performance.

  1. Example of Pagination:

    public async Task<IEnumerable<Product>> GetProducts(int pageNumber, int pageSize)
    {
        return await dbContext.Products
            .Skip((pageNumber - 1) * pageSize)  // Skip items before the current page
            .Take(pageSize)                    // Take the number of items for the current page
            .ToListAsync();
    }
    
  2. Handling Pagination Metadata: You can also return metadata (total count, total pages, etc.) to the client along with the paged data:

    public async Task<PagedResult<Product>> GetProducts(int pageNumber, int pageSize)
    {
        var totalCount = await dbContext.Products.CountAsync();
        var products = await dbContext.Products
            .Skip((pageNumber - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();
        
        return new PagedResult<Product>
        {
            Items = products,
            TotalCount = totalCount,
            TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
        };
    }
    
    public class PagedResult<T>
    {
        public IEnumerable<T> Items { get; set; }
        public int TotalCount { get; set; }
        public int TotalPages { get; set; }
    }
    

This ensures that only the necessary data is loaded for each page.


34. How would you implement a "soft delete" strategy with EF Core for related entities?

Question:

You have a Customer entity and a related Order entity. When you mark a Customer as deleted (soft delete), how do you ensure that all related Order records are also marked as deleted?

Answer:

You can use a combination of soft deletes and cascading soft delete logic. This involves marking the related Order entities as deleted when the Customer is soft deleted.

  1. Add an IsDeleted flag to both entities:

    public class Customer
    {
        public int CustomerId { get; set; }
        public string Name { get; set; }
        public bool IsDeleted { get; set; } // Soft delete flag
        public ICollection<Order> Orders { get; set; }
    }
    
    public class Order
    {
        public int OrderId { get; set; }
        public int CustomerId { get; set; }
        public bool IsDeleted { get; set; } // Soft delete flag
        public Customer Customer { get; set; }
    }
    
  2. Set up cascading soft delete:

    When deleting a Customer, you can mark all related Orders as deleted.

    public void SoftDeleteCustomer(int customerId)
    {
        var customer = dbContext.Customers
            .Include(c => c.Orders)  // Load related orders
            .FirstOrDefault(c => c.CustomerId == customerId);
    
        if (customer != null)
        {
            customer.IsDeleted = true;
    
            foreach (var order in customer.Orders)
            {
                order.IsDeleted = true;
            }
    
            dbContext.SaveChanges();
        }
    }
    

In this example, when a Customer is marked as deleted, all related Orders are also marked as deleted.


35. How do you optimize complex queries in EF Core?

Question:

You have a complex query involving multiple joins, aggregations, and filtering, and the query is running slowly. How would you optimize this in EF Core?

Answer:

Optimizing complex queries in EF Core can involve several strategies:

  1. Use AsNoTracking() for read-only queries:
    If you do not need change tracking, disable it to improve performance.

    var result = dbContext.Orders
        .AsNoTracking()
        .Where(o => o.CustomerId == customerId)
        .ToList();
    
  2. Select only the required columns:
    Instead of fetching entire entities, select only the columns you need.

    var result = dbContext.Orders
        .Where(o => o.CustomerId == customerId)
        .Select(o => new { o.OrderId, o.TotalAmount })
        .ToList();
    
  3. Break the query into smaller parts:
    If the query involves multiple steps or subqueries, break it into smaller, more manageable queries that are easier to optimize.

    var orders = dbContext.Orders
        .Where(o => o.CustomerId == customerId)
        .ToList();
    
    var orderItems = dbContext.OrderItems
        .Where(oi => orders.Select(o => o.OrderId).Contains(oi.OrderId))
        .ToList();
    
  4. Use indexes on frequently queried columns:
    Ensure that the database has indexes on columns involved in filtering (WHERE clauses) or joining operations.

  5. Consider database-level optimization:
    Sometimes, EF Core cannot fully optimize certain queries, especially those involving complex joins or aggregations. In such cases, using raw SQL or stored procedures can be beneficial.

    var result = dbContext.Products
        .FromSqlRaw("SELECT * FROM Products WHERE Price > {0}", 100)
        .ToList();
    

36. How do you handle transactions when using SaveChanges() for multiple entities in EF Core?

Question:

You need to save changes to multiple entities (Customer, Order, and Product) in a single transaction. How would you handle this to ensure all changes are persisted atomically?

Answer:

To handle transactions that involve multiple entities, you can use the TransactionScope or IDbContextTransaction provided by EF Core.

  1. Using IDbContextTransaction:

    using (var transaction = dbContext.Database.BeginTransaction())
    {
        try
        {
            // Modify entities
            dbContext.Customers.Add(new Customer { Name = "John Doe" });
            dbContext.Orders.Add(new Order { CustomerId = 1, OrderDate = DateTime.Now });
            dbContext.Products.Add(new Product { Name = "Laptop", Price = 1200 });
    
            // Save all changes in one transaction
            dbContext.SaveChanges();
    
            // Commit transaction
            transaction.Commit();
        }
        catch (Exception)
        {
            // Rollback in case of failure
            transaction.Rollback();
            throw;
        }
    }
    

In this example, all changes are committed or rolled back as a unit, ensuring data consistency across the different entities.



Here are additional advanced EF Core technical coding interview questions for experienced developers:


37. How do you handle concurrency conflicts in EF Core?

Question:

You are working on a multi-user application where two users might attempt to update the same record simultaneously. How do you handle concurrency conflicts in EF Core?

Answer:

EF Core provides optimistic concurrency handling, where a conflict occurs when two users try to update the same record at the same time. This can be resolved using a row version or timestamp field that tracks changes.

  1. Add a RowVersion field to your entity:

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    
        // RowVersion property for concurrency control
        [Timestamp]
        public byte[] RowVersion { get; set; }
    }
    
  2. Handle concurrency exceptions in your code:

    When a conflict occurs, EF Core will throw a DbUpdateConcurrencyException.

    try
    {
        dbContext.SaveChanges();
    }
    catch (DbUpdateConcurrencyException ex)
    {
        // Handle concurrency conflict
        foreach (var entry in ex.Entries)
        {
            if (entry.State == EntityState.Modified)
            {
                // Optionally, reload the entity and merge changes
                entry.OriginalValues.SetValues(entry.GetDatabaseValues());
            }
        }
    }
    

By marking the RowVersion property with the [Timestamp] attribute, EF Core will automatically check this column when saving the entity to ensure no conflicting updates have been made.


38. What is the role of ValueGeneratedOnAdd() and ValueGeneratedOnUpdate() in EF Core?

Question:

You need to configure a property in your entity to be automatically generated on insert and updated on every update. How would you achieve this in EF Core?

Answer:

ValueGeneratedOnAdd() and ValueGeneratedOnUpdate() are methods in EF Core used to configure how a property value is generated by the database.

  • ValueGeneratedOnAdd(): This tells EF Core that the value of the property will be generated when the entity is added (e.g., an identity column or GUID).
  • ValueGeneratedOnUpdate(): This tells EF Core that the value of the property will be updated every time the entity is updated (e.g., a timestamp or version number).
  1. Example: Auto-generated value on insert and update:

    public class Order
    {
        public int OrderId { get; set; }
        public string OrderNumber { get; set; }
    
        // A column that is generated on insert and updated on every update
        public DateTime LastModified { get; set; }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>()
            .Property(o => o.LastModified)
            .ValueGeneratedOnAddOrUpdate(); // Value generated on both add and update
    }
    

In this example, LastModified will be automatically populated on insert and updated every time the entity is updated.


39. How do you prevent N+1 query problems in EF Core?

Question:

You notice that your application is making N+1 queries for related data, resulting in performance issues. How do you prevent this in EF Core?

Answer:

The N+1 query problem occurs when EF Core generates an additional query for each related entity, which can result in excessive database calls. This issue can be mitigated using eager loading (via Include()) or explicit loading.

  1. Eager Loading: Use Include() to load related entities in a single query.

    var products = dbContext.Products
        .Include(p => p.Category)      // Include related Category data
        .ToList();
    
  2. Eager Loading with Multiple Relations:

    var orders = dbContext.Orders
        .Include(o => o.Customer)      // Include Customer relation
        .Include(o => o.OrderItems)    // Include OrderItems relation
        .ThenInclude(oi => oi.Product) // Include Product inside OrderItems
        .ToList();
    
  3. Use .ToList() as early as possible to limit multiple queries and reduce the time complexity.

    var products = dbContext.Products
        .Include(p => p.Supplier)
        .ToList();  // The Include() should be used before ToList() to reduce N+1 problems
    

By eager loading, EF Core will generate a single SQL query with JOINs to retrieve the data, which reduces unnecessary database round trips.


40. How do you implement custom conventions in EF Core?

Question:

You want to automatically apply a specific convention to all entities in your model (e.g., automatically naming all string columns with a max length of 255 characters). How do you implement this?

Answer:

EF Core allows you to implement custom conventions by overriding OnModelCreating and using the ModelBuilder API.

  1. Example: Apply a max length convention to all string properties:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        foreach (var entity in modelBuilder.Model.GetEntityTypes())
        {
            foreach (var property in entity.GetProperties())
            {
                if (property.ClrType == typeof(string))
                {
                    property.SetMaxLength(255); // Apply max length of 255 to all string properties
                }
            }
        }
    }
    
  2. Applying a custom naming convention for tables:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        foreach (var entity in modelBuilder.Model.GetEntityTypes())
        {
            entity.SetTableName(entity.GetTableName().ToLowerInvariant()); // Convert all table names to lowercase
        }
    }
    

These conventions are applied to all entities automatically when the model is created, allowing for easier maintenance and standardization of naming conventions.


41. How do you handle multi-tenancy with EF Core?

Question:

You need to support a multi-tenant application where each tenant has its own database. How would you manage multi-tenancy with EF Core?

Answer:

In a multi-tenant application, you can handle tenant isolation at the database level, schema level, or table level. The approach depends on the requirements for tenant isolation.

  1. Database per tenant: Each tenant has its own database. You can dynamically switch the database connection at runtime based on the tenant.

    public class ApplicationDbContext : DbContext
    {
        private readonly string _tenantConnectionString;
    
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, string tenantConnectionString)
            : base(options)
        {
            _tenantConnectionString = tenantConnectionString;
        }
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(_tenantConnectionString);  // Use tenant-specific database connection
        }
    }
    
  2. Schema per tenant: If you're using the same database but different schemas for each tenant, you can configure the DbContext to use different schemas for different tenants.

    public class ApplicationDbContext : DbContext
    {
        private readonly string _tenantSchema;
    
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, string tenantSchema)
            : base(options)
        {
            _tenantSchema = tenantSchema;
        }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema(_tenantSchema);  // Configure schema based on tenant
        }
    }
    
  3. Tenant identification: The tenant can be identified based on a header, URL segment, or user session. Once identified, you configure the context to use the appropriate database or schema.

    public class TenantProvider
    {
        public string GetTenantConnectionString(string tenantId)
        {
            // Return connection string based on the tenant
        }
    }
    

This allows you to isolate tenants either at the database level, schema level, or even table level, depending on the architecture and isolation requirements.


42. What is the purpose of HasQueryFilter in EF Core?

Question:

You want to automatically apply a global filter to all queries in EF Core, such as only retrieving active records. How do you implement this?

Answer:

EF Core provides the HasQueryFilter method to define global filters that apply to all queries for a given entity type.

  1. Example: Implementing a global "IsDeleted" filter:

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public bool IsDeleted { get; set; }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .HasQueryFilter(p => !p.IsDeleted); // Automatically exclude deleted products
    }
    
  2. Effect of Query Filters: When you perform queries on Product, EF Core will automatically apply the IsDeleted filter.

    var activeProducts = dbContext.Products.ToList();  // The query will automatically exclude IsDeleted = true
    

This is useful for scenarios such as soft deletes, where you want to exclude soft-deleted records globally without having to manually filter them out in each query.


43. How do you handle schema migrations when working with multiple databases in EF Core?

Question:

Your application needs to handle migrations for multiple databases (e.g., one for tenants and one for shared resources). How would you handle schema migrations for multiple databases in EF Core?

Answer:

EF Core allows you to work with multiple databases by configuring each database and applying migrations separately.

  1. Create multiple contexts for each database:

    public class TenantDbContext : DbContext
    {
        public TenantDbContext(DbContextOptions<TenantDbContext> options)
            : base(options) { }
    }
    
    public class SharedDbContext : DbContext
    {
        public SharedDbContext(DbContextOptions<SharedDbContext> options)
            : base(options) { }
    }
    
  2. Applying migrations for each database:

    • First, ensure that each context has its own migration configuration.
    • Use the dotnet ef migrations add and dotnet ef database update commands for each context.
    # Apply migrations for the tenant database
    dotnet ef migrations add TenantMigration --context TenantDbContext
    dotnet ef database update --context TenantDbContext
    
    # Apply migrations for the shared database
    dotnet ef migrations add SharedMigration --context SharedDbContext
    dotnet ef database update --context SharedDbContext
    

EF Core will handle the migration and schema updates separately for each database.



Here are more advanced EF Core technical coding interview questions for experienced developers:


44. What is the difference between SaveChanges() and SaveChangesAsync() in EF Core?

Question:

What is the difference between SaveChanges() and SaveChangesAsync() in EF Core, and when would you use one over the other?

Answer:

  • SaveChanges(): This method is synchronous, meaning it will block the thread until the database operation is completed. It is suitable for scenarios where the database operations are fast or you don’t need to worry about scalability.

    dbContext.SaveChanges();  // Synchronous
    
  • SaveChangesAsync(): This method is asynchronous, meaning it doesn’t block the thread and allows for better scalability, especially in high-concurrency scenarios. It's recommended in web applications to avoid blocking threads and improve responsiveness.

    await dbContext.SaveChangesAsync();  // Asynchronous
    

When to use:
Use SaveChangesAsync() when you are working in asynchronous methods (e.g., web API or UI applications) to prevent blocking the UI thread or the request thread.


45. Explain the difference between eager loading, lazy loading, and explicit loading in EF Core.

Question:

What are the differences between eager loading, lazy loading, and explicit loading, and when should you use each?

Answer:

  1. Eager Loading:
    Eager loading loads related entities as part of the initial query using the Include() method. It is useful when you know you'll need the related data upfront.

    var orders = dbContext.Orders.Include(o => o.OrderItems).ToList();
    
    • Use case: When you need related data immediately and want to avoid multiple queries.
  2. Lazy Loading:
    Lazy loading automatically loads related entities when you access the navigation property. It requires enabling lazy loading proxies in the DbContext configuration.

    public class Order
    {
        public ICollection<OrderItem> OrderItems { get; set; }
    }
    
    • Use case: When you don’t know if you need the related data and want it to load on-demand.

    Configuration: Enable lazy loading by installing the Microsoft.EntityFrameworkCore.Proxies package and setting UseLazyLoadingProxies():

    optionsBuilder.UseLazyLoadingProxies();
    
  3. Explicit Loading:
    Explicit loading allows you to load related entities manually after the initial query is executed using Load() or ThenInclude().

    var order = dbContext.Orders.Find(1);
    dbContext.Entry(order).Collection(o => o.OrderItems).Load();
    
    • Use case: When you need more control over when related data is loaded.

46. What is the ValueGeneratedOnAddOrUpdate() method in EF Core, and how do you use it?

Question:

What is the purpose of the ValueGeneratedOnAddOrUpdate() method in EF Core, and how do you use it?

Answer:

The ValueGeneratedOnAddOrUpdate() method is used to configure a property that should be generated by the database both on insert and update. This is useful for properties like a timestamp or version number that should be updated every time an entity is updated.

  1. Example: Using ValueGeneratedOnAddOrUpdate():

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
    
        // Timestamp or version property
        public DateTime LastModified { get; set; }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .Property(p => p.LastModified)
            .ValueGeneratedOnAddOrUpdate();  // Automatically set and updated
    }
    
    • Use case: For properties like LastModified or a version number that is automatically updated on both add and update operations.

47. How do you configure a composite primary key in EF Core?

Question:

How would you configure a composite primary key for an entity in EF Core?

Answer:

In EF Core, you can configure a composite primary key by using the HasKey() method in the OnModelCreating method.

  1. Example: Configuring a composite primary key:

    public class OrderItem
    {
        public int OrderId { get; set; }
        public int ProductId { get; set; }
        public int Quantity { get; set; }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<OrderItem>()
            .HasKey(oi => new { oi.OrderId, oi.ProductId });  // Composite primary key
    }
    
    • Use case: When you need a composite key that involves more than one property.

48. How do you handle circular references in EF Core?

Question:

You have entities that reference each other, creating a circular reference (e.g., Order references Customer and Customer references Order). How do you handle this in EF Core?

Answer:

Circular references can be problematic when serializing entities, as they may cause infinite loops. EF Core has options to manage these references:

  1. Use JsonIgnore attribute: If you don’t want to serialize the circular references in APIs, use JsonIgnore to break the circular reference.

    public class Order
    {
        public int OrderId { get; set; }
        public Customer Customer { get; set; }
    }
    
    public class Customer
    {
        public int CustomerId { get; set; }
        [JsonIgnore]  // Prevent serialization of the circular reference
        public ICollection<Order> Orders { get; set; }
    }
    
  2. Configure the model to handle circular references: Use the ReferenceHandling configuration to control the handling of circular references globally for JSON serialization in your application.

    services.AddControllers()
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
        });
    
    • Use case: When serializing data for web APIs, breaking circular references helps to avoid stack overflow errors.

49. How do you implement custom database functions or stored procedures in EF Core?

Question:

You need to call a custom stored procedure or function from EF Core. How would you implement that?

Answer:

EF Core provides several ways to call raw SQL functions or stored procedures, either through FromSqlRaw() or ExecuteSqlRaw() methods.

  1. Calling a stored procedure with FromSqlRaw():

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
    }
    
    var products = dbContext.Products
        .FromSqlRaw("EXEC GetProducts")  // Call stored procedure
        .ToList();
    
  2. Executing a stored procedure with ExecuteSqlRaw():

    dbContext.Database.ExecuteSqlRaw("EXEC UpdateProductPrice {0}, {1}", productId, newPrice);
    
  3. Mapping stored procedure results: You can map stored procedure results to entities or raw types by using FromSqlRaw() with LINQ projections.

    var results = dbContext.Products
        .FromSqlRaw("EXEC GetProductsWithDetails")
        .Select(p => new { p.ProductId, p.Name, p.Price })
        .ToList();
    
  4. Executing scalar values:

    var total = dbContext.Database
        .ExecuteSqlRaw("SELECT SUM(Price) FROM Products");
    

50. What are shadow properties in EF Core?

Question:

What are shadow properties in EF Core, and how do you use them?

Answer:

Shadow properties are properties that are not defined in the entity class but are still tracked by EF Core and stored in the database. They can be useful for scenarios such as auditing or tracking metadata.

  1. Example: Defining a shadow property:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .Property<DateTime>("CreatedDate");  // Shadow property
    }
    
    • Access shadow property:
    var createdDate = dbContext.Entry(product).Property("CreatedDate").CurrentValue;
    
    • Use case: For scenarios like storing audit data or additional metadata without modifying your entity class.



Here are more advanced EF Core technical coding interview questions for experienced developers:


51. How do you handle transactions in EF Core?

Question:

How do you manage transactions in EF Core, and what are the different ways to work with transactions?

Answer:

EF Core provides several ways to handle transactions, either automatically through SaveChanges() or manually using IDbContextTransaction.

  1. Automatic Transactions (Default):
    EF Core automatically wraps all SaveChanges() calls in a transaction. If the save is successful, the transaction is committed; if any exception occurs, the transaction is rolled back.

    dbContext.SaveChanges(); // Automatic transaction management
    
  2. Manual Transactions:
    For more control, you can manually start, commit, or roll back transactions using IDbContextTransaction. This is useful when you want to execute multiple operations in a single transaction.

    using (var transaction = dbContext.Database.BeginTransaction())
    {
        try
        {
            // Perform multiple database operations
            dbContext.SaveChanges();
            transaction.Commit();  // Commit the transaction
        }
        catch
        {
            transaction.Rollback();  // Rollback in case of error
        }
    }
    
  3. Async Transactions:
    EF Core also supports async transaction handling. The BeginTransactionAsync() method is used when working with async code.

    using (var transaction = await dbContext.Database.BeginTransactionAsync())
    {
        try
        {
            await dbContext.SaveChangesAsync();
            await transaction.CommitAsync();  // Commit the transaction
        }
        catch
        {
            await transaction.RollbackAsync();  // Rollback in case of error
        }
    }
    

Use Case: Use manual transactions when you need multiple operations (e.g., multiple SaveChanges() calls or other database operations) to be part of the same atomic transaction.


52. How do you configure a one-to-many relationship in EF Core?

Question:

How do you configure a one-to-many relationship between two entities in EF Core?

Answer:

A one-to-many relationship occurs when one entity has multiple related entities, and the related entities have a foreign key to the primary entity. In EF Core, this is configured using the HasOne() and WithMany() methods in the OnModelCreating method.

  1. Example: Configuring a one-to-many relationship:

    public class Customer
    {
        public int CustomerId { get; set; }
        public string Name { get; set; }
        public ICollection<Order> Orders { get; set; }
    }
    
    public class Order
    {
        public int OrderId { get; set; }
        public int CustomerId { get; set; }
        public Customer Customer { get; set; }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>()
            .HasOne(o => o.Customer)        // Each Order has one Customer
            .WithMany(c => c.Orders)        // Each Customer can have many Orders
            .HasForeignKey(o => o.CustomerId);  // The foreign key on Order
    }
    
    • Use case: When a Customer can have multiple Orders, but each Order is related to only one Customer.

53. How do you configure inheritance with EF Core?

Question:

How do you configure inheritance in EF Core, and what strategies are available for mapping inheritance to the database?

Answer:

EF Core supports three strategies for handling inheritance in the database:

  1. Table per Hierarchy (TPH):
    In TPH, a single table is used to store all entities in the inheritance hierarchy, and a discriminator column is used to distinguish between the different types.

    public class Animal
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    public class Dog : Animal
    {
        public string Breed { get; set; }
    }
    
    public class Cat : Animal
    {
        public string Color { get; set; }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Animal>()
            .HasDiscriminator<string>("AnimalType")
            .HasValue<Dog>("Dog")
            .HasValue<Cat>("Cat");
    }
    
    • Use case: Use TPH when you want to store all classes in the hierarchy in a single table.
  2. Table per Type (TPT):
    In TPT, each class in the inheritance hierarchy has its own table, but these tables are linked through foreign keys.

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Dog>()
            .ToTable("Dogs")
            .HasBaseType<Animal>();
    
        modelBuilder.Entity<Cat>()
            .ToTable("Cats")
            .HasBaseType<Animal>();
    }
    
    • Use case: Use TPT when you need to keep separate tables for each type, but need to join them together when querying.
  3. Table per Concrete Class (TPC):
    In TPC, each class in the hierarchy has its own table and there is no shared base table. This means the data for each class is duplicated across tables.

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Dog>().ToTable("Dogs");
        modelBuilder.Entity<Cat>().ToTable("Cats");
    }
    
    • Use case: Use TPC when you need fully separated tables for each type without shared properties between classes.

54. How do you handle soft deletes in EF Core?

Question:

How do you implement soft deletes in EF Core, where a record is marked as deleted but not actually removed from the database?

Answer:

In EF Core, you can handle soft deletes by adding a flag (e.g., IsDeleted) to your entities and filtering out soft-deleted records globally using a query filter.

  1. Step 1: Add an IsDeleted property to your entity:

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public bool IsDeleted { get; set; }
    }
    
  2. Step 2: Configure the global filter in OnModelCreating:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .HasQueryFilter(p => !p.IsDeleted);  // Global query filter for soft deletes
    }
    
  3. Step 3: Soft delete operation:

    When performing a soft delete, you just update the IsDeleted flag:

    var product = dbContext.Products.Find(1);
    if (product != null)
    {
        product.IsDeleted = true;
        dbContext.SaveChanges();
    }
    
  4. Step 4: Handling includes with soft deletes:

    If you want to include soft-deleted records in a query, you can override the global filter:

    var productsIncludingDeleted = dbContext.Products
        .IgnoreQueryFilters()  // This disables the global filter temporarily
        .ToList();
    
    • Use case: Soft deletes are useful when you want to keep historical data for auditing or recovery purposes.

55. How do you manage database schema versioning with EF Core migrations?

Question:

How do you manage database schema versioning using EF Core migrations?

Answer:

EF Core provides a migration system that allows you to track changes to your database schema over time. It’s essential for keeping the database schema in sync with the application code.

  1. Add a migration:
    Whenever you make changes to your model (e.g., adding, removing, or modifying entities), you can generate a migration using the dotnet ef migrations add command.

    dotnet ef migrations add AddProductTable
    
  2. Apply migrations:
    To update the database schema, use the dotnet ef database update command.

    dotnet ef database update
    
  3. Versioning:
    Each migration file is timestamped and can be used to roll back to a specific state of the database schema. EF Core maintains a special table, __EFMigrationsHistory, in the database to track applied migrations.

  4. Roll back a migration:
    You can remove the last migration if it has not yet been applied to the database using:

    dotnet ef migrations remove
    

    To revert the database to a previous state, you can use:

    dotnet ef database update <MigrationName>
    
    • Use case: Migrations are essential in team environments to maintain synchronization between the application's database schema and the codebase.

56. How do you handle database seeding in EF Core?

Question:

How do you implement database seeding in EF Core to add initial data to your database?

Answer:

EF Core provides a way to seed data using the HasData() method in the OnModelCreating method, which allows you to populate the database with initial data when migrations are applied.

  1. Example: Seeding data using HasData():

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().HasData(
            new Product { ProductId = 1, Name = "Product1", Price = 10.0m },
            new Product { ProductId = 2, Name = "Product2", Price = 20.0m }
        );
    }
    
  2. Running migrations to apply seed data: After defining your seed data, run the migration and update the database:

    dotnet ef migrations add SeedProducts
    dotnet ef database update
    
  3. Use Case:
    Database seeding is useful for adding initial lookup data (like categories, roles, or

default settings) when setting up the application for the first time.



Here are more advanced EF Core technical coding interview questions for experienced developers:


57. How do you handle concurrency in EF Core?

Question:

How do you handle concurrency issues in EF Core when multiple users or processes try to update the same record simultaneously?

Answer:

EF Core provides two approaches to handle concurrency:

  1. Optimistic Concurrency Control:

    • Optimistic concurrency allows multiple users to retrieve the same record but requires a way to detect conflicts when saving changes. EF Core uses a timestamp or version number field to track the state of an entity.

    Steps to implement Optimistic Concurrency:

    • Add a Timestamp or RowVersion property to the entity:

      public class Product
      {
          public int ProductId { get; set; }
          public string Name { get; set; }
          public decimal Price { get; set; }
          [Timestamp]
          public byte[] RowVersion { get; set; }  // This field is used for concurrency
      }
      
    • Enable concurrency control in OnModelCreating:

      protected override void OnModelCreating(ModelBuilder modelBuilder)
      {
          modelBuilder.Entity<Product>()
              .Property(p => p.RowVersion)
              .IsRowVersion();
      }
      
    • When saving changes, EF Core automatically checks if the RowVersion has changed in the database. If it has, a DbUpdateConcurrencyException is thrown.

    • Handling the exception:

      try
      {
          dbContext.SaveChanges();
      }
      catch (DbUpdateConcurrencyException ex)
      {
          // Handle concurrency conflict
      }
      
    • Use case: Optimistic concurrency is ideal for scenarios where conflicts are rare and you want to minimize locking, like in web applications.

  2. Pessimistic Concurrency Control:

    • Pessimistic concurrency locks the record so that other users cannot modify it until the transaction is completed. EF Core does not have built-in support for pessimistic locking, but it can be achieved through raw SQL queries.
    var product = dbContext.Products
        .FromSqlRaw("SELECT * FROM Products WHERE ProductId = {0} FOR UPDATE", productId)
        .FirstOrDefault();
    
    • Use case: Pessimistic concurrency is useful in scenarios where data consistency is critical, such as financial applications.

58. What are shadow properties and how are they used in EF Core?

Question:

What are shadow properties, and how are they used in EF Core?

Answer:

Shadow properties are properties that are defined in the database but are not directly included in the entity class. These properties are not part of the entity's class but are still tracked by EF Core.

  1. Defining Shadow Properties: Shadow properties can be added using the ModelBuilder in the OnModelCreating method.

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .Property<DateTime>("CreatedDate");  // Shadow property
    }
    
  2. Accessing Shadow Properties: Shadow properties are not part of the entity class, so they are accessed via the Entry() method.

    var createdDate = dbContext.Entry(product).Property("CreatedDate").CurrentValue;
    
  3. Use case: Shadow properties are useful for auditing, versioning, or storing metadata without modifying the entity class.


59. How do you configure a Many-to-Many relationship in EF Core?

Question:

How do you configure a many-to-many relationship between two entities in EF Core?

Answer:

In EF Core 5 and later, you can configure a many-to-many relationship without explicitly creating a join entity.

  1. Example: Many-to-Many Relationship:

    Let's say we have Student and Course entities, where a student can enroll in multiple courses, and a course can have multiple students.

    public class Student
    {
        public int StudentId { get; set; }
        public string Name { get; set; }
        public ICollection<Course> Courses { get; set; }
    }
    
    public class Course
    {
        public int CourseId { get; set; }
        public string Title { get; set; }
        public ICollection<Student> Students { get; set; }
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Student>()
            .HasMany(s => s.Courses)
            .WithMany(c => c.Students)
            .UsingEntity<Dictionary<string, object>>(
                "StudentCourse",  // Join table name
                j => j.HasOne<Course>().WithMany().HasForeignKey("CourseId"),
                j => j.HasOne<Student>().WithMany().HasForeignKey("StudentId"));
    }
    
  2. Use case: This approach works well when there are no additional properties on the join table. If additional properties (e.g., EnrollmentDate) are needed, you can create an explicit join entity.


60. What is the difference between AsNoTracking() and AsTracking() in EF Core?

Question:

What is the difference between AsNoTracking() and AsTracking() in EF Core, and when would you use each?

Answer:

  • AsNoTracking():

    • This method returns a query where the entities are not tracked by the DbContext. This improves performance because no change tracking is done.
    • Use case: Use AsNoTracking() when you are reading data for display purposes (e.g., read-only operations) and do not need to update the data.
    var products = dbContext.Products.AsNoTracking().ToList();
    
  • AsTracking():

    • This is the default behavior of EF Core, where entities are tracked by the DbContext. This means that EF Core will track any changes to the entities and save them to the database when SaveChanges() is called.
    • Use case: Use AsTracking() when you need to modify the retrieved entities and save those changes back to the database.
    var product = dbContext.Products.AsTracking().FirstOrDefault();
    
  • Performance Considerations:
    AsNoTracking() is typically more performant for read-only queries, as it reduces the overhead of change tracking. AsTracking() should be used when you need to perform operations like update or delete on the entities.


61. How do you configure a unique constraint in EF Core?

Question:

How do you configure a unique constraint for an entity property in EF Core?

Answer:

In EF Core, you can configure a unique constraint using the HasIndex() method and then apply the IsUnique() modifier.

  1. Example: Configuring a Unique Constraint:

    public class Product
    {
        public int ProductId { get; set; }
        public string Name { get; set; }
        public string SKU { get; set; }  // SKU must be unique
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>()
            .HasIndex(p => p.SKU)
            .IsUnique();  // Adding a unique constraint on the SKU property
    }
    
  2. Use case: This is useful when you need to enforce a unique constraint on a property (e.g., Email, SKU, Username).


62. How do you handle database migrations in a team environment with EF Core?

Question:

How do you handle database migrations in a team environment with EF Core?

Answer:

In a team environment, it's important to have a strategy to keep the database schema synchronized among all developers. Here are some best practices:

  1. Consistent Migration Management:

    • Ensure that every developer adds and applies migrations before starting new work.
    • Always run dotnet ef migrations add and dotnet ef database update to ensure migrations are up-to-date.
  2. Migration Workflow:

    • Developers should add migrations in sequence (one at a time) to avoid conflicts. Each developer should pull the latest changes from the version control system before adding their own migration.
  3. Apply Migrations to Local Development Database:

    • Always apply migrations to local databases and validate them before committing changes.
  4. Review Migrations:

    • Migrations should be reviewed to ensure that they do not contain unnecessary changes (e.g., changes that alter or drop existing data, unless intended).
  5. Migration in CI/CD:

    • Set up Continuous Integration (CI) pipelines that automatically apply migrations to test/staging databases to ensure that all migrations are applied correctly.

63. What is Include() and ThenInclude() in EF Core, and how do they work with relationships?

Question:

Explain the purpose of Include() and ThenInclude() in EF Core. How do they work in loading related data?

Answer:

In EF Core, Include() is used for eager loading of related data, while ThenInclude() is used for including nested related data.

  1. Include():

    • Include() is used to load related data along with the primary data.
    var orders = dbContext.Orders.Include(o => o.OrderItems).ToList();
    
  2. ThenInclude():

    • ThenInclude() is used to load additional related data from the related entities fetched via Include().
    var orders = dbContext.Orders
        .Include(o => o.OrderItems)
        .ThenInclude(oi => oi.Product)  // Include related Product for each OrderItem
        .ToList();
    

Use case: Use Include() when you need to eagerly load direct relationships, and ThenInclude() when you need to load deeper nested relationships.



64. How do you use raw SQL queries in EF Core?


Question:  

How do you execute raw SQL queries in EF Core, and when would you use them?


Answer:  

EF Core allows executing raw SQL queries to interact directly with the database. This can be useful when you need complex queries that cannot be easily expressed using LINQ or need to improve performance.


1. Raw SQL with FromSqlRaw():

   - Use FromSqlRaw() to execute SELECT queries.


Example:

   var products = dbContext.Products

       .FromSqlRaw("SELECT * FROM Products WHERE Price > {0}", 20)

       .ToList();



2. Executing non-SELECT queries:

   - Use ExecuteSqlRaw() for executing non-SELECT queries (e.g., INSERT, UPDATE, DELETE).


Example:

   dbContext.Database.ExecuteSqlRaw("UPDATE Products SET Price = Price * 1.1 WHERE CategoryId = {0}", categoryId);



3. Parameterized Queries:

   - Always use parameterized queries to prevent SQL injection vulnerabilities.


Example:

   var productId = 1;

   var product = dbContext.Products

       .FromSqlRaw("SELECT * FROM Products WHERE ProductId = {0}", productId)

       .FirstOrDefault();



4. Use case: Raw SQL queries are often used when you need to execute complex queries, work with stored procedures, or improve performance for certain scenarios that cannot be handled easily with LINQ.




65. What are the differences between Add(), Update(), and Attach() in EF Core?


Question:  

What is the difference between Add(), Update(), and Attach() methods in EF Core?


Answer:  

In EF Core, these methods are used to manage the state of entities in the DbContext.


1. Add():

   - Adds a new entity to the context. The entity is tracked as Added and will be inserted into the database when SaveChanges() is called.

   - Use case: When you are inserting a new entity.


Example:

   var newProduct = new Product { Name = "New Product" };

   dbContext.Products.Add(newProduct);

   dbContext.SaveChanges();



2. Update():

   - Marks an existing entity as Modified. This method is typically used when you want to modify an entity that already exists in the database.

   - Use case: When you want to update an existing entity's values, and EF Core will track it for changes.


Example:

   var product = dbContext.Products.Find(1);

   product.Name = "Updated Product";

   dbContext.Products.Update(product);

   dbContext.SaveChanges();



3. Attach():

   - Attaches an entity to the context without marking it as Added or Modified. The entity is tracked as Unchanged unless its properties are modified.

   - Use case: When you have an entity that exists in the database, but you want to attach it to the context without modifying it. Useful when you only want to track an entity without triggering any insert or update.


Example:

   var product = new Product { ProductId = 1 };

   dbContext.Products.Attach(product);  // No change to entity, just tracking

   dbContext.SaveChanges();





66. How do you optimize database performance with EF Core?


Question:  

What techniques do you use to optimize database performance in EF Core?


Answer:  

There are several ways to optimize performance in EF Core:


1. Use AsNoTracking() for Read-Only Queries:

   - When you don’t need to update the entities, use AsNoTracking() to avoid the overhead of change tracking.

   

Example:

   var products = dbContext.Products.AsNoTracking().ToList();



2. Lazy Loading vs Eager Loading:

   - Eager Loading: Use Include() to load related data in a single query to reduce the number of round trips to the database.

   

  Example:

     var order = dbContext.Orders.Include(o => o.OrderItems).FirstOrDefault();

  

   

   - Lazy Loading: Be cautious when using lazy loading because it can result in multiple queries being sent to the database. Enable lazy loading only when necessary and control it carefully.


3. Use Select() for Optimized Queries:

   - Only select the necessary columns to improve performance and reduce the amount of data being fetched.

   

Example:

   var products = dbContext.Products

       .Where(p => p.Price > 100)

       .Select(p => new { p.Name, p.Price })

       .ToList();



4. Batch Updates:

   - Instead of performing multiple SaveChanges() calls, try to batch them together to reduce database round-trips.


5. Indexing:

   - Ensure that the database tables have appropriate indexes on columns that are frequently queried. EF Core can configure indexes using HasIndex().


Example:

   modelBuilder.Entity<Product>()

       .HasIndex(p => p.Name)

       .IsUnique();



6. Avoid N+1 Query Problem:

   - Avoid executing additional queries in loops. Instead, use Include() to eagerly load related entities or Select() to retrieve only necessary data.


7. Use Raw SQL for Complex Queries:

   - If a query is too complex for LINQ or causes performance problems, use raw SQL for fine-grained control over query performance.




67. What are value converters in EF Core?


Question:  

What are value converters in EF Core, and how do they help in customizing how values are stored in the database?


Answer:  

Value converters in EF Core allow you to define how data is converted when being read from and written to the database. They are used when you need to store data in a different format in the database than it is in your entity.


1. Example: If you want to store a DateTime as a string in the database (in a specific format), you can use a value converter.


Example:

   public class Product

   {

       public int ProductId { get; set; }

       public DateTime CreatedDate { get; set; }

   }


   protected override void OnModelCreating(ModelBuilder modelBuilder)

   {

       var dateTimeConverter = new ValueConverter<DateTime, string>(

           v => v.ToString("yyyy-MM-dd"),  // Convert DateTime to string

           v => DateTime.Parse(v));        // Convert string to DateTime


       modelBuilder.Entity<Product>()

           .Property(p => p.CreatedDate)

           .HasConversion(dateTimeConverter);

   }



2. Use case: Value converters are useful when you need to store complex data types in a simplified format (e.g., converting enum values, DateTime values, or custom objects to a database column).




68. How do you handle schema changes during runtime with EF Core?


Question:  

How do you manage schema changes during runtime without downtime in EF Core?


Answer:  

In EF Core, schema changes typically require migrations, but handling runtime schema changes without downtime can be more complex, especially in production environments. Here are some strategies to handle schema changes during runtime:


1. Zero-Downtime Migrations:

   - Break down migrations into smaller steps to avoid downtime. For example:

     - Add new columns with default values first.

     - Apply any business logic changes after the column is added.

     - Once the changes are applied, you can remove old columns or tables if necessary.


2. Rolling Migrations:

   - Apply migrations in a rolling manner, updating one node at a time in a multi-node application.

   - Use application versioning to ensure backward compatibility during the migration.


3. Use Database Views:

   - Use database views to abstract complex schema changes and make them transparent to the application.


4. Feature Toggles for Schema Changes:

   - Use feature toggles to gradually roll out new features and schema changes without breaking the application.


5. Use Blue-Green Deployment:

   - Use blue-green deployment strategies where you have two production environments (Blue and Green). You deploy the new schema to one environment and switch traffic over once everything is validated.




69. How do you perform database migrations in a cloud-based environment like Azure?


Question:  

How do you perform EF Core database migrations in a cloud-based environment such as Azure?


Answer:  

To perform EF Core migrations in a cloud-based environment (e.g., Azure), the process is similar to how you would perform migrations locally, but with considerations for cloud infrastructure and deployment pipelines.


1. Using Azure CLI:

   - You can run migrations directly from Azure via the Azure CLI by connecting to the app's web app and using the dotnet ef commands.

   

bash

   az webapp ssh --name <app_name> --resource-group <resource_group>

   dotnet ef migrations add MigrationName

   dotnet ef database update



2. Using CI/CD Pipelines:

   - Implement CI/CD pipelines (e.g., Azure DevOps, GitHub Actions) to automatically run migrations during the deployment process.

   - You can add migration steps to your pipeline configuration:

   

yaml

   steps:

     - task: DotNetCoreCLI@2

      


 displayName: 'dotnet ef database update'

       inputs:

         command: 'custom'

         custom: 'ef'

         arguments: 'database update'



3. Ensure Backward Compatibility:

   - As with any production migration, ensure that the schema changes are backward-compatible with the previous version of the application to avoid breaking changes.



















Comments

Popular posts from this blog

Multiline to singleline IN C# - CODING

EF Core interview questions for beginners

EF Core interview questions for experienced