In Entity Framework, entities are the representation of business objects that are mapped 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.
Entities, in turn, are composed of properties, which correspond to the columns of the tables.
Features of Entities
- Simple classes: Entities are simple C# classes (do not depend on any specific base class from Entity Framework)
- Properties: The class properties represent the columns of the table
- Relationships: They have relationships with other entities, allowing for complex data structure modeling
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 object objects, instead of directly manipulating the database tables.
Defining an Entity
To define a entity, we simply create a class in C#. For example, let’s say 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
Product
class represents theProducts
table. - Each property of the class (
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 type of column in the database.
EF Core will attempt to automatically map the properties of the entity classes to the appropriate data types in the database, based on the type of the property 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 “basic” information and data. EF Core automatically maps these data types.
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
->INT
string
->VARCHAR
DateTime
->DATETIME
bool
->BIT
Although we will see that we can customize this behavior.
These properties do not map directly 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 to which a product belongs. Similarly, Products
in the Category
class is a navigation property that allows access to all products of a category.
Configuring Entities
Entities must be configured to be used. By default, Entity Framework uses naming conventions.
On the other hand, sometimes we will need to change or refine this configuration. Then we have two main methods, data annotations and 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 may cause conflicts)