Azure cosmosdb 使用.Net SDK Microsoft.Azure.Cosmos查询Cosmos DB以获取不同派生类型的列表
我们有一个接口和一个具有多个派生类型的基类Azure cosmosdb 使用.Net SDK Microsoft.Azure.Cosmos查询Cosmos DB以获取不同派生类型的列表,azure-cosmosdb,azure-cosmosdb-sqlapi,Azure Cosmosdb,Azure Cosmosdb Sqlapi,我们有一个接口和一个具有多个派生类型的基类 public interface IEvent { [JsonProperty("id")] public string Id { get; set; } string Type { get; } } public abstract class EventBase: IEvent { public string Id { get; set; } public abstract string
public interface IEvent
{
[JsonProperty("id")]
public string Id { get; set; }
string Type { get; }
}
public abstract class EventBase: IEvent
{
public string Id { get; set; }
public abstract string Type { get; }
}
public class UserCreated : EventBase
{
public override string Type { get; } = typeof(UserCreated).AssemblyQualifiedName;
}
public class UserUpdated : EventBase
{
public override string Type { get; } = typeof(UserUpdated).AssemblyQualifiedName;
}
我们正在使用.Net SDKMicrosoft.Azure.Cosmos
的v3将这些不同派生类型的事件存储在Cosmos DB的同一容器中。然后,我们希望读取所有事件,并将它们反序列化为正确的类型
public class CosmosDbTests
{
[Fact]
public async Task TestFetchingDerivedTypes()
{
var endpoint = "";
var authKey = "";
var databaseId ="";
var containerId="";
var client = new CosmosClient(endpoint, authKey);
var container = client.GetContainer(databaseId, containerId);
await container.CreateItemAsync(new UserCreated{ Id = Guid.NewGuid().ToString() });
await container.CreateItemAsync(new UserUpdated{ Id = Guid.NewGuid().ToString() });
var queryable = container.GetItemLinqQueryable<IEvent>();
var query = queryable.ToFeedIterator();
var list = new List<IEvent>();
while (query.HasMoreResults)
{
list.AddRange(await query.ReadNextAsync());
}
Assert.NotEmpty(list);
}
}
公共类COSMOSDBTEST
{
[事实]
公共异步任务TestFetchingDerivedTypes()
{
var endpoint=“”;
var authKey=“”;
var databaseId=“”;
var containerId=“”;
var client=new-CosmosClient(端点,authKey);
var container=client.GetContainer(databaseId,containerId);
wait container.CreateItemAsync(新用户创建的{Id=Guid.NewGuid().ToString()});
wait container.CreateItemAsync(新用户已更新{Id=Guid.NewGuid().ToString()});
var queryable=container.GetItemLinqQueryable();
var query=queryable.ToFeedIterator();
var list=新列表();
while(query.HasMoreResults)
{
AddRange(wait query.ReadNextAsync());
}
Assert.NotEmpty(列表);
}
}
似乎没有任何选项告诉GetItemLinqQueryable
如何处理类型。是否有其他方法或途径支持一个查询中的多个派生类型
如果有帮助的话,可以将事件放入某种包装器实体中,但是它们不允许作为序列化的sting存储在属性中。Stephen的评论为我指明了正确的方向,在这个博客的帮助下,我最终得到了一个类似于以下示例的解决方案:我们有一个自定义的
CosmosSerializer
,它使用了一个自定义的JsonConverter
读取类型属性
public interface IEvent
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("$type")]
string Type { get; }
}
public abstract class EventBase: IEvent
{
public string Id { get; set; }
public string Type => GetType().AssemblyQualifiedName;
}
public class UserCreated : EventBase
{
}
public class UserUpdated : EventBase
{
}
public class EventJsonConverter : JsonConverter
{
// This converter handles only deserialization, not serialization.
public override bool CanRead => true;
public override bool CanWrite => false;
public override bool CanConvert(Type objectType)
{
// Only if the target type is the abstract base class
return objectType == typeof(IEvent);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// First, just read the JSON as a JObject
var obj = JObject.Load(reader);
// Then look at the $type property:
var typeName = obj["$type"]?.Value<string>();
return typeName == null ? null : obj.ToObject(Type.GetType(typeName), serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException("This converter handles only deserialization, not serialization.");
}
}
EventJsonConverter
读取Type
属性
public interface IEvent
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("$type")]
string Type { get; }
}
public abstract class EventBase: IEvent
{
public string Id { get; set; }
public string Type => GetType().AssemblyQualifiedName;
}
public class UserCreated : EventBase
{
}
public class UserUpdated : EventBase
{
}
public class EventJsonConverter : JsonConverter
{
// This converter handles only deserialization, not serialization.
public override bool CanRead => true;
public override bool CanWrite => false;
public override bool CanConvert(Type objectType)
{
// Only if the target type is the abstract base class
return objectType == typeof(IEvent);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// First, just read the JSON as a JObject
var obj = JObject.Load(reader);
// Then look at the $type property:
var typeName = obj["$type"]?.Value<string>();
return typeName == null ? null : obj.ToObject(Type.GetType(typeName), serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException("This converter handles only deserialization, not serialization.");
}
}
CosmosClient现在是使用我们自己的NewtonSoftJSONCSOMassessiver
和EventJsonConverter
创建的
public class CosmosDbTests
{
[Fact]
public async Task TestFetchingDerivedTypes()
{
var endpoint = "";
var authKey = "";
var databaseId ="";
var containerId="";
var client = new CosmosClient(endpoint, authKey, new CosmosClientOptions
{
Serializer = new NewtonsoftJsonCosmosSerializer(new JsonSerializerSettings
{
Converters = { new EventJsonConverter() }
})
});
var container = client.GetContainer(databaseId, containerId);
await container.CreateItemAsync(new UserCreated{ Id = Guid.NewGuid().ToString() });
await container.CreateItemAsync(new UserUpdated{ Id = Guid.NewGuid().ToString() });
var queryable = container.GetItemLinqQueryable<IEvent>();
var query = queryable.ToFeedIterator();
var list = new List<IEvent>();
while (query.HasMoreResults)
{
list.AddRange(await query.ReadNextAsync());
}
Assert.NotEmpty(list);
}
}
公共类COSMOSDBTEST
{
[事实]
公共异步任务TestFetchingDerivedTypes()
{
var endpoint=“”;
var authKey=“”;
var databaseId=“”;
var containerId=“”;
var client=new-CosmosClient(端点、authKey、new-CosmosClientOptions
{
Serializer=新的NewtonSoftJSONCSOMasserializer(新的JsonSerializerSettings
{
转换器={new EventJsonConverter()}
})
});
var container=client.GetContainer(databaseId,containerId);
wait container.CreateItemAsync(新用户创建的{Id=Guid.NewGuid().ToString()});
wait container.CreateItemAsync(新用户已更新{Id=Guid.NewGuid().ToString()});
var queryable=container.GetItemLinqQueryable();
var query=queryable.ToFeedIterator();
var list=新列表();
while(query.HasMoreResults)
{
AddRange(wait query.ReadNextAsync());
}
Assert.NotEmpty(列表);
}
}
您是否使用定制的宇宙采集器
?没有,但您的问题帮助我找到了这个博客,帮助我找到了解决方案。