Tấn*_*ang 6 c# repository data-partitioning .net-core azure-cosmosdb
我正在开发一个IDocumentClient用于对 CosmosDB 执行查询的应用程序。我GenericRepository通过查询支持Id和Predicate。
将数据库从 SqlServer 更改为 CosmosDb 时,我遇到了麻烦,在 CosmosDb 中,我们有partition key. 而且我不知道如何通过partition key不更改接口partition key作为参数传递来实现支持查询的存储库。
public interface IRepository<T>
{
//I can handle this one by adding value of partition key to id and split it by ":"
Task<T> FindByIdAsync(string id);
// I am stuck here!!!
Task<T> FindByPredicateAsync(Expression<Func<T, bool>> predicate);
}
Run Code Online (Sandbox Code Playgroud)
我的实现
public class Repository<T> : IRepository<T>
{
private readonly IDocumentClient _documentClient;
private readonly string _databaseId;
private readonly string _collectionId;
public Repository(IDocumentClient documentClient, string databaseId, string collectionId)
{
_documentClient = documentClient;
_databaseId = databaseId;
_collectionId = collectionId;
}
public async Task<T> FindByIdAsync(string id)
{
var documentUri = UriFactory.CreateDocumentUri(_databaseId, _collectionId, id);
try
{
var result = await _documentClient.ReadDocumentAsync<TDocument>(documentUri, new RequestOptions
{
PartitionKey = ParsePartitionKey(documentId)
});
return result.Document;
}
catch (DocumentClientException e)
{
if (e.StatusCode == HttpStatusCode.NotFound)
{
throw new EntityNotFoundException();
}
throw;
}
}
public async Task<T> FindByPredicateAsync(Expression<Func<T, bool>> predicate)
{
//Need to query CosmosDb with partition key here!
}
private PartitionKey ParsePartitionKey(string entityId) => new PartitionKey(entityId.Split(':')[0]);
}
Run Code Online (Sandbox Code Playgroud)
非常感谢任何帮助,谢谢。
我找到了使您的存储库独立于数据库的解决方案(例如,我使用的是 v3 SDK)。刚刚将当前界面分为两部分:
public interface IRepository<T>
{
Task<T> FindItemByDocumentIdAsync(string documentId);
Task<IEnumerable<T>> FindItemsBySqlTextAsync(string sqlQuery);
Task<IEnumerable<T>> FindAll(Expression<Func<T, bool>> predicate = null);
}
public interface IPartitionSetter<T>
{
string PartititonKeyValue { get; }
void SetPartitionKey<T>(string partitionKey);
}//using factory method or DI framework to create same instance for IRepository<T> and IPartitionSetter<T> in a http request
Run Code Online (Sandbox Code Playgroud)
执行:
public class Repository<T> : IRepository<T>, IPartitionSetter<T>
{
//other implementation
public async Task<IEnumerable<T>> FindAll(Expression<Func<T, bool>> predicate = null)
{
var result = new List<T>();
var queryOptions = new QueryRequestOptions
{
MaxConcurrency = -1,
PartitionKey = ParsePartitionKey()
};
IQueryable<T> query = _container.GetItemLinqQueryable<T>(requestOptions: queryOptions);
if (predicate != null)
{
query = query.Where(predicate);
}
var setIterator = query.ToFeedIterator();
while (setIterator.HasMoreResults)
{
var executer = await setIterator.ReadNextAsync();
result.AddRange(executer.Resource);
}
return result;
}
private string _partitionKey;
public string PartititonKeyValue => _partitionKey;
private PartitionKey? ParsePartitionKey()
{
if (_partitionKey == null)
return null;
else if (_partitionKey == string.Empty)
return PartitionKey.None;//for query documents with partition key is empty
else
return new PartitionKey(_partitionKey);
}
public void SetPartitionKey<T>(string partitionKey)
{
_partitionKey = partitionKey;
}
}
Run Code Online (Sandbox Code Playgroud)
您需要在执行查询之前注入IPartitionSetter<T>和调用SetPartitionKey以在此处应用分区键。
| 归档时间: |
|
| 查看次数: |
255 次 |
| 最近记录: |