从 Ardalis CosmosDB 规范中的规范返回基类

问题描述 投票:0回答:1

在 CosmosDB 集合中,我有两种类型的实体,它们继承自一个基类。 我想从规范返回基类,并能够将该基类对象转换为具体对象。 我不使用 EF,我使用 CosmosDB SDK。 我想要这样的东西:

class BaseClass
{
   string Id;
}


class ClassA : BaseClass
{
string Status;
}

class ClassB : BaseClass
{
string Amount;
}

public class MyScpec : Specification<BaseClass>
{
    public MyScpec () 

{

Query.Select(x =>
(x is ClassA
             ? new ClassA { Id = x.Id, Status = x.Status }

: new ClassB { Id = x.Id, Amount = x.Amount}
));

}
}

进一步在代码中我希望能够这样做:

var list = _repository.List(new MySpec());

foreach(var item in list)
{
    if(item is ClassA)    { ...}

}

我尝试返回 BaseClass:

Query.Select(new BaseClass(){...})

但是我无法将其转换为子类。

另外,我尝试做类似 EF 中的事情,当我们可以配置实体时

builder.HasBaseType<BaseClass>();

但据我所知,CosmosDB SDK 中不存在这种可能性。

.net azure-cosmosdb ardalis-specification
1个回答
0
投票

我找到了解决方案。你需要有一个自定义的 json 转换器

public abstract class AbstractJsonConverter<T> : JsonConverter
{
    protected abstract T? Create(Type objectType, JObject jObject);

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }
        
        var jObject = JObject.Load(reader);
        if (jObject.Type == JTokenType.Null)
        {
            return null;
        }
        
        var target = Create(objectType, jObject);
        serializer.Populate(jObject.CreateReader(), target!);

        return target;
    }

    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

public class DataModelConverter : AbstractJsonConverter<DataModelBase>
{
    protected override DataModelBase Create(Type objectType, JObject jObject)
    {
        switch (jObject[nameof(DataModel.id)]!.Value<string>())
        {
            case var id when id!.StartsWith("typeOne"):
                return new DataModelOne();
            case var id when id!.StartsWith("typeTwo"):
                return new DataModelTwo();
            default:
                throw new ArgumentException();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.