简体   繁体   English

无法将可查询方法转换为可枚举方法。 这可能是实体框架中的一个问题

[英]Unable to convert a queryable method to an enumerable method. This is likely an issue in Entity Framework

I am creating a somewhat complex query to retrieve some many to many relationships with an entity.我正在创建一个有点复杂的查询来检索与实体的多对多关系。 Here is thee code that creates the query:这是创建查询的代码:

  protected virtual async Task<IQueryable<ContactWithNavigationProperties>> GetQueryForNavigationPropertiesAsync()
  {
    var dbContext = await GetDbContextAsync();
    return from contact in await GetDbSetAsync()
           join department in dbContext.Departments
             on contact.DepartmentId equals department.Id into departments
           from department in departments.DefaultIfEmpty()
           join client in dbContext.Clients
             on contact.ClientId equals client.Id into clients
           from client in clients.DefaultIfEmpty()
           join contactAddress in dbContext.Set<ContactAddress>()
             on contact.Id equals contactAddress.ContactId into contactAddresses
           from contactAddress in contactAddresses.DefaultIfEmpty()
           join contactEmailAddress in dbContext.Set<ContactEmailAddress>()
             on contact.Id equals contactEmailAddress.ContactId into contactEmailAddresses
           from contactEmailAddress in contactEmailAddresses.DefaultIfEmpty()
           join contactPhoneNumber in dbContext.Set<ContactPhoneNumber>()
             on contact.Id equals contactPhoneNumber.ContactId into contactPhoneNumbers
           from contactPhoneNumber in contactPhoneNumbers.DefaultIfEmpty()
           select new ContactWithNavigationProperties
           {
             Contact = contact,
             Department = department,
             Client = client,
             Addresses = (from ca in contactAddresses
                          join address in dbContext.Addresses
                            on ca.AddressId equals address.Id into addresses
                          from address in addresses.DefaultIfEmpty()
                          select address).ToList(),
             EmailAddresses = (from cea in contactEmailAddresses
                               join emailAddress in dbContext.EmailAddresses
                                 on cea.EmailAddressId equals emailAddress.Id into emailAddresses
                               from emailAddress in emailAddresses.DefaultIfEmpty()
                               select emailAddress).ToList(),
             PhoneNumbers = (from cpn in contactPhoneNumbers
                             join phoneNumber in dbContext.PhoneNumbers
                               on cpn.PhoneNumberId equals phoneNumber.Id into phoneNumbers
                             from phoneNumber in phoneNumbers.DefaultIfEmpty()
                             select phoneNumber).ToList()
           };
  }

As soon as this query is executed, I am getting the following exception:执行此查询后,我将收到以下异常:

