如何通过可空字段查询 Azure Table 存储?
How to query Azure Table storage by nullable fields?
我有 table 个可以为 null 的字段:
public int? Order {get; set;}
public DateTime? StartDate {get; set;}
public DateTime? EndDate {get; set;}
public string Text {get; set;}
所有这些字段都可以是 NULL 值
查询记录时出现问题
其中 Order、StartDate、EndDate 和 Text 不为 NULL 或
其中 Order、StartDate 和 Text 不为空但 EndDate 为空或
其中 Order 和 Text 不为空,但 StartDate 和 EndDate 为空
Order.HasValue && StartDate.HasValue && EndDate.HasValue && !string.IsNullOrEmpty(Text) || Order.HasValue && StartDate.HasValue && !EndDate.HasValue && !string.IsNullOrEmpty(Text) || Order.HasValue && !StartDate.HasValue && !EndDate.HasValue && !string.IsNullOrEmpty(Text)
使用此类查询时出现错误或 400(错误请求)或不支持的运算符(不支持 isnullorempty)
根据这个答案 不可能查询 NULL 值...
据我所知,您无法将 DateTime 设置为 null 或空。
所以,我建议您可以将日期时间存储为字符串,当您想要映射到视图模型时,您可以将字符串转换为 DateTime。
插入实体时,将 DateTime 转换为字符串:
TableBatchOperation batchOperation = new TableBatchOperation();
DateTime dts = DateTime.Now;
DateTime dte = DateTime.UtcNow;
// Create a customer entity and add it to the table.
CustomerEntity customer1 = new CustomerEntity("Smith", "Jeff");
customer1.Order = 1;
customer1.StartDate = Convert.ToString(dts);
customer1.EndDate = Convert.ToString(dte);
customer1.Text = "text1";
// Create another customer entity and add it to the table.
CustomerEntity customer2 = new CustomerEntity("Smith", "Ben");
customer2.Order = 2;
customer2.StartDate = Convert.ToString(dts);
customer2.EndDate = "";
customer2.Text = "text2";
CustomerEntity customer3 = new CustomerEntity("Smith", "Cai");
customer3.Order = 3;
customer3.StartDate = "";
customer3.EndDate = "";
customer3.Text = "text3";
// Add both customer entities to the batch insert operation.
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
batchOperation.Insert(customer3);
// Execute the batch operation.
table.ExecuteBatch(batchOperation);
实体如下:
public class CustomerEntity : TableEntity
{
public CustomerEntity(string lastName, string firstName)
{
this.PartitionKey = lastName;
this.RowKey = firstName;
}
public CustomerEntity() { }
public int? Order { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public string Text { get; set; }
public DateTime? ConvertTime(string dateStr)
{
if (string.IsNullOrEmpty(dateStr))
return null;
DateTime dt;
var convert=DateTime.TryParse(dateStr, out dt);
return dt;
}
}
显示或映射到模型时,可以使用ConvertTime方法判断列是否为空ConvertTime(entity.StartDate)
。 如果为空,则显示为空,如果有值,则将字符串转换为日期时间。
string orderhasvalue = TableQuery.GenerateFilterCondition("Order", QueryComparisons.NotEqual, null);
string startdatehasvalue = TableQuery.GenerateFilterCondition("StartDate", QueryComparisons.NotEqual, null);
string enddatehasvalue = TableQuery.GenerateFilterCondition("EndDate", QueryComparisons.NotEqual, null);
string texthasvalue = TableQuery.GenerateFilterCondition("Text", QueryComparisons.NotEqual, null);
string startdatenothasvalue = TableQuery.GenerateFilterCondition("StartDate", QueryComparisons.Equal, null);
string enddatenothasvalue = TableQuery.GenerateFilterCondition("EndDate", QueryComparisons.Equal, null);
TableQuery<CustomerEntity> query1 = new TableQuery<CustomerEntity>().Where(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
orderhasvalue, TableOperators.And, startdatehasvalue),
TableOperators.And, enddatehasvalue),
TableOperators.And, texthasvalue)
);
TableQuery<CustomerEntity> query2 = new TableQuery<CustomerEntity>().Where(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
orderhasvalue, TableOperators.And, startdatehasvalue),
TableOperators.And, enddatenothasvalue),
TableOperators.And, texthasvalue)
);
TableQuery<CustomerEntity> query3 = new TableQuery<CustomerEntity>().Where(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
orderhasvalue, TableOperators.And, startdatenothasvalue),
TableOperators.And, enddatenothasvalue),
TableOperators.And, texthasvalue)
);
// Print the fields for each customer.
foreach (CustomerEntity entity in table.ExecuteQuery(query2))
{
Console.WriteLine("{0}, {1}\t{2}\t{3}\t{4}\t{5}", entity.PartitionKey, entity.RowKey,
entity.Order, entity.ConvertTime(entity.StartDate), entity.ConvertTime(entity.EndDate), entity.Text);
}
您不能在 Azure Table 存储中查询空值,string
也不例外。写入 Azure table 时,具有空值的 属性 不会以表格形式存在,因此引用该 属性 的查询将始终 return 出乎意料的结果。作为解决方法,您可以做的是提供默认的非空值并查询这些值。如果 string
将值 ""
分配给 string
,则允许您查询 string.Empty(不是 null
,因为 ""
不是 null
).对于 DateTime?
类型,同样的解决方法但不是 ""
,您可以分配一个模糊的默认值,即。 DateTime.MinValue
(或MaxValue
)如果属性的实际值为null,否则您可以将其转换为string
并将空字符串指定为默认值但您需要支付来回转换的价格,所以我个人更愿意尽可能避免这种情况。
您可以在 Azure table 存储上查询字符串数据类型字段的空过滤器。
OData 查询 = 不是(Id ne '')
使用上面的 Odata 查询,您可以仅在字符串数据类型字段上过滤空数据。
您可以在 azure table storage Text Editor 中提供以上查询或使用下面是 C# 代码来获取数据
TableQuery partitionKeysQuery = new TableQuery()
.Where("不是 (Id ne '')");
List contentKeyEntities = new List();
TableQuerySegment partitionKeySegment = null;
while (partitionKeySegment == null || partitionKeySegment.ContinuationToken != null)
{
Task t1 = Task.Run(() => O365ReportingTable.ExecuteQuerySegmentedAsync(partitionKeysQuery, partitionKeySegment?.ContinuationToken));
t1.Wait();
partitionKeySegment = t1.Result;
contentKeyEntities.AddRange(partitionKeySegment.Results);
Console.WriteLine(contentKeyEntities.Count);
}
return contentKeyEntities;
public class 审计日志实体:表实体
{
#region构造函数代码
/// <summary>
/// default constructor
/// </summary>
public AuditLogEntity() { }
/// <summary>
/// constructor for creating an AuditLogEntity
/// </summary>
/// <param name="partitionKey">partition key of the data</param>
/// <param name="rowKey">row key for the row</param>
public AuditLogEntity(string partitionKey, string rowKey, JObject content)
{
PartitionKey = partitionKey;
RowKey = rowKey;
Properties = ConvertToEntityProperty(content);
}
#endregion Constructor Code
#region Public Properties
/// <summary>
/// additional properties for the entity
/// </summary>
public IDictionary<string, EntityProperty> Properties { get; set; }
#endregion Public Properties
#region Private Methods
/// <summary>
/// converts JObjects keys into properties
/// </summary>
/// <param name="content">JObject to convert</param>
/// <returns>Dictionary with key value pairs of JOjbect keys</returns>
private IDictionary<string, EntityProperty> ConvertToEntityProperty(JObject content)
{
IDictionary<string, EntityProperty> properties = new Dictionary<string, EntityProperty>();
if (content != null)
{
foreach (JProperty prop in content.Properties())
{
properties.Add(prop.Name, new EntityProperty(prop.Value.ToString()));
}
}
return properties;
}
/// <summary>
/// overrides the base WriteEntry to dynamically write properties to table storage
/// </summary>
/// <param name="operationContext">operation being performed</param>
/// <returns>dictionary of set properties</returns>
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
IDictionary<string, EntityProperty> results = base.WriteEntity(operationContext);
foreach (string key in Properties.Keys)
{
results.Add(key, Properties[key]);
}
return results;
}
/// <summary>
/// overridden base ReadEntry method to convert propeties coming from table storage into the properties from this object
/// </summary>
/// <param name="properties">properties read in from table storage</param>
/// <param name="operationContext">operation being performed</param>
public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
{
base.ReadEntity(properties, operationContext);
Properties = properties;
}
#endregion Private Methods
}
我有 table 个可以为 null 的字段:
public int? Order {get; set;}
public DateTime? StartDate {get; set;}
public DateTime? EndDate {get; set;}
public string Text {get; set;}
所有这些字段都可以是 NULL 值
查询记录时出现问题
其中 Order、StartDate、EndDate 和 Text 不为 NULL 或
其中 Order、StartDate 和 Text 不为空但 EndDate 为空或
其中 Order 和 Text 不为空,但 StartDate 和 EndDate 为空
Order.HasValue && StartDate.HasValue && EndDate.HasValue && !string.IsNullOrEmpty(Text) || Order.HasValue && StartDate.HasValue && !EndDate.HasValue && !string.IsNullOrEmpty(Text) || Order.HasValue && !StartDate.HasValue && !EndDate.HasValue && !string.IsNullOrEmpty(Text)
使用此类查询时出现错误或 400(错误请求)或不支持的运算符(不支持 isnullorempty)
根据这个答案 不可能查询 NULL 值...
据我所知,您无法将 DateTime 设置为 null 或空。 所以,我建议您可以将日期时间存储为字符串,当您想要映射到视图模型时,您可以将字符串转换为 DateTime。
插入实体时,将 DateTime 转换为字符串:
TableBatchOperation batchOperation = new TableBatchOperation();
DateTime dts = DateTime.Now;
DateTime dte = DateTime.UtcNow;
// Create a customer entity and add it to the table.
CustomerEntity customer1 = new CustomerEntity("Smith", "Jeff");
customer1.Order = 1;
customer1.StartDate = Convert.ToString(dts);
customer1.EndDate = Convert.ToString(dte);
customer1.Text = "text1";
// Create another customer entity and add it to the table.
CustomerEntity customer2 = new CustomerEntity("Smith", "Ben");
customer2.Order = 2;
customer2.StartDate = Convert.ToString(dts);
customer2.EndDate = "";
customer2.Text = "text2";
CustomerEntity customer3 = new CustomerEntity("Smith", "Cai");
customer3.Order = 3;
customer3.StartDate = "";
customer3.EndDate = "";
customer3.Text = "text3";
// Add both customer entities to the batch insert operation.
batchOperation.Insert(customer1);
batchOperation.Insert(customer2);
batchOperation.Insert(customer3);
// Execute the batch operation.
table.ExecuteBatch(batchOperation);
实体如下:
public class CustomerEntity : TableEntity
{
public CustomerEntity(string lastName, string firstName)
{
this.PartitionKey = lastName;
this.RowKey = firstName;
}
public CustomerEntity() { }
public int? Order { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public string Text { get; set; }
public DateTime? ConvertTime(string dateStr)
{
if (string.IsNullOrEmpty(dateStr))
return null;
DateTime dt;
var convert=DateTime.TryParse(dateStr, out dt);
return dt;
}
}
显示或映射到模型时,可以使用ConvertTime方法判断列是否为空ConvertTime(entity.StartDate)
。 如果为空,则显示为空,如果有值,则将字符串转换为日期时间。
string orderhasvalue = TableQuery.GenerateFilterCondition("Order", QueryComparisons.NotEqual, null);
string startdatehasvalue = TableQuery.GenerateFilterCondition("StartDate", QueryComparisons.NotEqual, null);
string enddatehasvalue = TableQuery.GenerateFilterCondition("EndDate", QueryComparisons.NotEqual, null);
string texthasvalue = TableQuery.GenerateFilterCondition("Text", QueryComparisons.NotEqual, null);
string startdatenothasvalue = TableQuery.GenerateFilterCondition("StartDate", QueryComparisons.Equal, null);
string enddatenothasvalue = TableQuery.GenerateFilterCondition("EndDate", QueryComparisons.Equal, null);
TableQuery<CustomerEntity> query1 = new TableQuery<CustomerEntity>().Where(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
orderhasvalue, TableOperators.And, startdatehasvalue),
TableOperators.And, enddatehasvalue),
TableOperators.And, texthasvalue)
);
TableQuery<CustomerEntity> query2 = new TableQuery<CustomerEntity>().Where(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
orderhasvalue, TableOperators.And, startdatehasvalue),
TableOperators.And, enddatenothasvalue),
TableOperators.And, texthasvalue)
);
TableQuery<CustomerEntity> query3 = new TableQuery<CustomerEntity>().Where(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
TableQuery.CombineFilters(
orderhasvalue, TableOperators.And, startdatenothasvalue),
TableOperators.And, enddatenothasvalue),
TableOperators.And, texthasvalue)
);
// Print the fields for each customer.
foreach (CustomerEntity entity in table.ExecuteQuery(query2))
{
Console.WriteLine("{0}, {1}\t{2}\t{3}\t{4}\t{5}", entity.PartitionKey, entity.RowKey,
entity.Order, entity.ConvertTime(entity.StartDate), entity.ConvertTime(entity.EndDate), entity.Text);
}
您不能在 Azure Table 存储中查询空值,string
也不例外。写入 Azure table 时,具有空值的 属性 不会以表格形式存在,因此引用该 属性 的查询将始终 return 出乎意料的结果。作为解决方法,您可以做的是提供默认的非空值并查询这些值。如果 string
将值 ""
分配给 string
,则允许您查询 string.Empty(不是 null
,因为 ""
不是 null
).对于 DateTime?
类型,同样的解决方法但不是 ""
,您可以分配一个模糊的默认值,即。 DateTime.MinValue
(或MaxValue
)如果属性的实际值为null,否则您可以将其转换为string
并将空字符串指定为默认值但您需要支付来回转换的价格,所以我个人更愿意尽可能避免这种情况。
您可以在 Azure table 存储上查询字符串数据类型字段的空过滤器。
OData 查询 = 不是(Id ne '')
使用上面的 Odata 查询,您可以仅在字符串数据类型字段上过滤空数据。
您可以在 azure table storage Text Editor 中提供以上查询或使用下面是 C# 代码来获取数据
TableQuery partitionKeysQuery = new TableQuery() .Where("不是 (Id ne '')");
List contentKeyEntities = new List();
TableQuerySegment partitionKeySegment = null;
while (partitionKeySegment == null || partitionKeySegment.ContinuationToken != null)
{
Task
public class 审计日志实体:表实体 { #region构造函数代码
/// <summary>
/// default constructor
/// </summary>
public AuditLogEntity() { }
/// <summary>
/// constructor for creating an AuditLogEntity
/// </summary>
/// <param name="partitionKey">partition key of the data</param>
/// <param name="rowKey">row key for the row</param>
public AuditLogEntity(string partitionKey, string rowKey, JObject content)
{
PartitionKey = partitionKey;
RowKey = rowKey;
Properties = ConvertToEntityProperty(content);
}
#endregion Constructor Code
#region Public Properties
/// <summary>
/// additional properties for the entity
/// </summary>
public IDictionary<string, EntityProperty> Properties { get; set; }
#endregion Public Properties
#region Private Methods
/// <summary>
/// converts JObjects keys into properties
/// </summary>
/// <param name="content">JObject to convert</param>
/// <returns>Dictionary with key value pairs of JOjbect keys</returns>
private IDictionary<string, EntityProperty> ConvertToEntityProperty(JObject content)
{
IDictionary<string, EntityProperty> properties = new Dictionary<string, EntityProperty>();
if (content != null)
{
foreach (JProperty prop in content.Properties())
{
properties.Add(prop.Name, new EntityProperty(prop.Value.ToString()));
}
}
return properties;
}
/// <summary>
/// overrides the base WriteEntry to dynamically write properties to table storage
/// </summary>
/// <param name="operationContext">operation being performed</param>
/// <returns>dictionary of set properties</returns>
public override IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext)
{
IDictionary<string, EntityProperty> results = base.WriteEntity(operationContext);
foreach (string key in Properties.Keys)
{
results.Add(key, Properties[key]);
}
return results;
}
/// <summary>
/// overridden base ReadEntry method to convert propeties coming from table storage into the properties from this object
/// </summary>
/// <param name="properties">properties read in from table storage</param>
/// <param name="operationContext">operation being performed</param>
public override void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext)
{
base.ReadEntity(properties, operationContext);
Properties = properties;
}
#endregion Private Methods
}