Ошибка EF Core 3.0 MoveNext при включении с помощью SingleOrDefault

Я читал разные решения и пробовал разные реализации без каких-либо результатов. При использовании другой реализации ошибка всегда одна и та же: «System.InvalidOperationException: перечислитель не смог выполнить MoveNextAsync».

Здесь генерируется исключение.

var portfolioTrades = await _context
      .Portfolios
      .Include(PortfolioEntityTypeConfiguration.TradesList)
      .SingleOrDefaultAsync(x => x.id == id);

Включение обрабатывается способом

  builder.OwnsMany<Trade>(TradesList, x =>
            {
                x.WithOwner().HasForeignKey("portfolio_id");
                x.ToTable("product_trade", SchemaNames.Public);

                x.Property<TradeID>("id");
                x.Property<DateTimeOffset>("_date").HasColumnName("date");
                x.Property("_details").HasColumnName("details");
                x.Property<Guid>("_schemaId").HasColumnName("schema_id");

                x.HasKey(x => x.id);

            });

EF выполнит этот запрос и вернет 1 запись

SELECT t.id, t.description, t.end_client_name, t.name, t0.id, t0.details, t0.portfolio_id
FROM (
    SELECT p.id, p.description, p.end_client_name, p.name
    FROM account.portfolio AS p
    WHERE p.id = '3adcaff1-de64-4ae3-b8b7-c390d76aa0bd'
    LIMIT 2
) AS t
LEFT JOIN product_trade AS t0 ON t.id = t0.portfolio_id
ORDER BY t.id, t0.id

Здесь ниже Сущности

 public class Trade : Entity
{
    public TradeID id { get; private set; }

    private DateTimeOffset _date { get; set; }

    public JObject _details { get; set; }

    private Guid _schemaId { get; set; }

    private Trade()
    {
        id = new TradeID(Guid.NewGuid());
    }

    private Trade( DateTimeOffset date, string details, Guid schema_id)
    {
        id = new TradeID(Guid.NewGuid());
        _date = date;
        _schemaId = schema_id;
        _details = JsonConvert.DeserializeObject<JObject>(details);
    }

    internal static Trade Create(DateTimeOffset date, string details, Guid schema_id)
    {
        return new Trade(date, details, schema_id);
    }

}

}

public class Portfolio : Entity, IAggregateRoot
{
    public PortfolioID id { get; private set; }

    private string _name { get; set; }

    private string _end_client_name { get; set; }

    private string _description { get; set; }

    private readonly List<Trade> _trades;

    private Portfolio()
    {
       _trades = new List<Trade>();
    }
}

// ошибка

System.InvalidOperationException: Enumerator failed to MoveNextAsync.
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
   at Rx.Products.Infrastructure.Domain.Portfolios.PortfolioRepository.GetByPortfolioIdAsync(PortfolioID id) in ....\PortfolioRepository.cs:line 37
   at Rx.Products.Application.Portfolios.CreateTrade.CreateTradeCommandHandler.Handle(CreateTradeCommand request, CancellationToken cancellationToken) in ...\CreateTradeCommandHandler.cs:line 19
   at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
   at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
   at Rx.Products.API.TradesController.RegisterCustomer(CreateTradeRequest new_trade) in ....\TradesController.cs:line 65
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS
=======
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 726
Content-Type: application/json
Host: localhost:54315
User-Agent: PostmanRuntime/7.24.1
Postman-Token: 2aabfa69-9d5c-4637-9d48-02a713077235

справочник ms об отношении генерируют ту же ошибку. Спасибо за ваше время.