2021-12-06 07:49:17.867 -06:00 [ERR] Unable to convert a queryable method to an enumerable method. This is likely an issue in Entity Framework, please file an issue at https://go.microsoft.com/fwlink/?linkid=2142044.
System.InvalidOperationException: Unable to convert a queryable method to an enumerable method. This is likely an issue in Entity Framework, please file an issue at https://go.microsoft.com/fwlink/?linkid=2142044.
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.ConvertToEnumerable(MethodInfo queryableMethod, IEnumerable`1 arguments)
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
   at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor)
   at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
   at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.PendingSelectorExpandingExpressionVisitor.Visit(Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.Expand(Expression query)
   at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query)
   at Microsoft.EntityFrameworkCore.Query.RelationalQueryTranslationPreprocessor.Process(Expression query)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.GetAsyncEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
   at MyProject.Contacts.EfCoreContactRepository.GetListWithNavigationPropertiesAsync(String filterText, String name, String surname, String title, Nullable`1 lastContactDateMin, Nullable`1 lastContactDateMax, String note, Nullable`1 departmentId, Nullable`1 clientId, Nullable`1 primary, Nullable`1 active, String sorting, Int32 maxResultCount, Int32 skipCount, CancellationToken cancellationToken) in D:\Century\Internal\Clients.Link\Clients.Link\src\MyProject.EntityFrameworkCore\Contacts\EfCoreContactRepository.cs:line 54
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at MyProject.Contacts.ContactsAppService.GetListAsync(GetContactsInput input) in D:\Century\Internal\Clients.Link\Clients.Link\src\MyProject.Application\Contacts\ContactAppService.cs:line 59
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Authorization.AuthorizationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
   at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at lambda_method3642(Closure , Object )
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.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.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)

So before I submit a bug, I was hoping someone who is an expert with Entity Framework could take a look at my query and point out anything glaring.因此,在我提交错误之前,我希望实体框架专家可以查看我的查询并指出任何明显的问题。

Here is my csproj file with its dependencies:这是我的 csproj 文件及其依赖项:

<Project Sdk="Microsoft.NET.Sdk">

  <Import Project="..\..\common.props" />

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <RootNamespace>MyProject</RootNamespace>
  </PropertyGroup>

  <ItemGroup>
    <Compile Remove="Addresses\AddressesDataSeedContributorWithDependencies.cs" />
    <Compile Remove="Campaigns\CampaignsDataSeedContributor.cs" />
    <Compile Remove="ClientNeeds\ClientNeedsDataSeedContributor.cs" />
    <Compile Remove="Clients\ClientsDataSeedContributorWithDependencies.cs" />
    <Compile Remove="Contacts\ContactsDataSeedContributorWithDependencies.cs" />
    <Compile Remove="Countries\CountriesDataSeedContributor.cs" />
    <Compile Remove="Departments\DepartmentsDataSeedContributor.cs" />
    <Compile Remove="EmailAddresses\EmailAddressesDataSeedContributor.cs" />
    <Compile Remove="EntityFrameworkCore\MyProjectDataSeeder.cs" />
    <Compile Remove="LeadSources\LeadSourcesDataSeedContributor.cs" />
    <Compile Remove="Migrations\MyProjectDbContextModelSnapshot - Copy.cs" />
    <Compile Remove="Opportunities\OpportunitiesDataSeedContributorWithDependencies.cs" />
    <Compile Remove="Opportunities\OpportunityLineItemsDataSeedContributorWithDependencies.cs" />
    <Compile Remove="PhoneNumbers\PhoneNumbersDataSeedContributor.cs" />
    <Compile Remove="ProductGroups\ProductGroupsDataSeedContributor.cs" />
    <Compile Remove="Products\ProductsDataSeedContributorWithDependencies.cs" />
    <Compile Remove="RevenueRepeatFreqs\RevenueRepeatFreqsDataSeedContributor.cs" />
    <Compile Remove="States\StatesDataSeedContributorWithDependencies.cs" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\MyProject.Domain\MyProject.Domain.csproj" />
    <PackageReference Include="Microsoft.Data.SqlClient" Version="3.0.1" />
    <PackageReference Include="Volo.Abp.EntityFrameworkCore.SqlServer" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.SettingManagement.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.IdentityServer.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.BackgroundJobs.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.AuditLogging.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.FeatureManagement.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.BlobStoring.Database.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.Identity.Pro.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.LanguageManagement.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Saas.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.Abp.TextTemplateManagement.EntityFrameworkCore" Version="4.4.4" />
    <PackageReference Include="Volo.CmsKit.Pro.EntityFrameworkCore" Version="4.4.4" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.*">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
      <PrivateAssets>compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native</PrivateAssets>
    </PackageReference>
  </ItemGroup>

</Project>

As you can see I am using ABP Commercial 4.4.4 with EF 5.0.如您所见,我正在使用 ABP Commercial 4.4.4 和 EF 5.0。 Thanks for your help.谢谢你的帮助。

EDIT编辑

It was requested that I include my DB context and my applicable entity definitions.要求我包含我的数据库上下文和适用的实体定义。 Here goes:开始:

MyProductDbContext MyProductDbContext

[ConnectionStringName("Default")]
public class MyProductDbContext : MyProductDbContextBase<MyProductDbContext>
{
  public MyProductDbContext(DbContextOptions<MyProductDbContext> options)
    : base(options) { }

  public DbSet<Contact> Contacts { get; set; }
  public DbSet<EmailAddress> EmailAddresses { get; set; }
  public DbSet<PhoneNumber> PhoneNumbers { get; set; }
  public DbSet<Department> Departments { get; set; }
  public DbSet<Address> Addresses { get; set; }
  public DbSet<State> States { get; set; }
  public DbSet<Country> Countries { get; set; }

  protected override void OnModelCreating(ModelBuilder builder)
  {
    builder.SetMultiTenancySide(MultiTenancySides.Both);

    base.OnModelCreating(builder);
    if (builder.IsHostDatabase())
    {
      builder.Entity<Country>(b =>
      {
        b.ToTable(MyProductConsts.DbTablePrefix + "Countries", MyProductConsts.DbSchema);
        b.ConfigureByConvention();
        b.Property(x => x.Code).HasColumnName(nameof(Country.Code)).IsRequired()
         .HasMaxLength(CountryConsts.CodeMaxLength);
        b.Property(x => x.Name).HasColumnName(nameof(Country.Name)).IsRequired()
         .HasMaxLength(CountryConsts.NameMaxLength);
        b.Property(x => x.Primary).HasColumnName(nameof(Country.Primary));
        b.Property(x => x.Active).HasColumnName(nameof(Country.Active));
      });
    }

    builder.Entity<State>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "States", MyProductConsts.DbSchema);
      b.ConfigureByConvention();
      b.Property(x => x.TenantId).HasColumnName(nameof(State.TenantId));
      b.Property(x => x.Code).HasColumnName(nameof(State.Code)).IsRequired().HasMaxLength(StateConsts.CodeMaxLength);
      b.Property(x => x.Name).HasColumnName(nameof(State.Name)).IsRequired().HasMaxLength(StateConsts.NameMaxLength);
      b.Property(x => x.Primary).HasColumnName(nameof(State.Primary));
      b.Property(x => x.Active).HasColumnName(nameof(State.Active));

      // TODO - Implement referential integrity checks in a StateManager domain service
      //b.HasOne<Country>().WithMany().IsRequired().HasForeignKey(x => x.CountryId);
    });
    builder.Entity<Address>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "Addresses", MyProductConsts.DbSchema);
      b.ConfigureByConvention();
      b.Property(x => x.TenantId).HasColumnName(nameof(Address.TenantId));
      b.Property(x => x.Name).HasColumnName(nameof(Address.Name)).IsRequired()
       .HasMaxLength(AddressConsts.NameMaxLength);
      b.Property(x => x.AddressType).HasColumnName(nameof(Address.AddressType)).IsRequired();
      b.Property(x => x.Line1).HasColumnName(nameof(Address.Line1)).IsRequired()
       .HasMaxLength(AddressConsts.Line1MaxLength);
      b.Property(x => x.Line2).HasColumnName(nameof(Address.Line2)).HasMaxLength(AddressConsts.Line2MaxLength);
      b.Property(x => x.Line3).HasColumnName(nameof(Address.Line3)).HasMaxLength(AddressConsts.Line3MaxLength);
      b.Property(x => x.City).HasColumnName(nameof(Address.City)).IsRequired()
       .HasMaxLength(AddressConsts.CityMaxLength);
      b.Property(x => x.PostalCode).HasColumnName(nameof(Address.PostalCode)).IsRequired()
       .HasMaxLength(AddressConsts.PostalCodeMaxLength);
      b.Property(x => x.Primary).HasColumnName(nameof(Address.Primary));
      b.Property(x => x.Active).HasColumnName(nameof(Address.Active));

      // TODO - Implement referential integrity checks in an AddressManager domain service
      //b.HasOne<State>().WithMany().IsRequired().HasForeignKey(x => x.StateId);
      //b.HasOne<Country>().WithMany().IsRequired().HasForeignKey(x => x.CountryId);
    });
    builder.Entity<Department>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "Departments", MyProductConsts.DbSchema);
      b.ConfigureByConvention();
      b.Property(x => x.TenantId).HasColumnName(nameof(Department.TenantId));
      b.Property(x => x.Code).HasColumnName(nameof(Department.Code)).HasMaxLength(DepartmentConsts.CodeMaxLength);
      b.Property(x => x.Name).HasColumnName(nameof(Department.Name)).IsRequired()
       .HasMaxLength(DepartmentConsts.NameMaxLength);
      b.Property(x => x.Primary).HasColumnName(nameof(Department.Primary));
      b.Property(x => x.Active).HasColumnName(nameof(Department.Active));
    });
    builder.Entity<EmailAddress>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "EmailAddresses", MyProductConsts.DbSchema);
      b.ConfigureByConvention();
      b.Property(x => x.TenantId).HasColumnName(nameof(EmailAddress.TenantId));
      b.Property(x => x.Name).HasColumnName(nameof(EmailAddress.Name)).IsRequired()
       .HasMaxLength(EmailAddressConsts.NameMaxLength);
      b.Property(x => x.EmailAddressType).HasColumnName(nameof(EmailAddress.EmailAddressType)).IsRequired();
      b.Property(x => x.Email).HasColumnName(nameof(EmailAddress.Email)).IsRequired()
       .HasMaxLength(EmailAddressConsts.EmailMaxLength);
      b.Property(x => x.Primary).HasColumnName(nameof(EmailAddress.Primary));
      b.Property(x => x.Active).HasColumnName(nameof(EmailAddress.Active));
    });
    builder.Entity<PhoneNumber>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "PhoneNumbers", MyProductConsts.DbSchema);
      b.ConfigureByConvention();
      b.Property(x => x.TenantId).HasColumnName(nameof(PhoneNumber.TenantId));
      b.Property(x => x.Name).HasColumnName(nameof(PhoneNumber.Name)).IsRequired()
       .HasMaxLength(PhoneNumberConsts.NameMaxLength);
      b.Property(x => x.PhoneNumberType).HasColumnName(nameof(PhoneNumber.PhoneNumberType)).IsRequired();
      b.Property(x => x.Number).HasColumnName(nameof(PhoneNumber.Number)).IsRequired()
       .HasMaxLength(PhoneNumberConsts.NumberMaxLength);
      b.Property(x => x.Primary).HasColumnName(nameof(PhoneNumber.Primary));
      b.Property(x => x.Active).HasColumnName(nameof(PhoneNumber.Active));
      b.Property(x => x.Extension).HasColumnName(nameof(PhoneNumber.Extension))
       .HasMaxLength(PhoneNumberConsts.ExtensionMaxLength);
    });
    builder.Entity<Contact>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "Contacts", MyProductConsts.DbSchema);
      b.ConfigureByConvention();
      b.Property(x => x.TenantId).HasColumnName(nameof(Contact.TenantId));
      b.Property(x => x.Name).HasColumnName(nameof(Contact.Name)).HasMaxLength(ContactConsts.NameMaxLength);
      b.Property(x => x.Surname).HasColumnName(nameof(Contact.Surname)).IsRequired()
       .HasMaxLength(ContactConsts.SurnameMaxLength);
      b.Property(x => x.Title).HasColumnName(nameof(Contact.Title)).HasMaxLength(ContactConsts.TitleMaxLength);
      b.Property(x => x.LastContactDate).HasColumnName(nameof(Contact.LastContactDate))
       .HasMaxLength(ContactConsts.TitleMaxLength);
      b.Property(x => x.Note).HasColumnName(nameof(Contact.Note));
      b.Property(x => x.Primary).HasColumnName(nameof(Contact.Primary));
      b.Property(x => x.Active).HasColumnName(nameof(Contact.Active));

      // many-to-one relationships
      b.HasOne<Department>().WithMany().HasForeignKey(x => x.DepartmentId);
      b.HasOne<Client>().WithMany().HasForeignKey(x => x.ClientId).IsRequired(false);

      // many-to-many relationships
      b.HasMany(x => x.ContactAddresses).WithOne().HasForeignKey(x => x.ContactId).IsRequired();
      b.HasMany(x => x.ContactEmailAddresses).WithOne().HasForeignKey(x => x.ContactId).IsRequired();
      b.HasMany(x => x.ContactPhoneNumbers).WithOne().HasForeignKey(x => x.ContactId).IsRequired();
    });
    builder.Entity<ContactAddress>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "ContactAddresses" + MyProductConsts.DbSchema);
      b.ConfigureByConvention();

      //define composite key
      b.HasKey(x => new { x.ContactId, x.AddressId });

      //many-to-many configuration
      b.HasOne<Contact>().WithMany(x => x.ContactAddresses).HasForeignKey(x => x.ContactId).IsRequired();
      b.HasOne<Address>().WithMany().HasForeignKey(x => x.AddressId).IsRequired();

      b.HasIndex(x => new { x.ContactId, x.AddressId });
    });
    builder.Entity<ContactEmailAddress>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "ContactEmailAddresses" + MyProductConsts.DbSchema);
      b.ConfigureByConvention();

      //define composite key
      b.HasKey(x => new { x.ContactId, x.EmailAddressId });

      //many-to-many configuration
      b.HasOne<Contact>().WithMany(x => x.ContactEmailAddresses).HasForeignKey(x => x.ContactId).IsRequired();
      b.HasOne<EmailAddress>().WithMany().HasForeignKey(x => x.EmailAddressId).IsRequired();

      b.HasIndex(x => new { x.ContactId, x.EmailAddressId });
    });
    builder.Entity<ContactPhoneNumber>(b =>
    {
      b.ToTable(MyProductConsts.DbTablePrefix + "ContactPhoneNumbers" + MyProductConsts.DbSchema);
      b.ConfigureByConvention();

      //define composite key
      b.HasKey(x => new { x.ContactId, x.PhoneNumberId });

      //many-to-many configuration
      b.HasOne<Contact>().WithMany(x => x.ContactPhoneNumbers).HasForeignKey(x => x.ContactId).IsRequired();
      b.HasOne<PhoneNumber>().WithMany().HasForeignKey(x => x.PhoneNumberId).IsRequired();

      b.HasIndex(x => new { x.ContactId, x.PhoneNumberId });
    });
  }
}

Contact接触

public class Contact : FullAuditedAggregateRoot<Guid>, IMultiTenant
{
  private Contact() { }

  internal Contact(Guid id, string name, [NotNull] string surname, string title,
    DateTime? lastContactDate, string note,
    Guid? departmentId = null, Guid? clientId = null, Guid? tenantId = null,
    bool primary = false, bool active = true)
  {
    Id = id;

    Check.Length(name, nameof(name), ContactConsts.NameMaxLength);
    Check.NotNull(surname, nameof(surname));
    Check.Length(surname, nameof(surname), ContactConsts.SurnameMaxLength);
    Check.Length(title, nameof(title), ContactConsts.TitleMaxLength);

    Name = name;
    Surname = surname;
    Title = title;
    LastContactDate = lastContactDate;
    Note = note;
    Primary = primary;
    Active = active;
    DepartmentId = departmentId;
    ClientId = clientId;
    TenantId = tenantId;
    ContactAddresses = new List<ContactAddress>();
    ContactEmailAddresses = new List<ContactEmailAddress>();
    ContactPhoneNumbers = new List<ContactPhoneNumber>();
  }

  [CanBeNull] public virtual string Name { get; set; }

  [NotNull] public virtual string Surname { get; private set; }

  [CanBeNull] public virtual string Title { get; set; }

  [CanBeNull] public virtual DateTime? LastContactDate { get; set; }

  [CanBeNull] public virtual string Note { get; set; }

  public virtual bool Primary { get; set; }

  public virtual bool Active { get; set; }

  [CanBeNull] public virtual Guid? DepartmentId { get; set; }
  [CanBeNull] public virtual Guid? ClientId { get; set; }

  [NotNull] public virtual ICollection<ContactAddress> ContactAddresses { get; }
  [NotNull] public virtual ICollection<ContactEmailAddress> ContactEmailAddresses { get; }
  [NotNull] public virtual ICollection<ContactPhoneNumber> ContactPhoneNumbers { get; }

  public virtual Guid? TenantId { get; set; }
}

ContactAddress联系地址

using System;
using Volo.Abp.Domain.Entities;

namespace MyProduct.Contacts;

public class ContactAddress : Entity
{
  private ContactAddress() { }

  public ContactAddress(Guid contactId, Guid addressId)
  {
    ContactId = contactId;
    AddressId = addressId;
  }

  public Guid ContactId { get; protected set; }

  public Guid AddressId { get; protected set; }

  public override object[] GetKeys()
  {
    return new object[] { ContactId, AddressId };
  }
}

ContactEmailAddress and ContactPhoneNumber entities follow the same pattern as ContactAddress. ContactEmailAddress 和 ContactPhoneNumber 实体遵循与 ContactAddress 相同的模式。

Address地址

public class ContactPhoneNumber : Entity
{
  private ContactPhoneNumber() { }

  public ContactPhoneNumber(Guid contactId, Guid phoneNumberId)
  {
    ContactId = contactId;
    PhoneNumberId = phoneNumberId;
  }

  public Guid ContactId { get; protected set; }

  public Guid PhoneNumberId { get; protected set; }

  public override object[] GetKeys()
  {
    return new object[] { ContactId, PhoneNumberId };
  }
}

EmailAddress and PhoneNumber entities follow the same pattern as Address. EmailAddress 和 PhoneNumber 实体遵循与 Address 相同的模式。

I can provide additional entities but I think these are the ones you need.我可以提供其他实体,但我认为这些是您需要的。

After struggling with the query syntax (which I'm not all that familiar with), I reworked the query using the fluent syntax.在处理了查询语法(我不太熟悉)之后,我使用流利的语法重新编写了查询。

  protected virtual async Task<IQueryable<ContactWithNavigationProperties>> GetQueryForNavigationPropertiesAsync()
  {
    var dbContext = await GetDbContextAsync();
    return dbContext.Contacts
                    .Include(c => c.ContactAddresses)
                    .Include(c => c.ContactEmailAddresses)
                    .Include(c => c.ContactPhoneNumbers)
                    .AsSingleQuery()
                    .Select(c => new ContactWithNavigationProperties
                    {
                      Contact = c,
                      Department = dbContext.Departments.FirstOrDefault(d => d.Id == c.DepartmentId),
                      Client = dbContext.Clients.FirstOrDefault(cl => cl.Id == c.ClientId),
                      Addresses = dbContext.Addresses.Where(a =>
                        c.ContactAddresses.Select(ca => ca.AddressId).Contains(a.Id)).ToList(),
                      EmailAddresses = dbContext.EmailAddresses.Where(ea =>
                        c.ContactEmailAddresses.Select(cea => cea.EmailAddressId).Contains(ea.Id)).ToList(),
                      PhoneNumbers = dbContext.PhoneNumbers.Where(pn =>
                        c.ContactPhoneNumbers.Select(cpn => cpn.PhoneNumberId).Contains(pn.Id)).ToList()
                    });
  }

This worked as I had hoped.这如我所愿。

Note, however, the inclusion of the AsSingleQuery() call.但是请注意,包含AsSingleQuery()调用。 I was getting an exception telling me that my query was configured (I suppose globally) to use AsSplitQuery() and that a collection within the query could not be retrieved using a split query.我收到一个异常,告诉我我的查询已配置(我想是全局的)使用AsSplitQuery()并且无法使用拆分查询检索查询中的集合。 This makes some sense as the inner queries use the included dependencies.这是有道理的,因为内部查询使用包含的依赖项。

I think something was going on along the same lines with my query syntax version and that's why it was failing.我认为我的查询语法版本发生了同样的事情,这就是它失败的原因。

Please leave a comment if you have a good explanation for what is going on or how to fix my query syntax.如果您对正在发生的事情或如何修复我的查询语法有很好的解释,请发表评论。 Hopefully everyone will learn something.希望每个人都能学到一些东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM