Azure|EF Core 6.0 Azure Cosmos DB Provider的新特性( 二 )


publicclassTag { publicintId { get; set; }publicstringText { get; set; }} 然后标签类被引用:
publicICollection<Tag> Tags { get; set; }接着原始类型被提升为复杂类型并存储在一个单独的表中 。 另一种方法是将标签组合成一个字段 , 该字段包含一个以逗号分隔的列表 。 这种方法需要一个值转换器将列表编组到字段中以进行更新 , 并将字段分解为列表以进行读取 。 这也使得回答诸如“有多少贴子有X标签?”这样的问题变得困难 。 在使用EF Core 5时 , 我选择了单列方法 。 我在写入时将列表序列化为JSON , 在读取时将其反序列化 。 这是序列化代码:
privatestaticstringToJson<T> ( T item) => JsonSerializer.Serialize(item);privatestaticT FromJson<T> ( stringjson ) => JsonSerializer.Deserialize<T>(json);【Azure|EF Core 6.0 Azure Cosmos DB Provider的新特性】我配置EF Core来进行转换:
docModel.Property( d=> d.Tags).HasConversion( t=> ToJson(t),t=> FromJson<List< string>>(t));结果文件看起来是这样的:
{ "tags": "[\"one\ ", \"two\ ", \"three\ "]" } 在EF Core 6.0中 , 我只是删除了代码然后利用原始类型的内置处理方式 , 结果是这样的文档:
{ "tags": ["one","two","three" ] } 这导致了schema发现改变 , 但是Azure Cosmos DB没有问题处理 。 另一方面 , 当使用标签作为数组的当前模型遇到使用标签作为字段的旧记录时 , c#代码将抛出异常 。 当EF Core没有NoSQL迁移的概念时 , 我们如何处理这个问题?
Raw SQL
一个很常见的请求是允许开发人员为数据访问编写自己的SQL 。 这正是我处理代码迁移所需要的特性 。 要使Raw SQL工作 , 它必须投射到一个现有的模型 。 它是实体的DbSet<T>的扩展 。 在我的例子中 , 它支持就地迁移 。 在更新代码之后 , 尝试加载文档将会失败 。 文档只有一个字符串属性用于“tag” , 但c#模型是一个数组 , 因此JSON序列化会抛出一个异常 。 为了解决这个问题 , 我使用了Azure Cosmos DB的一个内置特性 , 它将 字符串解析为数组 。 使用查询 , 我将实体投影到匹配当前schema的文档中 , 然后将其保存回来 。 这是迁移代码:
vardocs = awaitDocuments.FromSqlRaw("select c.id, c.Uid, c.AuthorAlias, c.Deion, c.Html, c.Markdown, c.PublishDate, c.Title, STRINGTOARRAY(c.Tags) as Tags from c").ToListAsync;foreach( vardoc indocs){ Entry(doc).State = EntityState.Modified; } 这个特性使开发人员能够创建LINQ provider可能不支持的复杂查询 。

推荐阅读