ServiceStack / Issues

Issue Tracker for the commercial versions of ServiceStack
11 stars 8 forks source link

Cant find Property on Type 'IEnumerable`1' at ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn, Func`2 filter) #782

Closed solrevdev closed 1 year ago

solrevdev commented 1 year ago

Describe the issue

Hi,

I have a working released project and when I update ServiceStack.Ormlite.MySqlConnector to version 6.1.0 and above I get the following error:

System.ArgumentException: Cant find 'BatchId' Property on Type 'IEnumerable`1'
   at ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn, Func`2 filter) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack.OrmLite/src/ServiceStack.OrmLite/OrmLiteExecFilter.cs:line 119

Any nuget package 6.0.2 and below it works fine.

Could you point me in the right direction please.

Reproduction

The offending line that throws the exception is

var found = await db.LoadSingleByIdAsync<T>(id).ConfigureAwait(false);
System.ArgumentException: Cant find 'BatchId' Property on Type 'IEnumerable`1'
   at ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn, Func`2 filter) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack.OrmLite/src/ServiceStack.OrmLite/OrmLiteExecFilter.cs:line 119
   at web.Core.Data.Repository`1.FindById(Guid id) in /Users/solrevdev/Projects/redacted/src/web/Core/Data/Repository.cs:line 61
   at web.Core.Services.ProducerService.GetFullAndEagerBatch(Guid batchId) in /Users/solrevdev/Projects/redacted/src/web/Core/Services/ProducerService.cs:line 285
   at web.Pages.Production.ViewPageModel.OnGetAsync() in /Users/solrevdev/Projects/redacted/src/web/Pages/Production/View.cshtml.cs:line 22
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.NonGenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at web.Startup.<>c.<<Configure>b__9_0>d.MoveNext() in /Users/solrevdev/Projects/redacted/src/web/Startup.cs:line 117
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Expected behavior

When I upgraded I expceted it to work or for there to be some docs or intellisense explaining that my code needed to change or something.

System Info

dotnet

dotnet --info
.NET SDK (reflecting any global.json):
 Version:   6.0.402
 Commit:    6862418796

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  12.6
 OS Platform: Darwin
 RID:         osx.12-x64
 Base Path:   /usr/local/share/dotnet/sdk/6.0.402/

Host:
  Version:      7.0.0-rc.2.22472.3
  Architecture: x64
  Commit:       550605cc93

.NET SDKs installed:
  3.1.419 [/usr/local/share/dotnet/sdk]
  3.1.424 [/usr/local/share/dotnet/sdk]
  6.0.402 [/usr/local/share/dotnet/sdk]
  7.0.100-rc.2.22477.23 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.25 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.30 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.10 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.0-rc.2.22476.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.30 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.10 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.0-rc.2.22472.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  Not set

global.json file:
  /Users/solrevdev/Projects/fridgeswag/global.json

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

neofetch

