Couchbase EFCore Provider Limitations
The Couchbase EFCore Provider is still evolving and does not currently support all features of EF Core or Couchbase. We recommend reviewing the known limitations to avoid potential issues and ensure a smooth development experience.
Unsupported EF Core Features
-
Eager loading/fetching — use the
Include
and/orThenInclude
methods to specify related data to be included in query results. -
Value generation — auto-generated values for properties and or primary keys.
-
Migrations — The migrations feature in EF Core provides a way to incrementally update the database schema to keep it in sync with the application’s data model while preserving existing data in the database.
-
Table splitting — EF Core allows to map two or more entities to a single row. This is called table splitting or table sharing.
-
Any features not explicitly mentioned in this documentation
Unsupported Couchbase Features
-
All queries use NOT_BOUNDED. This means that the query will not wait for the index to be updated before returning results. This is the default behavior for Couchbase queries.
-
Only default values are used for all queries generated and executed against Couchbase.
-
Only default values are used for K/V CRUD operations.
-
Transactions are not currently supported.
-
Enhanced durability is not currently supported.
-
Compare and swap (CAS) is not currently supported.
-
Pessimistic locking is not currently supported.
-
Field level encryption is not currently supported.
-
XATTR and Virtual XATTR are not currently supported.
-
Sub-Document operations are not currently supported.
-
Non-JSON Document types are not currently supported.
Only Async Queries Supported
Limitations on the Couchbase SDK mean that only async queries are supported.
If a sync query is attempted, a NotImplementedException
will be thrown with the following message:
"Couchbase EF Core Database Provider does not support synchronous I/O. Make sure to use and correctly await only async methods when using Entity Framework Core to access Couchbase database. See Couchbase EF Core Database Provider documentation for more information."
All async queries are expected to be awaited.
Avoid using Wait()
or Result()
on async queries, as this is the sync-over-async anti-pattern
and leads to deadlocks and thread pool starvation.
Subdocument (Denormalization) Not Supported
The Couchbase EF Core Provider maps to Couchbase’s JSON document model, which is not a relational model. This means that some features of EF Core may not work as expected, and data may not be saved as expected. For example, if you have a one-to-many relationship and you delete the parent entity, the child entities may not be deleted as well. This is because Couchbase does not have the concept of foreign keys or cascading deletes.
It is important to understand the limitations of the Couchbase EF Core Provider and to use it accordingly.
Additionally, parent JSON and chlidren document are stored in their own Collections.
Consider the following JSON document; in this case we have a parent document that represents a person and a child document that represents a child of that person.
If the child document does not have a primary key, it will be lost when the parent document is saved.
This is because EF Core will not be able to find the child document and it will not be saved to the database.
Additionally, two collections must exist in Couchbase: parent
and child
.
Now take this document for example:
{
"id": "1",
"name": "John Doe",
"children": [
{
"name": "Jane Doe"
}
]
}
In this document, the child document does not have an id, so it will be lost when the parent document is saved even if both collections exist. To fix this, you need to ensure that the child document has an id, like so:
{
"id": "1",
"name": "John Doe",
"children": [
{
"id": "2",
"name": "Jane Doe"
}
]
}
This will be mapped to the following entities:
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
public List<Child> Children { get; set; }
}
public class Child
{
public string Id { get; set; }
public string Name { get; set; }
}
In the a DbContext.OnModelCreating
method, you would configure the entities like this:
builder.Entity<Person>().ToCouchbaseCollection(this, "parent");
builder.Entity<Child>().ToCouchbaseCollection(this, "child");
Avoid Dynamic or Object Type Properties
The dynamic and/or the System.Object type can be used as a property type in EF Core. This is not recommended for Couchbase, as it will not be able to map the property to a JSON document. This is the actual type of the field can only be determined at runtime. It is recommended to use a specific type for the property, such as a string or a number.
Unsupported LINQ Queries
LINQ queries can be a near unlimited variety of queries, and the EF Core Couchbase DB Provider does not support all of them.
If a lambda expression cannot be translated into a SQL++ statement, then query will error out with a InvalidOperationException
and a message similar to the following:
System.InvalidOperationException The LINQ expression 'DbSet<Customer>() .Where(c => (int)DbSet<Order>() .Where(o => o.CustomerID == "John Doe") .Select(o => (int?)o.CustomerID.Length) .FirstOrDefault() == 0)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.`
Note that while the error message indicates that the query cannot re-rewritten using AsEnumerable
or ToList
, this is not a supported feature of the EF Core Couchbase DB Provider as it is sync-over-async.