When using the Code-First approach, EF Core uses Conventions (smart defaults) to guess how your C# classes should map to SQL Tables. When those guesses are wrong, you can override them using Data Annotations—attributes placed directly on your C# properties.
If you don't strictly define your database rules, EF Core assumes the following:
User, it generates a table named Users (Pluralized).Id or UserId, it designates it as the Primary Key and configures it to Auto-Increment.string, it maps it to NVARCHAR(MAX) in SQL Server.int vs int?), it makes the SQL Column NOT NULL.Relying purely on conventions often leads to bloated databases (like defining every string field as MAX length). We use attributes from System.ComponentModel.DataAnnotations to assert strict control.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
// Overrides the table name convention
[Table("tbl_CompanyEmployees")]
public class Employee
{
// Explicitly declare the Primary Key
[Key]
public string EmployeeId { get; set; }
// Overrides NVARCHAR(MAX) to NVARCHAR(50)
// Marks the column as NOT NULL in the database
[Required]
[MaxLength(50)]
public string FirstName { get; set; }
// Maps the C# property "Cost" to a SQL column named "Calculated_Expense"
// Forces the SQL precision to be 18 digits with 2 decimal places
[Column("Calculated_Expense", TypeName = "decimal(18,2)")]
public decimal Cost { get; set; }
// This property exists in C# RAM, but will NEVER be created as a SQL Column!
[NotMapped]
public string FullName => $"{FirstName} {LastName}";
}
Data Annotations are powerful because they pull double-duty. The [Required] and [MaxLength(50)] attributes don't just configure the SQL Database column during migrations; they also automatically trigger ASP.NET Core MVC/Web API validation responses! If a user submits a 51-character string, the API will reject it with a 400 Bad Request before EF Core ever attempts to save it.
Q: "Why do Senior Architects generally discourage using Data Annotations to configure EF Core, preferring the Fluent API instead?"
Architect Answer: "The core philosophy of Domain-Driven Design (DDD) dictates that your Core Domain Entities (the C# classes) should be completely pure and unaware of the infrastructure layer. By plastering `[Table('tbl_Users')]` and `[Column(TypeName)]` all over our C# objects, we are tightly coupling our Domain to arbitrary SQL Database concerns. Furthermore, Data Annotations are functionally limited. They cannot configure complex schemas like shadow properties, composite primary keys, or sophisticated index filtering. The Fluent API (`OnModelCreating`) removes all database mapping logic from the C# classes and stores it in centralized configuration files, keeping our entities clean and unlocking 100% of EF Core's feature set."