Как расширить свойства унаследованных объектов в OData и DotnetCore? - PullRequest
0 голосов
/ 26 сентября 2019

Я реализовал следующие объекты в ядре Dotnet 2.2.0 и OData 7.2.1.

Module.cs:

using System.Collections.Generic;
namespace Models
{
    public abstract class Module
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public virtual ICollection<ModuleDefinition> ModuleDefinitions { get; set; }
    }
}

Invoice.cs:

namespace Models
{
    public class Invoice : Module
    {

    }
}

Определение модуля:

namespace Models
{
    public class ModuleDefinition
    {
        public int ModuleId { get; set; }
        public Module Module { get; set; }
        public int DefinitionId { get; set; }
        public Definition Definition { get; set; }
    }
}

Definition.cs

using System.Collections.Generic;
namespace Models
{
    public class Definition
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection<ModuleDefinition> ModuleDefinitions { get; set; }
    }
}

Context.cs:

using Microsoft.EntityFrameworkCore;

namespace Models
{
    public class Context : DbContext
    {
        public Context(DbContextOptions<Context> options) : base(options) { }

        public DbSet<Module> Modules { get; set; }
        public DbSet<Invoice> Invoices { get; set; }
        public DbSet<Definition> Definitions { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<ModuleDefinition>()
                        .HasKey(md => new { md.ModuleId, md.DefinitionId });
            modelBuilder.Entity<ModuleDefinition>()
                        .HasOne(md => md.Module)
                        .WithMany(m => m.ModuleDefinitions)
                        .HasForeignKey(md => md.ModuleId);
            modelBuilder.Entity<ModuleDefinition>()
                        .HasOne(md => md.Definition)
                        .WithMany(d => d.ModuleDefinitions)
                        .HasForeignKey(md => md.DefinitionId);
        }
    }
}

Startup.cs:

var builder = new ODataConventionModelBuilder();
            builder.EntitySet<Invoice>("Invoices");
            builder.EntitySet<Module>("Modules");
            builder.EntitySet<ModuleDefinition>("ModuleDefinitions").EntityType.HasKey(t => new { t.ModuleId, t.DefinitionId }); ;
            builder.EnableLowerCamelCase();
            app.UseOData(routeName: "ODataRoute", routePrefix: "odata", model: builder.GetEdmModel());

Вызов этого URL https://localhost:5001/odata/modules?$expand=moduleDefinitions в порядке, и я получил этот ответ:

{"@odata.context":"https://localhost:5001/odata/$metadata#Modules(moduleDefinitions())","value":[{"@odata.type":"#Models.Invoice","id":1,"title":"t","description":"d","moduleDefinitions":[{"moduleId":1,"definitionId":1}]}]}

Но при попытке расширить ModuleDefinition для сущности счета через OData с помощью: https://localhost:5001/odata/invoices?$expand=moduleDefinitions Я ожидал что-то вроде этого:

{"@odata.context":"https://localhost:5001/odata/$metadata#Invoice(moduleDefinitions(definition()))","value":[{"@odata.type":"#Models.Invoice","id":1,"title":"t","description":"d","test":"","moduleDefinitions":[{"moduleId":1,"definitionId":1,"definition":{"id":1,"name":"n"}}]}]}

, но я получил ошибку в dotnet:

info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [m].[Id], [m].[Description], [m].[Discriminator], [m].[Title], [m].[test]
      FROM [Modules] AS [m]
      WHERE [m].[Discriminator] = N'Invoice'
fail: Microsoft.EntityFrameworkCore.Query[10100]
      An exception occurred while iterating over the results of a query for context type 'Models.Context'.
      System.ArgumentNullException: Value cannot be null.
      Parameter name: source
         at System.Linq.Enumerable.Select[TSource,TResult](IEnumerable`1 source, Func`2 selector)
         at lambda_method(Closure , QueryContext , Invoice )
         at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
         at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.IShaper<TOut>.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
         at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
         at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
         at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
         at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 results, QueryContext queryContext, IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext()
         at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
System.ArgumentNullException: Value cannot be null.
Parameter name: source
   at System.Linq.Enumerable.Select[TSource,TResult](IEnumerable`1 source, Func`2 selector)
   at lambda_method(Closure , QueryContext , Invoice )
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
   at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.IShaper<TOut>.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 results, QueryContext queryContext, IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext()
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()

В чем проблема?

1 Ответ

0 голосов
/ 26 сентября 2019

Я решил проблему согласно Ответ Джертера

Я только что отредактировал Startup.cs:

var builder = new ODataConventionModelBuilder();
            builder.EntitySet<Invoice>("Invoices").EntityType.DerivesFromNothing(); //Edited Code
            builder.EntitySet<Module>("Modules");
            builder.EntitySet<ModuleDefinition>("ModuleDefinitions").EntityType.HasKey(t => new { t.ModuleId, t.DefinitionId }); ;
            builder.EnableLowerCamelCase();
            app.UseOData(routeName: "ODataRoute", routePrefix: "odata", model: builder.GetEdmModel());
...