这是一个非常尴尬的错误,我花了一段时间才把它处理到这几行代码.完整的代码可以被抓取as fiddle,但你必须提供你的Cosmos URL和密钥才能运行.问题是,我们定义了一个public static readonly Author Unknown
字段,而类Author
是一个记录,其定义如下:
public record Author(
[Required] string Id,
[Required] string DisplayName,
[Required] string MailAddress)
{
// This is going to be mutated! 👇🏻
public static readonly Author Unknown = Create(nameof(Unknown));
public static Author Create(string name)
{
return new Author(
name.ToLowerInvariant(),
name,
$"{name}@test.internal");
}
}
在下一步中,我们有一个类,我们希望从/向Azure Cosmos数据库读取/写入,该类可以简单到
public class DocumentBase
{
[Newtonsoft.Json.JsonProperty("id")]
public Guid Id { get; set; } = default!;
public string PartitionKey { get; set; } = "PartitionKey";
// Apply static readonly record in default ctor of class
public Author Modified { get; set; } = Author.Unknown;
}
我们设置中的下一件事是一个Cosmos DB容器,我们可以使用它来读/写我们的文档:
private static async Task<Container> CreateContainer()
{
var endPoint = "https://{yourCosmosDatabase}.documents.azure.com:443/";
var key = "{yourCosmosKey}";
var client = new CosmosClient(endPoint, key);
var containerId = $"{DateTime.UtcNow:s}-{Guid.NewGuid()}";
var partitionKey = "/PartitionKey";
var database = client.GetDatabase("Testing");
var response = await database.CreateContainerAsync(new ContainerProperties
{
Id = containerId,
PartitionKeyPath = partitionKey,
DefaultTimeToLive = -1
});
return response.Container;
}
以下是更改Author.Unknown
中的值的代码:
public static async Task Main()
{
// Create a container to access Cosmos
var container = await CreateContainer();
// Create an instance with individual values
var defaultValue = new DocumentBase
{
Id = Guid.NewGuid(),
Modified = Author.Create("Modified"),
};
// Create a copy of the static readonly record for comparison
var copyOfUnknown = Author.Unknown with { };
// Check if the copy and the original values are equal
// with value comparison thanks to the help of record
Author.Unknown.ShouldBe(copyOfUnknown);
// Let Cosmos write that instance down to the database
// and read back the fresh created value.
// It will be returned by the function, but we ignore it.
await container.CreateItemAsync(defaultValue, new PartitionKey(defaultValue.PartitionKey));
// Make another comparison that fails, because in Author.Unknown
// you find now Author.Create("Modified")!
Author.Unknown.ShouldBe(copyOfUnknown);
}
那么这里到底是怎么回事?
我们有一个存储record
的public static readonly
字段,在对来自宇宙的响应进行反序列化后,那个字段发生了Mutations ?这怎么可能呢?
要解决这个问题,我们有多个选项,也许可以显示遇到这个问题所需的配料:
- 将readonly字段替换为属性getter,该属性getter在每次被调用时返回一个新实例.
- Do not set
DocumentBase
的默认ctor中的Modified
属性 -
Set使用复制ctor
= Author.Unknown with { };
在默认ctorDocumentBase
中设置Modified
属性
然而,这种行为确实出乎意料,如果有人能解释这种行为,我会很高兴.顺便说一下,我们使用了最新的NuGet软件包Microsoft.Azure.Cosmos 3.38.1.