从DocumentDB查询POCO实体
我正在关注Microsoft测试DocumentDB的这篇博客文章 。
我创建了一个集合,并在我的应用程序中通过不同的POCO类插入了2个文档。 它创建了文档,但我无法将它们过滤回各自的POCO类。 我意识到我正在查询所有集合,因此它显然正在检索存储在该集合中的所有文档。
在查询时区分文档的最佳方法是什么,以便我可以按类型单独查询它们?
我可以在文档中添加一个类型字段,并且可以通过WHERE type="user"
获取,但我不确定我不能用users
是文档类型的SELECT * FROM users
(如果在DocumentDB中有这样的东西),不是一个集合。
以下是我创建文档的方法:
var user1= new User() { UserTypeId = 0, UserName = "user1@hotmail.com", Password = "12345", PasswordSalt = "saltyPassword", UserStatusId = 1, ProfilePhotoKey = "KJSY" }; await DocumentDBRepository.CreateItemAsync(user1); var client = new Client() { ClientName = "client1", Secret = "rxPBsIVYya2Jg2ZHPNG8gL0P36TnutiBehvEFgk938M=", Title = "Administration Front End Application", ApplicationTypeId = 0, Active = false, RefreshTokenLifeTime = 60, AllowedOrigin = "http://localhost:8080", AllowedRoles = "admin" }; await DocumentDBRepository.CreateItemAsync(client);
文档Db存储库类
public static class DocumentDBRepository { //Use the Database if it exists, if not create a new Database private static Database ReadOrCreateDatabase() { var db = Client.CreateDatabaseQuery() .Where(d => d.Id == DatabaseId) .AsEnumerable() .FirstOrDefault(); if (db == null) { db = Client.CreateDatabaseAsync(new Database { Id = DatabaseId }).Result; } return db; } //Use the DocumentCollection if it exists, if not create a new Collection private static DocumentCollection ReadOrCreateCollection(string databaseLink) { var col = Client.CreateDocumentCollectionQuery(databaseLink) .Where(c => c.Id == CollectionId) .AsEnumerable() .FirstOrDefault(); if (col == null) { var collectionSpec = new DocumentCollection { Id = CollectionId }; var requestOptions = new RequestOptions { OfferType = "S1" }; col = Client.CreateDocumentCollectionAsync(databaseLink, collectionSpec, requestOptions).Result; } return col; } //Expose the "database" value from configuration as a property for internal use private static string databaseId; private static String DatabaseId { get { if (string.IsNullOrEmpty(databaseId)) { databaseId = ConfigurationManager.AppSettings["database"]; } return databaseId; } } //Expose the "collection" value from configuration as a property for internal use private static string collectionId; private static String CollectionId { get { if (string.IsNullOrEmpty(collectionId)) { collectionId = ConfigurationManager.AppSettings["collection"]; } return collectionId; } } //Use the ReadOrCreateDatabase function to get a reference to the database. private static Database database; private static Database Database { get { if (database == null) { database = ReadOrCreateDatabase(); } return database; } } //Use the ReadOrCreateCollection function to get a reference to the collection. private static DocumentCollection collection; private static DocumentCollection Collection { get { if (collection == null) { collection = ReadOrCreateCollection(Database.SelfLink); } return collection; } } //This property establishes a new connection to DocumentDB the first time it is used, //and then reuses this instance for the duration of the application avoiding the //overhead of instantiating a new instance of DocumentClient with each request private static DocumentClient client; private static DocumentClient Client { get { // change policy to ConnectionMode: Direct and ConnectionProtocol: TCP on publishing to AZURE if (client == null) { string endpoint = ConfigurationManager.AppSettings["endpoint"]; string authKey = ConfigurationManager.AppSettings["authKey"]; Uri endpointUri = new Uri(endpoint); client = new DocumentClient(endpointUri, authKey); } return client; } } /* QUERY HELPERS */ public static IEnumerable GetAllItems() { return Client.CreateDocumentQuery(Collection.DocumentsLink) .AsEnumerable(); } public static IEnumerable GetItems(Expression<Func> predicate) { return Client.CreateDocumentQuery(Collection.DocumentsLink) .Where(predicate) .AsEnumerable(); } public static async Task CreateItemAsync(T item) { return await Client.CreateDocumentAsync(Collection.SelfLink, item); } public static T GetItem(Expression<Func> predicate) { return Client.CreateDocumentQuery(Collection.DocumentsLink) .Where(predicate) .AsEnumerable() .FirstOrDefault(); } public static async Task UpdateItemAsync(string id, T item) { Document doc = GetDocument(id); return await Client.ReplaceDocumentAsync(doc.SelfLink, item); } private static Document GetDocument(string id) { return Client.CreateDocumentQuery(Collection.DocumentsLink) .Where(d => d.Id == id) .AsEnumerable() .FirstOrDefault(); } }
我想得到:
var q = DocumentDBRepository.GetAllItems().ToList(); var t = DocumentDBRepository.GetAllItems().ToList();
q应仅包含由其创建的用户文档
await DocumentDBRepository.CreateItemAsync(user1);
并且t应该只包含由其创建的客户端文档
await DocumentDBRepository.CreateItemAsync(client1);
由于DocumentDB没有每个文档的任何内置type
元数据,因此在将异构文档存储在同一个集合中时,您需要添加一个(例如您建议的type
属性或任何其他区别属性)并使用它在WHERE
子句中。 您为此属性命名的内容以及您在其中存储的值与您的集合名称无关。
关于SELECT * from users WHERE type='user'
的SELECT * from users WHERE type='user'
具体示例, SELECT * from users WHERE type='user'
可以工作,但SELECT * from users
将返回所有文档,无论类型如何。
默认情况下,所有属性都被编入索引,包括新形成的type
属性,这使您可以有效地执行WHERE子句过滤,而无需进行集合扫描。
重新思考如何区分集合中的文档类型……
我开始使用Type属性,它只是简单地获取了iternal类型名称(基类“实体”中的getter)
我的期望是我们在查询时会使用Type属性。
然而,我们很快转而使用类型值作为每个实体类型的分区键的后缀(“pkey”再次从Entityinheritance – 因为我们通过将所有内容存储在一个集合中而不得不使用一个分区键来节省$所有文档类型的属性名称)
如果类型名称是“Thing”并且只有一个那么“id”是“Thing”而pkey是“-identifier- | Thing”
如果-identifier-标识一个组,那么多个记录将具有“id”的唯一值,并且范围查询很容易简单地查询pkey和迭代。
类型名称应为pkey后缀,以确保不减少读写分配
id和pkey也很好地作为一个独特的索引 – 当你发现自己缺少关系SQL时,这是一个受欢迎的function:-)
关于POCO – 我正在认真考虑放弃直接的POCO操作,因为我们在使用camelcase json序列化和sql查询时遇到了很多麻烦。 我们最终无法信任全局camelcase设置 – 而是在所有字段上详尽地设置json名称。
我正在考虑使用内部POCO,它持续存在于文档中。 POCO getter和setter通过getAttributeValue()和setAttributeValue()引用Document实例。 然后,我们可以通过DI将持久层交换为其他内容
Document类有很多有趣的方法,我们还没有考虑过。
将POCO与持久性脱钩也是可取的。
只是对你的一些想法。
- 从c#中获取来自Azure的keyVault的秘密
- 从Azure函数中的local.settings.json中读取自定义设置
- Azure Notification Hubs templateName的用法
- 已发布的C#Bot在一段时间后会遇到内部服务器错误
- 访问Azure Service Fabric状态服务状态
- .net-core-2.0 azure app service 502.5错误
- 支持HTTP和HTTPS Web.Config WCF服务
- 我可以绕过MVC应用程序内的WebAPI控制器的组织身份validation吗?
- 使用ASP.NET Web API并排进行基本和表单身份validation