In Entity Framework, entities are the representation of business objects that map to tables in a relational database.
That is, an entity is a C# class that will have a representation in a table in the database. Each instance of this class will correspond to a row in the table.
In turn, entities are composed of properties, which correspond to the columns of the tables.
Characteristics of Entities
- Simple Classes: Entities are simple C# classes (they do not depend on any specific Entity Framework base class)
- Properties: The class properties represent the table columns
- Relationships: They have relationships with other entities, allowing the modeling of complex data structures
Entities and their properties are the foundation of data modeling in Entity Framework, and they allow us to work with data in the form of objects, instead of directly manipulating database tables.
Defining an Entity
To define an entity, we simply create a class in C#. For example, suppose we want to model a Products table in our database.
The corresponding entity might look like this:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
}
In this example,
- The
Productclass represents theProductstable. - Each class property (
Id,Name,Price,Stock) corresponds to a column in the table.
Properties of an Entity
The properties of an entity represent the columns of the table. Each property has a data type that determines the column type in the database.
EF Core will try to automatically map the properties of the entity classes to the appropriate data types in the database, based on the property type in C#.
Thus, we have two main types of properties in Entity Framework.
- Scalar Properties: Represent simple values like
int,string,decimal,DateTime, etc. - Navigation Properties: Represent relationships between entities.
They contain the “basic” information and data. EF Core maps these data types automatically.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public DateTime CreationDate { get; set; }
}
In this example, Id, Name, Price and CreationDate are scalar properties that map to columns in the Products table.
Some common basic data types in EF Core include:
int->INTstring->VARCHARDateTime->DATETIMEbool->BIT
Although we will see later that we can customize this behavior.
These properties are not directly mapped to columns in the table, but allow access to related entities.
For example, suppose we have a Category entity and we want to relate it to Product:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int CategoryId { get; set; } // Foreign key
public Category Category { get; set; } // Navigation property
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Product> Products { get; set; } // Navigation property
}
In this case, Category is a navigation property that allows access to the category a product belongs to. Similarly, Products in the Category class is a navigation property that allows access to all products in a category.
Entity Configuration
Entities must be configured to be used. By default, Entity Framework uses certain naming conventions.
On the other hand, sometimes we will need to change or fine-tune this configuration. We then have two main methods, data annotations and the fluent API.
- Naming Conventions, implicit configuration (based on predefined rules)
- Data Annotations, explicit configuration using attributes
- Fluent API, explicit configuration using functions
Each of these approaches has its advantages and disadvantages
| Method | Advantages | Disadvantages |
|---|---|---|
| Conventions | ✅ Simple | ❌ Little control over mapping |
| Data Annotations | ✅ Can be more readable ✅ Good for validations | ❌ “Clutters” classes with attributes ❌ Limited for complex relationships |
| Fluent API | ✅ Maximum control over mapping ✅ Centralized configuration | ❌ Higher learning curve |
In general,
- Use naming conventions when they are sufficient.
- If they are not:
- Use Data Annotations for simple configurations (names, basic types)
- Prefer Fluent API for complex relationship configurations
Avoid mixing both approaches for the same entity (it can cause conflicts)