person Massimo Mannoni    schedule 14.05.2020    source источник
comment
Есть ли дополнительная информация в исключении? Не могли бы вы добавить трассировку стека?   -  person Guru Stron    schedule 14.05.2020
comment
@GuruStron, конечно, добавил. tnx   -  person Massimo Mannoni    schedule 14.05.2020
comment
@GuruStron, чтобы предоставить вам более подробную информацию. если я удалю Включить, код будет работать правильно и объект будет заполнен.   -  person Massimo Mannoni    schedule 14.05.2020
comment
Кажется, по какой-то причине EF получает несколько записей. Попробуйте FirstOrDefaultAsync и SingleOrDefault. См. this и это проблемы.   -  person Guru Stron    schedule 14.05.2020
comment
@GuruStron с изменением запроса SingleOrDefault, изменяя LIMIT на 1, но возвращаемая ошибка остается той же. Спасибо за ссылки, часть статьи я прочитал безрезультатно: /   -  person Massimo Mannoni    schedule 14.05.2020


Ответы (1)


  1. Думаю, вам действительно поможет общедоступное свойство Portfolio.Trades, которое можно использовать для навигации и определения взаимосвязи между классом Portfolio и классом Trade.
    public class Portfolio : Entity, IAggregateRoot
    {
        // Other class members defined above...

        // New public navigation property for the relationship.
        public IReadOnlyList<Trade> Trades => _trades.AsReadOnly();
    }
  1. Если вы используете отношение OwnsMany, вам не нужно использовать оператор .Include в запросе. Если вы используете отношение HasMany, вам нужно будет использовать оператор .Include.

Использование HasMany и Include:

builder.HasMany(port.Trades, x =>
            {
                // Other configuration code defined above...
            });

var portfolioTrades = await _context
      .Portfolios
      .Include(port => port.Trades)
      .SingleOrDefaultAsync(port => port.id == id);

Использование OwnsMany, а не Include:

builder.OwnsMany(port.Trades, x =>
            {
                // Other configuration code defined above...
            });

var portfolioTrades = await _context
      .Portfolios
      .SingleOrDefaultAsync(port => port.id == id);

Использование отношения OwnsMany будет означать, что все дочерние Trade объекты будут автоматически опрошены для вас. Использование отношения HasMany позволяет указать включение дочерних объектов Trade в состав вашего запроса.

person Steve Scherrer    schedule 14.05.2020
comment
Спасибо Стиву за поддержку. Изменение портфеля сущностей предполагает, что у меня возникла новая ошибка. --- ›Тип« Торговля »нельзя пометить как принадлежащий, поскольку не принадлежащий ему тип сущности с таким именем уже существует. - person Massimo Mannoni; 15.05.2020
comment
очевидно, я удалил включение, используя OwnsMany - person Massimo Mannoni; 15.05.2020
comment
Если есть другая сущность, отличная от Portfolio, которая имеет отношение к сущности Trade, тогда сущность Trade не может принадлежать сущности Portfolio. Самый простой способ устранить эту ошибку - использовать отношение HasMany и использовать оператор .Include в запросе. Мне нравится использовать отношения OwnsMany, где есть относительно небольшое количество дочерних элементов, а коллекция дочерних элементов не увеличивается без ограничений. Подробнее о различиях можно прочитать здесь: stackoverflow.com/ questions / 58516830 / - person Steve Scherrer; 15.05.2020
comment
builder.OwnsMany ‹ProductIdentifier› (ProductIdentifiers, i = ›{.....}); Я использовал предложенный вами код, но ошибка осталась прежней. Сущность вызывается с использованием var product = await _context .Products .Where (x = ›x.Id == id) .SingleAsync (); и ошибка всегда одна и та же. Перечислитель не смог выполнить MoveNextAsync. спасибо Массимо - person Massimo Mannoni; 29.05.2020
comment
.Products.Where (x = ›x.Id == id) .ToListAsync (); используя этот оператор, запрос, сгенерированный, если он выполняется внутри инструмента sql, работает правильно, но vs заморожен ... - person Massimo Mannoni; 29.05.2020
comment
ВЫБРАТЬ ..... p0.product_id, p0.identifier_id FROM public.product AS p LEFT JOIN public.product_identifier AS p0 ON p.id = p0.product_id ГДЕ p.id = $ 1 - person Massimo Mannoni; 29.05.2020