Reputation: 73
Theory: So in my attempt to always improve i came across this conundrum. The following code underneath is the existing code. My understanding is that the app will actually make a separate connection for each of the following singletons. Since these all point at the same instance I am fairly certain that if you hit an index that has 2 of those classes youre usage of cosmos DB will be greater.
Question: Can you reduce the following singleton declarations to use a generic object of T so that way you can use one singleton vs the N+1?
services.AddSingleton<IDocumentDBRepository<Car>>(new DocumentDBRepository<Car>("Database"));
services.AddSingleton<IDocumentDBRepository<House>>(new DocumentDBRepository<House>("Database"));
services.AddSingleton<IDocumentDBRepository<Employer>>(new DocumentDBRepository<Employer>("Database"));
services.AddSingleton<IDocumentDBRepository<Photo>>(new DocumentDBRepository<Photo>("Database"));
Also if you have an alternate suggestion for me or something else to even look into please advise so i can research into it also!
Upvotes: 1
Views: 2626
Reputation: 106836
You seem to have several questions:
A) Your Cosmos usage only depends on the calls you make to the database and does not depend on how many services you create to access the database.
B) By looking at your code it seems that you are using Microsoft.Extensions.DependencyInjection
. This framework has support for open generics which in theory could reduce your four singleton registrations to a single registration using an open generic type. Something like:
.AddSingleton(typeof(IDocumentDBRepository<>), typeof(DocumentDBRepository<>)
Here the open generic service type is IDocumentDBRepository<>
and the implementation type is DocumentDBRepository<>
. When the dependency injection framework has to create an IDocumentDBRepository<Car>
service it will create an DocumentDBRepository<Car>
instance. This means that there will still be a repository instance for each specific document type (Car
, House
etc.) but you don't have to inject a service for each specific type.
Unfortunately, that is not possible in your case as you are using the constructor that require an argument for each of the four services. However, you might be able to refactor your services to work around this problem. One (general) solution is to introduce a factory:
public interface IDocumentDBRepositoryFactory<T>
{
IDocumentDBRepository<T> Create(string databaseName);
}
And the implemenentation:
internal class DocumentDBRepositoryFactory<T>
{
public IDocumentDBRepository<T> Create(string databaseName)
=> return new DocumentDBRepository(databaseName);
}
You then register this factory (using open generics):
.AddSingleton(typeof(IDocumentDBRepositoryFactory<>), typeof(DocumentDBRepositoryFactory<>)
Now the consumers of repositories will have to use an IDocumentDBRepositoryFactory<T>
instance and call the Create
method and supply the database name to get the actual IDocumentDBRepository<T>
instance. Another option is to get rid of the databaseName
argument to the factory method and instead configure the factory instance to supply this (presumably from configuration).
Introducing a factory allows you to postpone decisions from when you configure the system to when the system executes. In this case the decision about which database to connect to.
Upvotes: 1
Reputation: 5549
You may change your DocumentDBRepository
class to directly accept a DocumentClient
. In this way, it will not create a new client but use the specified one.
However, I do not think you should do this. Because, the CosmosDB usage count is based on RU not connection. Link for CosmosDB pricing
Azure Cosmos DB bills for provisioned throughput and consumed storage by the hour.
Provisioned throughput is expressed in Request Units per second (RU/s), which can be used for various database operations (e.g., inserts, reads, replaces, upserts, deletes, queries, etc.). For example, 1 RU/s is sufficient for processing one eventually consistent read per second of 1K item, and 5 RU/s is sufficient for processing one write per second of 1K item.
Storage is billed for each GB used for your SSD-backed data and index.
Upvotes: 1