In this lesson, you will learn how to enforce service boundaries while maintaining necessary data integrity when working with multiple databases in a microservice architecture.
Ownership and Isolation
In a microservice architecture, the most critical rule is that each service must own its data. You should never share a database between microservices. If Service A needs data from Service B, it should interact via an API, not by reaching into Service B’s tables.
However, a challenge arises when your business logic requires references between these services—for example, an Order in the Ordering Service needs to track a CustomerId from the Identity Service. Since you cannot use standard SQL Foreign Keys across databases, you must implement Logical Referential Integrity.
Implementing Logical References
Instead of using EF Core navigation properties that span database boundaries, you store the identifier of the remote entity as a plain property. This keeps the database schemas decoupled.
public class Order
{
public int Id { get; set; }
// We store the ID, but do not create a navigation property
// to the remote User entity.
public Guid CustomerId { get; set; }
public decimal TotalAmount { get; set; }
}
Ensuring Consistency
Because EF Core cannot enforce a Foreign Key constraint across two different physical databases, you must manage data consistency at the application layer. If a User is deleted in the Identity Service, the Ordering Service remains unaware. To handle this:
- Eventual Consistency: Use an event bus (like RabbitMQ or Azure Service Bus). When a user is deleted, the Identity Service publishes a
UserDeletedIntegrationEvent. - Local Handling: The Ordering Service listens for this event and executes a local command to update or "soft-delete" the associated
Orders.
By treating these relationships as local IDs rather than database-level joins, you prevent "leaky abstractions" where the schema of one service dictates the schema of another. This approach keeps your services independently deployable and scalable.
Key Takeaway: To maintain microservice autonomy, use plain IDs for cross-service references instead of physical Foreign Keys, and rely on integration events to maintain consistency across service boundaries.