簡體   English   中英

在Linq中使用時,如何使我的班級扮演Guid的角色?

[英]How can I make my class act like a Guid when used in Linq?

我將Cosmosdb與.net CORE 2.2和Cosmosdb SQL SDK結合使用。 默認情況下,cosmosdb將為每個文檔分配“ Id”屬性作為Guid。 但是僅憑ID不足以直接讀取文檔,還必須知道其分區。 因此,我創建了一個名為CosmosGuid的類,其中包含一個Id屬性(Guid)和一個PartitionKey屬性(字符串)。 ToString()被重寫以在Guid上調用.ToString(“ N”)來刪除破折號,並將PartitionKey附加到末尾。 我遇到的問題是,當我在Linq中使用CosmosGuid時,生成的SQL將包含CosmosGuid的json版本,我真的需要它只是一個字符串。 我可以調用.ToString(),這將產生所需的結果,但是恐怕其他開發人員會在Linq表達式中使用我的類,並且由於未知原因它會失敗。 當我保存CosmosGuid時,我創建了一個自定義的newtonsoft轉換器,以在保存時調用ToString()並在讀取時調用.Parse(string)。 當您在Linq中比較兩個Guid時,生成的SQL出現在一個字符串中,但是當我比較兩個CosmosGuid時,它會創建我的類的json字符串。 我怎樣才能使我的班級表現得像個向導?

我已經嘗試實現與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版本。 (該ID也是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屬性,則Cosmosdb SDK生成的SQL可以正常工作。 在Linq中使用時,如何使我的班級像.net Guid一樣工作?

對於LINQ to對象:

您可以在CosmosGuid類上重載==運算符,請參見operator keyword

另外,您可以實現IEquatable<Guid>並改用.Equals()

public class CosmosGuid : IEquatable<Guid>
{

  ....

  public bool Equals(Guid other) {
    return this.Guid == other;
  }
}
.Where(x => cosmosGuid.Equals(x.Id))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM