如何使用 EF Core 查找 CosmosDB 中的不良数据?

问题描述 投票:0回答:1

我正在尝试从 CosmosDb 中的

DbSet
中提取所有条目,如下所示:

var list = context.MarketplaceTransactions.ToList();

此操作失败:

信息:2024年8月23日12:44:05.527 CosmosEventId.ExecutingSqlQuery [30100](Microsoft.EntityFrameworkCore.Database.Command)

对分区“(null)”中的容器“StrangeCloudDbContext”执行 SQL 查询[参数=[]]
选择c
从根 c
WHERE (c["Discriminator"] = "MarketplaceTransaction")
信息:2024年8月23日12:44:07.788 CosmosEventId.ExecutedReadNext [30102](Microsoft.EntityFrameworkCore.Database.Command)
执行 ReadNext (2088.0046 ms, 39.43 RU) ActivityId='cdfdac63-7605-4746-a90d-9669cf864d0e',
容器='StrangeCloudDbContext',分区='(空)',参数=[]
选择c
从根 c
WHERE (c["Discriminator"] = "MarketplaceTransaction")
失败:8/23/2024 12:44:07.802 CoreEventId.QueryIterationFailed[10100] (Microsoft.EntityFrameworkCore.Query)

迭代上下文类型“StrangeCloud.Api.Data.StrangeCloudDbContext”的查询结果时发生异常。

System.InvalidOperationException:可为 Null 的对象必须有一个值。

在 lambda_method14(闭包,QueryContext,JObject)
在 Microsoft.EntityFrameworkCore.Cosmos.Query.Internal.CosmosShapedQueryCompilingExpressionVisitor.QueryingEnumerable`1.Enumerator.MoveNext()

我已打开详细的错误报告和敏感日志记录。

大概数据库中的条目之一对于不为空的属性有一个空条目(也许?)。但是,数据库中有数百万个条目和数十个属性,并且该错误告诉我属性或条目都不是问题所在。

如何找到并解决问题?

entity-framework-core azure-cosmosdb
1个回答
0
投票

您可以使用 AsEnumerable() 然后枚举结果,而不是使用尝试一次具体化所有实体的 ToList()。这样,您可以捕获每个有问题的实体的异常:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;

async Task ProcessMarketplaceTransactions(StrangeCloudDbContext context)
{
    var problematicEntities = new List<(int index, Exception exception)>();
    var validEntities = new List<MarketplaceTransaction>();
    int totalProcessed = 0;

    try
    {
        // First, attempt to execute the query without materializing entities
        var query = context.MarketplaceTransactions.AsNoTracking();
        
        // Use a small Take() to test if the query executes at all
        await query.Take(1).ToListAsync();

        // If we get here, the query itself is valid. Now let's process entities.
        await foreach (var entity in query.AsAsyncEnumerable())
        {
            try
            {
                // Attempt to access all properties to force full materialization
                var temp = new 
                {
                    entity.Id,
                    // List all other properties here
                };
                validEntities.Add(entity);
            }
            catch (Exception ex)
            {
                problematicEntities.Add((totalProcessed, ex));
            }
            totalProcessed++;

            // Optional: Add a break condition if you want to limit processing
            // if (totalProcessed >= 1000000) break;
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Query execution failed: {ex.Message}");
        return; // Exit if we can't even start the query
    }

    Console.WriteLine($"Total entities processed: {totalProcessed}");
    Console.WriteLine($"Valid entities: {validEntities.Count}");
    Console.WriteLine($"Problematic entities: {problematicEntities.Count}");

    foreach (var (index, exception) in problematicEntities)
    {
        Console.WriteLine($"Error at index {index}: {exception.Message}");
    }
}

// Usage
await ProcessMarketplaceTransactions(context);
  1. 首先尝试使用 Take(1) 执行查询以检查查询本身是否有效。这将捕获查询执行期间发生的任何异常。
  2. 如果查询有效,它将使用 AsAsyncEnumerable() 来流式传输结果,这对于大型数据集更有效。
  3. 然后,它尝试单独具体化每个实体,捕获有问题的实体的异常。
  4. 外部 try-catch 将处理查询执行期间发生的任何异常,而内部 try-catch 处理实体具体化期间发生的异常。
© www.soinside.com 2019 - 2024. All rights reserved.