Amazon Dynamo DB持久性ORM

时间:2017-04-19 13:15:54

标签: c# amazon-web-services amazon-dynamodb aws-sdk data-access-layer

我正在尝试为AWS DynamoDB创建一个通用的包装器库(C#/ .NET),它可以充当DAL(数据访问层)。使用此库的应用程序将不会与AWS库紧密耦合,因为以后可能会对其进行更改。

从包装类中公开的方法的结构是 的 InsertItem< T>(对象) UpdateItem< T>(对象) DeleteItem< T>(ID /对象) 下, 的 列表< T> GetAll() T GetByParameter< T>(Id)的

我发现使用AWSSDK有三种方法可以使用AWS DynamoDB服务。

方法(1): 低级访问 - 将模型转换为aws hashmap输入结构并调用getItem()/ putItem()。

方法(2): 使用文档进行高级访问 - 将模型转换为文档模型并将文档对象传递给aws。

方法(3): 使用持久性进行高级访问 - 在模型中使用属性DynamoDBTable将模型映射到dynamoDb表并使用linq操作来获取/更新表。

方法(1)& (2),我发现很难将模型映射到dynamoDB表。在方法(3)中,我看到我需要在应用程序的模型类中包含DynamoDB属性,这将使它紧密耦合。

在这种情况下,有没有办法在运行时创建映射,还是有其他方法?

我还想过我是否可以json序列化/反序列化模型并插入dynamoDB(在这种情况下,只有2列 - 任何模型的id,json主体)。

如果我错了或遗失了某些内容,请纠正我。

2 个答案:

答案 0 :(得分:2)

以下是我前进的解决方案,减去一些无关的细节。最大的挑战是读取任意类型的数据,因为您不能轻易地从JSON中分辨出来。

在我的解决方案中,选择要编写的类型的消费应用程序也知道如何识别在读取时要反序列化的类型。这是必要的,因为我需要返回多个不同类型的日志,因此将JSON返回给消费者并让他们处理它更有意义。如果要在DAL中包含此项,可以在数据库中添加“类型”列并使用反射进行转换,但我认为您在一次调用中仍然存在返回多种类型数据的问题。

我们提供的用于消费的界面具有读/写方法(您可以添加您需要的任何其他内容)。请注意,写入允许指定T,但如上所述,读取需要调用者反序列化。

public interface IDataAccess
{
    Task WriteAsync<T>(Log<T> log) where T : class, new();
    Task<IEnumerable<LogDb>> GetLogsAsync(long id);
}

LogDb类包含持久性属性:

[DynamoDBTable("TableName")]
public class LogDb
{
    [DynamoDBHashKey("Id")]
    public long Id{ get; set; }

    [DynamoDBProperty(AttributeName = "Data", Converter = typeof(JsonStringConverter))]
    public string DataJson { get; set; }
}

通用Log&lt; T&gt;用于强类型写作的类。在IDataAccess实现中调用ToDb()方法以实际写入DB。接收LogDb的构造函数将由已确定用于反序列化的适当类型的消费应用程序使用:

public class Log<T>
    where T : class, new()
{
    public Log() { }

    public Log(LogDb logDb)
    {
        Data = licensingLogDb.OldDataJson.Deserialize<T>();
        Id = licensingLogDb.Id;
    }

    public long Id { get; set; }
    public T Data { get; set; }

    public LogDb ToDb()
    {
        string dataJson = Data.Serialize();
        return new LogDb
        {
            DataJson = dataJson,
            Id = Id
        };
    }
}

LogDb上的属性中使用的JsonStringConverter将DataJson属性中的JSON字符串转换为DynamoDB文档和从DynamoDB文档转换:

public class JsonStringConverter : IPropertyConverter
{
    public DynamoDBEntry ToEntry(object value)
    {
        string json = value as string;
        return !String.IsNullOrEmpty(json)
            ? Document.FromJson(json)
            : null;
    }

    public object FromEntry(DynamoDBEntry entry)
    {
        var document = entry.AsDocument();
        return document.ToJson();
    }
}

一个帮助器类提供了Serialize和Deserialize扩展,它们使用JSON.NET的JsonConvert.Serialize / Deserialize,但是使用了空检查:

public static class JsonHelper
{
    public static string Serialize(this object value)
    {
        return value != null 
            ? JsonConvert.SerializeObject(value) 
            : String.Empty;
    }

    public static T Deserialize<T>(this string json)
        where T : class, new()
    {
        return !String.IsNullOrWhiteSpace(json) 
            ? JsonConvert.DeserializeObject<T>(json)
            : null;
    }
}

答案 1 :(得分:0)

通用方法将Dynamo表转换为c#类作为扩展函数。

public static List<T> ToMap<T>(this List<Document> item)
    {
        List<T> model = (List<T>)Activator.CreateInstance(typeof(List<T>));
        foreach (Document doc in item)
        {
            T m = (T)Activator.CreateInstance(typeof(T));
            var propTypes = m.GetType();
            foreach (var attribute in doc.GetAttributeNames())
            {
                var property = doc[attribute];
                if (property is Primitive)
                {
                    var properties = propTypes.GetProperty(attribute);
                    if (properties != null)
                    {
                        var value = (Primitive)property;
                        if (value.Type == DynamoDBEntryType.String)
                        {
                            properties.SetValue(m, Convert.ToString(value.AsPrimitive().Value));
                        }
                        else if (value.Type == DynamoDBEntryType.Numeric)
                        {
                            properties.SetValue(m, Convert.ToInt32(value.AsPrimitive().Value));
                        }
                    }
                }
                else if (property is DynamoDBBool)
                {
                    var booleanProperty = propTypes.GetProperty(attribute);
                    if (booleanProperty != null)
                        booleanProperty.SetValue(m, property.AsBoolean());
                }
            }
            model.Add(m);
        }
        return model;
    }