我有一个小问题。我正在尝试从 Cosmos db 迁移到 Azure 中的表存储。问题是我已经很长时间没有处理表存储了。原来我之前用过的包有很大一部分已经过时了。并且官方文档没有提供所需的信息。
目前我使用此方法来添加项目:
public static async Task AddDomain(CloudTable table, DomainEntity domain)
{
TableOperation insertOperation = TableOperation.Insert((Microsoft.WindowsAzure.Storage.Table.ITableEntity)domain);
await table.ExecuteAsync(insertOperation);
}
这个功能应用程序添加域:
[FunctionName("AddDomain")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function,"post", Route = null)] HttpRequest req,
[Table("Domains")] CloudTable domainsTable,
ILogger log)
{
DomainEntity domain = CreateDomain();
await AddDomain(domainsTable, domain);
return new OkResult();
}
但是当我运行该函数时它会抛出异常:
Error indexing method 'AddDomain'
和
System.InvalidOperationException at Microsoft.Azure.WebJobs.Extensions.Tables.TableAttributeBindingProvider.TryCreate.
我对其他 CRUD 操作也有同样的问题。知道发生了什么吗?
最佳答案
这是我上个月的做法
我的服务等级
using Azure;
using Azure.Data.Tables;
using VPMS.FuncApp.EFCore.AuditSetup;
namespace VPMS.Persistence.AuditSetup;
internal class TableStorageService : ITableStorageService
{
private readonly TableServiceClient _tableServiceClient;
public TableStorageService(TableServiceClient tableServiceClient)
{
_tableServiceClient = tableServiceClient;
}
public async Task BulkInsert(string tableName, string partionKey, List<AuditTableStorageTable> audit)
{
var client = _tableServiceClient.GetTableClient(tableName);
List<TableTransactionAction> addEntitiesBatch = new List<TableTransactionAction>();
addEntitiesBatch.AddRange(audit.Select(e => new TableTransactionAction(TableTransactionActionType.Add, e)));
await client.SubmitTransactionAsync(addEntitiesBatch).ConfigureAwait(false);
}
public async Task CreateTableIfNotExistsAsync(string tableName)
{
var client = _tableServiceClient.GetTableClient(tableName);
await client.CreateIfNotExistsAsync();
}
}
我的函数应用
using Microsoft.Azure.WebJobs;
using Microsoft.EntityFrameworkCore;
using VPMS.FuncApp.EFCore;
using VPMS.FuncApp.EFCore.AuditSetup;
using VPMS.Persistence.AuditSetup;
namespace VPMS.FuncApp.ArchiveAppAuditLogs;
public sealed class ArchiveAppAuditLogTimerTrigger
{
private readonly VPMSDbContext _dbContext;
private readonly ITableStorageService _tableStorageService;
public ArchiveAppAuditLogTimerTrigger(VPMSDbContext dbContext, ITableStorageService tableStorageService)
{
_dbContext = dbContext;
_tableStorageService = tableStorageService;
}
[FunctionName(nameof(ArchiveAppAuditLogTimerTrigger))]
public async Task ArchiveAppAuditLogTrigger([TimerTrigger("%ArchiveAppAuditLogCron%")] TimerInfo myTimer)
{
var currentDate = DateTimeOffset.UtcNow.Date;
var auditTable = _dbContext.Set<Audit>();
await _tableStorageService.CreateTableIfNotExistsAsync(FuncAppConstants.AuditTableName);
var query = auditTable.Where(w => w.CreatedOn < currentDate);
int pageSize = 100;
bool hasMoreRecords = true;
for (int skip = 1; hasMoreRecords is true; skip++)
{
var recordsToSync = await query.Skip(0)
.Take(pageSize)
.ToListAsync();
hasMoreRecords = recordsToSync.Any();
if (hasMoreRecords is false) break;
var groupedAuditData = recordsToSync.GroupBy(b => b.TableName).ToList();
foreach (var groupedAuditDatem in groupedAuditData)
{
List<AuditTableStorageTable> auditStorageTableRecords = new();
foreach (var auditEntry in groupedAuditDatem.ToList()) auditStorageTableRecords.Add(AuditTableStorageTable.BuilData(auditEntry));
await _tableStorageService.BulkInsert(FuncAppConstants.AuditTableName, groupedAuditDatem.Key, auditStorageTableRecords);
}
auditTable.RemoveRange(recordsToSync);
await _dbContext.SaveChangesAsync();
}
}
}
我的Azure函数应用启动类
using Azure.Identity;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Azure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using VPMS.FuncApp.EFCore;
using VPMS.FuncApp.Interfaces;
using VPMS.FuncApp.Services;
using VPMS.Persistence.AuditSetup;
using VPMS.SharedKernel.Interfaces;
[assembly: FunctionsStartup(typeof(VPMS.FuncApp.Startup))]
namespace VPMS.FuncApp;
public sealed class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
var configurations = builder.GetContext().Configuration;
builder.Services.AddAzureClients(builder =>
{
builder.AddTableServiceClient(configurations.GetValue<string>("AzureWebJobsStorage"));
builder.UseCredential(new DefaultAzureCredential());
});
}
}
TableStorage 继承的类
using Azure;
using Azure.Data.Tables;
using VPMS.Persistence.AuditSetup;
namespace VPMS.FuncApp.EFCore.AuditSetup;
public sealed class AuditTableStorageTable : ITableEntity
{
public string? UserId { get; set; }
public AuditType AuditType { get; set; }
public string TableName { get; set; } = null!;
public DateTimeOffset CreatedOn { get; set; }
public string? OldValues { get; set; }
public string? NewValues { get; set; }
public string? AffectedColumns { get; set; }
public string PrimaryKey { get; set; } = null!;
public Guid BatchId { get; set; }
// these comes from the implemented interface
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset? Timestamp { get; set; }
public ETag ETag { get; set; }
public static AuditTableStorageTable BuilData(Audit audit)
{
return new()
{
PartitionKey = audit.TableName,
TableName = audit.TableName,
AffectedColumns = audit.AffectedColumns,
AuditType = audit.AuditType,
BatchId = audit.BatchId,
CreatedOn = audit.CreatedOn,
OldValues = audit.OldValues,
NewValues = audit.NewValues,
PrimaryKey = audit.PrimaryKey,
RowKey = Guid.NewGuid().ToString(),
UserId = audit.UserId,
};
}
}
关于azure - Function App 中表存储的 CRUD 操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75281344/