FirebirdSQL / NETProvider

Firebird ADO.NET Data Provider
https://www.firebirdsql.org/en/net-provider/
Other
161 stars 66 forks source link

Scaffold table fails with "Sequence contains no matching element" #1055

Closed Dreamoochy closed 2 years ago

Dreamoochy commented 2 years ago

I try to scaffold Northwind DB via

dotnet ef dbcontext scaffold 
"User=SYSDBA;Password=masterkey;Database=../../Northwind/Northwind.fdb;Dialect=3;Charset=UTF8;ServerType=1" 
FirebirdSql.EntityFrameworkCore.Firebird --namespace Northwind.Shared --data-annotations

No errors, but .cs files for EmployeeTerritories and CustomerCustomerDemo tables are not generated. If I try to scaffold them individually

dotnet ef dbcontext scaffold 
"User=SYSDBA;Password=masterkey;Database=../../Northwind/Northwind.fdb;Dialect=3;Charset=UTF8;ServerType=1" 
FirebirdSql.EntityFrameworkCore.Firebird --table EmployeeTerritories --namespace Northwind.Shared --data-annotations

I get the following error

Build started...
Build succeeded.
To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
System.InvalidOperationException: Sequence contains no matching element
   at System.Linq.ThrowHelper.ThrowNoMatchException()
   at FirebirdSql.EntityFrameworkCore.Firebird.Scaffolding.Internal.FbDatabaseModelFactory.GetConstraints(DbConnection connection, IReadOnlyList`1 tables)
   at FirebirdSql.EntityFrameworkCore.Firebird.Scaffolding.Internal.FbDatabaseModelFactory.GetTables(DbConnection connection, Func`3 filter)
   at FirebirdSql.EntityFrameworkCore.Firebird.Scaffolding.Internal.FbDatabaseModelFactory.Create(DbConnection connection, DatabaseModelFactoryOptions options)
   at FirebirdSql.EntityFrameworkCore.Firebird.Scaffolding.Internal.FbDatabaseModelFactory.Create(String connectionString, DatabaseModelFactoryOptions options)
   at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.ScaffoldModel(String connectionString, DatabaseModelFactoryOptions databaseOptions, ModelReverseEngineerOptions modelOptions, ModelCodeGenerationOptions codeOptions)    
   at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable`1 schemas, IEnumerable`1 tables, String modelNamespace, String contextNamespace, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames, Boolean suppressOnConfiguring, Boolean noPluralize)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable`1 schemaFilters, IEnumerable`1 tableFilters, String modelNamespace, String contextNamespace, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames, Boolean suppressOnConfiguring, Boolean noPluarlize)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Sequence contains no matching element

It seems that tables list/order matters. If I use

dotnet ef dbcontext scaffold 
"User=SYSDBA;Password=masterkey;Database=../../Northwind/Northwind.fdb;Dialect=3;Charset=UTF8;ServerType=1" 
FirebirdSql.EntityFrameworkCore.Firebird --table Region --table Employees --table Territories 
--table EmployeeTerritories --namespace Northwind.Shared --data-annotations

I get no errors, as well as no .cs file for the EmployeeTerritories table

I'm not an expert neither in C# nor in DBs, so any help would be appreciated.

.NET6 (SDK 6.0.302), FirebirdSql.EntityFrameworkCore.Firebird 9.0.2, Firebird (embedded) 4.0.1.2692 for Win64, Win 11 Pro

cincuranet commented 2 years ago

The System.InvalidOperationException: Sequence contains no matching element is fixed in ba0f2d61.

The reason why you don't see file for EmployeeTerritories is because it's a M:N table and EF Core hides that relational detail from you (although you can change the mapping and use such entity). You can see the hidden entity here:

entity.HasMany(d => d.Territories)
    .WithMany(p => p.Employees)
    .UsingEntity<Dictionary<string, object>>(
        "EmployeeTerritory",
        l => l.HasOne<Territory>().WithMany().HasForeignKey("TerritoryId").OnDelete(DeleteBehavior.Restrict).HasConstraintName("FK_EmployeeTerritories_Territories"),
        r => r.HasOne<Employee>().WithMany().HasForeignKey("EmployeeId").OnDelete(DeleteBehavior.Restrict).HasConstraintName("FK_EmployeeTerritories_Employees"),
        j =>
        {
            j.HasKey("EmployeeId", "TerritoryId");

            j.ToTable("EmployeeTerritories");

            j.HasIndex(new[] { "EmployeeId" }, "FK_EmployeeTerritories_Employees");

            j.HasIndex(new[] { "TerritoryId" }, "FK_EmployeeTerritories_Territories");

            j.HasIndex(new[] { "EmployeeId", "TerritoryId" }, "PK_EmployeeTerritories").IsUnique();

            j.IndexerProperty<int>("EmployeeId").HasColumnName("EmployeeID");

            j.IndexerProperty<string>("TerritoryId").HasMaxLength(20).HasColumnName("TerritoryID");
        });