Я использую Cosmosdb с .net CORE 2.2 и Cosmosdb SQL SDK.По умолчанию cosmosdb назначает каждому документу свойство Id в качестве Guid.Но одного только идентификатора недостаточно для непосредственного чтения документа, вы также должны знать его раздел.Поэтому я создал класс с именем CosmosGuid, который содержит свойство Id (Guid) и свойство PartitionKey (строка).ToString () переопределяется для вызова .ToString ("N") в Guid для удаления штрихов, и он добавляет PartitionKey в конец.У меня проблема в том, что когда я использую CosmosGuid в Linq, сгенерированный SQL будет содержать json-версию CosmosGuid, мне действительно нужно, чтобы она была просто строкой.Я могу вызвать .ToString (), и это приведет к желаемому результату, но я боюсь, что другой разработчик будет использовать мой класс в выражении Linq, и он потерпит неудачу по неизвестной причине.Когда я сохраняю CosmosGuid, я создал собственный конвертер newtonsoft для вызова ToString () при его сохранении и вызова .Parse (string) при чтении.Когда вы сравниваете два Guid в Linq, сгенерированный SQL получается в виде строки, но когда я сравниваю два CosmosGuid, он создает строку json моего класса.Как я могу заставить свой класс вести себя как Guid?
Я уже пытался реализовать все те же интерфейсы, что и Guid.Закрытие, которое я получил, реализовывало IEnumerable, и в GetComparer я возвратил:
new string[] { this.ToString() }.GetEnumerator();
Полученный код был идеальным, но он продолжал помещать мою строку в квадратные скобки [].
вот пример:
SELECT VALUE root FROM root WHERE (root['id'] = ['9a9dbbd5f78143c48b16f780c7ceaa4011'])
Это класс CosmosGuid, я полагаю, что id публикует полный класс, так как он не очень большой и может быть полезен для некоторых.
public class CosmosGuid
{
// This is the unique Id of the entity
public Guid Guid { get; set; }
// This is the partition key where the entity lives
public string PartitionKey { get; set; }
// This is the unique Id of the Document that contains the entity
public Guid? ParentGuid { get; set; }
// This is the PartitionKey of the Document that contains the entity
public string ParentPartitionKey { get; set; }
/// <summary>
/// Parses a CosmosGuid string into a new CosmosGuid
/// </summary>
/// <param name="cosmosGuid"></param>
public CosmosGuid(string cosmosGuid)
{
ParentGuid = null;
ParentPartitionKey = null;
try
{
var parsed = cosmosGuid.Split('-');
// We can accuratly parse the guid from the string by always grabing the first 32 characters.
// The characters after the first 32 are the PartitionKey.
// https://stackoverflow.com/a/4458925
// Guid.NewGuid().ToString("N") => 32 characters (digits only, no dashes)
Guid = Guid.Parse(parsed[0].Substring(0, 32));
PartitionKey = parsed[0].Substring(32, parsed[0].Length - 32);
if (parsed.Length == 2)
{
ParentGuid = Guid.Parse(parsed[1].Substring(0, 32));
ParentPartitionKey = parsed[1].Substring(32, parsed[1].Length - 32);
}
}
catch (Exception ex)
{
throw new Exception("The Id of the document is not a properly formatted CosmosGuid.", ex);
}
}
/// <summary>
/// Generates a new Guid and appends the PartitionKey. This is used for Documents.
/// </summary>
/// <param name="partitionKey"></param>
/// <returns></returns>
public static CosmosGuid NewCosmosGuid(string partitionKey)
{
return new CosmosGuid($"{ShortenGuid(Guid.NewGuid())}{partitionKey}");
}
/// <summary>
/// Generates a new Guid and appends the PartitionKey as well as the Parent Guid and Parent PartitionKey. This is used for Subdocuments.
/// </summary>
/// <param name="parent"></param>
/// <param name="partitionKey"></param>
/// <returns></returns>
public static CosmosGuid NewCosmosGuid(CosmosGuid parent, string partitionKey)
{
return new CosmosGuid($"{ShortenGuid(Guid.NewGuid())}{partitionKey}-{ShortenGuid(parent.Guid)}{parent.PartitionKey}");
}
/// <summary>
/// Returns only the Parent CosmosGuid. If there is no parent the value returned will be null.
/// </summary>
public CosmosGuid Parent
{
get
{
if (ParentGuid != null && ParentPartitionKey != null)
return new CosmosGuid($"{ShortenGuid((Guid)ParentGuid)}{ParentPartitionKey}");
else
return null;
}
}
/// <summary>
/// Parses a CosmosGuid string into a new CosmosGuid.
/// </summary>
/// <param name="cosmosGuid"></param>
/// <returns></returns>
public static CosmosGuid Parse(string cosmosGuid)
{
return new CosmosGuid(cosmosGuid);
}
/// <summary>
/// Generates a CosmosGuid formatted string.
/// </summary>
/// <returns></returns>
public override string ToString()
{
if (ParentGuid == null)
return $"{ShortenGuid(Guid)}{PartitionKey}";
else
return $"{ShortenGuid(Guid)}{PartitionKey}-{ShortenGuid((Guid)ParentGuid)}{ParentPartitionKey}";
}
/// <summary>
/// Removes the dashes from a Guid
/// </summary>
/// <param name="guid"></param>
/// <returns></returns>
private static string ShortenGuid(Guid guid)
{
// Just remove dashes from the guid to shorten it some.
// More can be done here if you wish but make sure the guid uniqueness isnt compromised.
return guid.ToString("N");
}
public static bool operator ==(CosmosGuid obj1, CosmosGuid obj2)
{
return obj1?.ToString() == obj2?.ToString();
}
public static bool operator !=(CosmosGuid obj1, CosmosGuid obj2)
{
return obj1?.ToString() != obj2?.ToString();
}
}
Если разработчик, где использовать CosmosGuid, не сможет работать, потому что сгенерированный SQL является версией Json класса.(идентификатор также является CosmosGuid):
var cosmosGuid = CosmosGuid.Parse("6bec688a0aca477c8175c09162b7a9b411");
var result = await Client.CreateDocumentQuery<MyClass>(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), options)
.Where(x => x.Id == cosmosGuid)
.AsDocumentQuery();
Это сгенерированный sql
SELECT VALUE root FROM root WHERE (root['id'] = {'Guid':'6bec688a-0aca-477c-8175-c09162b7a9b4','PartitionKey':'11','ParentGuid':null,'ParentPartitionKey':null,'Parent':null})
Вместо этого разработчик должен вызывать .ToString () везде в коде.
var cosmosGuid = CosmosGuid.Parse("6bec688a0aca477c8175c09162b7a9b411");
var result = await Client.CreateDocumentQuery<MyClass>(UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId), options)
.Where(x => x.Id.ToString() == cosmosGuid.ToString())
.AsDocumentQuery();
Это сгенерированный Sql
SELECT VALUE root FROM root WHERE (root['id'] = '6bec688a0aca477c8175c09162b7a9b411')
Если я удаляю CosmosGuid и возвращаюсь к использованию только идентификатора Guid в качестве свойства Id, SQL, сгенерированный Cosmosdb SDK, работает нормально.Как я могу заставить свой класс вести себя как .net Guid при использовании в Linq?