```text
OS: macOS 12.6 21G115 x86_64
Host: Macmini7,1
Kernel: 21.6.0
Uptime: 18 mins
Packages: 345 (brew)
Shell: zsh 5.8.1
Resolution: 2560x1440
DE: Aqua
WM: Quartz Compositor
WM Theme: Blue (Light)
Terminal: iTerm2
Terminal Font: CaskaydiaCoveNerdFontComplete-Regular 16
CPU: Intel i5-4278U (4) @ 2.60GHz
GPU: Intel Iris
Memory: 10339MiB / 16384MiB


### Additional context

_No response_

### Validations

- [X] Confirm [Issue is reproducible](https://github.com/ServiceStack/Issues#how-to-create-a-good-bug-report) from the information provided
- [X] Have an active commercial ServiceStack License _(GitHub Username is [registered on Support page](https://account.servicestack.net/account/support))_
mythz commented 1 year ago

Sounds like a binary incompatibility issue, like you're using a different version of MySqlConnector that the v2.1.8 OrmLite was built with. We haven't been regularly upgrading & testing MySqlConnector, what's the reason you're using it over the official MySql.Data ADO.NET Provider (in Ormlite.MySql)?

solrevdev commented 1 year ago

UPDATE

@mythz It looks like I needed it for MySqlConnectorDialect.Provider

 public static IServiceCollection AddOrmLiteDbFactoryServices(this IServiceCollection services, IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
        {
            var connectionString = configuration.GetConnectionString("defaultconnection");

            if (webHostEnvironment.IsProduction())
            {
                services.AddSingleton<IDbConnectionFactory>(_ => new OrmLiteConnectionFactory(connectionString, MySqlConnectorDialect.Provider));
            }
            else
            {
                services.AddSingleton<IDbConnectionFactory>(_ => new OrmLiteConnectionFactory(connectionString, MySqlConnectorDialect.Provider)
                {
                    ConnectionFilter = conn => new ProfiledDbConnection((DbConnection)conn, MiniProfiler.Current)
                });
            }

            return services;
        }

Hi @mythz good question. no good reason that I can think of. at some stage I must of (or tooling) added that in order to add the following to my .cs file

using ServiceStack.Data;
using ServiceStack.OrmLite;

Below is my full .csproj for reference.

So, should I be using a different package reference rather than <PackageReference Include="ServiceStack.Ormlite.MySqlConnector" Version="6.1.0" /> like ServiceStack.OrmLite.MySql for example?

Do you think swapping those references out will be enough to fix.

Thanks for looking at this by the way.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <UserSecretsId>625f2771-bf7e-4716-915c-f6eb2688c4e1</UserSecretsId>
  </PropertyGroup>

  <ItemGroup>
    <Using Include="StackExchange.Profiling" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.10" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.10">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.TypeScript.MSBuild" Version="4.8.4">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.0" />
    <PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
    <PackageReference Include="AWSSDK.S3" Version="3.7.9.67" />
    <PackageReference Include="BuildBundlerMinifier" Version="3.2.449" />
    <PackageReference Include="iTextSharp.LGPLv2.Core" Version="1.9.2" />
    <PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />
    <PackageReference Include="MiniProfiler.AspNetCore.Mvc" Version="4.2.22" />

    <PackageReference Include="Seq.Extensions.Logging" Version="6.1.0" />
    <PackageReference Include="ServiceStack.Ormlite.MySqlConnector" Version="6.1.0" />
    <PackageReference Include="solrevdev.instagrambasicdisplay" Version="1.1.3" />
    <PackageReference Include="Vereyon.Web.FlashMessage" Version="3.0.0" />
    <PackageReference Include="Wangkanai.Detection" Version="5.7.2" />
    <PackageReference Include="ZXing.Net" Version="0.16.8" />
    <PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
    <PackageReference Include="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Version="6.0.5.128" />
  </ItemGroup>

  <ItemGroup>
    <Folder Include="Core/Temp/">
    </Folder>
    <Folder Include="Core/Resources">
    </Folder>
  </ItemGroup>

  <ItemGroup Condition="'$(Configuration)' == 'Debug' ">
    <None Update="kestrel.pfx" CopyToOutputDirectory="PreserveNewest" Condition="Exists('kestrel.pfx')" />
  </ItemGroup>

  <ItemGroup>
    <Content Include="Core/Resources//**/*.*">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Project>
mythz commented 1 year ago

That should be fine, all ServiceStack libraries need to reference the same version, if you always want to use the latest version you would use a 6.* wildcard version instead.

Can't tell what the issue is from here, I'd recommend switching to OrmLite.MySql to see if it resolves it, if it's still an issue can you create a small standalone repro I can run locally to identify the issue.

solrevdev commented 1 year ago

@mythz

@mythz It looks like I needed it for MySqlConnectorDialect.Provider which isnt in <PackageReference Include="ServiceStack.OrmLite.MySql" Version="6.4.0" />

I'm trying to just use <PackageReference Include="ServiceStack.OrmLite.MySql" Version="6.4.0" /> instead but am getting an exception that the name The name 'MySqlConnectorDialect' does not exist in the current context

I'm sure you are right and I need to switch to OrmLite.MySql I just need to try and resolve where MySqlConnectorDialect comes from. Any ideas?

 public static IServiceCollection AddOrmLiteDbFactoryServices(this IServiceCollection services, IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
        {
            var connectionString = configuration.GetConnectionString("defaultconnection");

            if (webHostEnvironment.IsProduction())
            {
                services.AddSingleton<IDbConnectionFactory>(_ => new OrmLiteConnectionFactory(connectionString, MySqlConnectorDialect.Provider));
            }
            else
            {
                services.AddSingleton<IDbConnectionFactory>(_ => new OrmLiteConnectionFactory(connectionString, MySqlConnectorDialect.Provider)
                {
                    ConnectionFilter = conn => new ProfiledDbConnection((DbConnection)conn, MiniProfiler.Current)
                });
            }

            return services;
        }
mythz commented 1 year ago

OrmLite.MySql uses MySqlDialect.Provider

You can find Dialect providers listed in the docs: https://docs.servicestack.net/ormlite/getting-started

solrevdev commented 1 year ago

@mythz

Ok same issue even with <PackageReference Include="ServiceStack.OrmLite.MySql" Version="6.4.0" />

Let me try and recreate the bug and stand up to a Github project for you. I'll post again when done...

solrevdev commented 1 year ago

Hi @mythz,

I will still get you a standalone repo, but I wanted to post my findings as I go along in case some ah-ha moment occurred.

The difficulty is in getting the to the right set of model/schema/variables/data to recreate the issue in a small test project.

So far I have figured out that it has something to do with Load* methods throwing the error.

The Single* methods seems to be fine.

The Load* methods below throw the same exception

System.ArgumentException: Cant find 'BatchId' Property on Type 'IEnumerable`1'
   at ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn, Func`2 filter) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack.OrmLite/src/ServiceStack.OrmLite/OrmLiteExecFilter.cs:line 119

However replacing them with Single* does not

So if anything seems obvious from the below great otherwise bear with me while I try and get a repo small enough to reproduce

using var db = await DbFactory.OpenAsync().ConfigureAwait(false);
var batch = await db.SingleByIdAsync<Batch>(batchId).ConfigureAwait(false); // this actually works
var batch1 = await db.LoadSelectAsync<Batch>(x => x.Id == batchId).ConfigureAwait(false); // same error as i posted
var batch2 = await db.LoadSingleByIdAsync<Batch>(batchId).ConfigureAwait(false); // same error as i posted

The Batch class inherits from a base BaseEntity class and loads a collection of related Order's. Each Order is linked to various other classes/tables


public class BaseEntity
{
    [HiddenInput]
    [PrimaryKey]
    public Guid Id { get; set; } = Guid.NewGuid();

    [DataType(DataType.DateTime)]
    [Display(Name = "Date Created")]
    public DateTime DateCreated { get; set; } = DateTime.Now;

    [Display(Name = "Date Modified")]
    [DataType(DataType.DateTime)]
    public DateTime DateModified { get; set; } = DateTime.Now;  
}

public class Batch : BaseEntity
{
    [AutoIncrement]
    public long BatchNumber { get; set; }

    [Reference, Ignore]
    public IEnumerable<Order> Orders { get; set; }   
}

public class Order : BaseEntity
{
    public Order(Guid userId, Guid jobCardId)
    {
        UserId = userId;
        JobCardId = jobCardId;        
    }

    [AutoIncrement]
    public long OrderNumber { get; set; }

    [References(typeof(User))]
    public Guid UserId { get; set; }

    [References(typeof(JobCard))]
    public Guid? JobCardId { get; set; }

    [Ignore]
    public IEnumerable<JobCardItem> JobCardItemRef { get; set; }
}
mythz commented 1 year ago

Can you change IEnumerable<T> to List<T>, also your data models and DTOs should have a parameterless constructor which is what the libraries use when creating & populating instances.

solrevdev commented 1 year ago

Can you change IEnumerable<T> to List<T>, also your data models and DTOs should have a parameterless constructor which is what the libraries use when creating & populating instances.

@mythz Bingo!!!

That was indeed the issue. All is working as it should.

I changed IEnumerable<T> to List<T> and created a default constructor on my Order class and all worked nicely, I can now upgrade to the latest and greatest plus I am using the correct nuget this time!

Thank you so much! 🙏

mythz commented 1 year ago

Great, happy to hear it!