azure - Function App 中表存储的 CRUD 操作

标签 azure azure-functions azure-table-storage

我有一个小问题。我正在尝试从 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/

相关文章:

c# - 唤醒 Azure 函数

c# - 为什么发布 Azure Function 后出现内部服务器错误?

azure - 使用 Rest Api 查询 Azure 表存储

azure - microsoft azure 表身份验证 stringtosign 错误

c# - 使用 C# 中的 v4 函数应用从 Azure 表存储获取包含所有数据集的完整表

c# - 强制 EventProcessorHost 重新传递失败的 Azure 事件中心 eventData 到 IEventProcessor.ProcessEvents 方法

c# - Azure Functions 无法解释的冷启动

.net - Azure 网站中的缓存策略

java - 我的 Power BI 身份验证流程和 Web 请求有什么问题?

C# 模型与 CosmosDB 如何处理模型更改