TrackableEntities / EntityFrameworkCore.Scaffolding.Handlebars

Scaffold EF Core models using Handlebars templates.
MIT License
210 stars 53 forks source link

NullReferenceException in CheckOutputFiles #23

Closed andregizero closed 6 years ago

andregizero commented 6 years ago

I'm using .NET Core 2.1.300-rc1-008673 and have updated to 1.0.0-rc3 of EntityFrameworkCore.Scaffolding.Handlebars. I get the following NullPointer when trying to scaffold from an existing database. I have previously used 1.0.0-beta together with .NET Core 2.0 and have successfully scaffolded using the same database.

Unable to generate entity type for table 'dbo.SavedRadioButtons'. The column 'dbo.NoteResources.IsActive' would normally be mapped to a non-nullable bool property, but it has a default constraint. Such a column is mapped to a nullable bool property to allow a difference between setting the property to false and invoking the default constraint. See https://go.microsoft.com/fwlink/?linkid=851278 for details. System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.CheckOutputFiles(ScaffoldedModel scaffoldedModel, String outputDir, Boolean overwriteFiles) at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.Save(ScaffoldedModel scaffoldedModel, String outputDir, Boolean overwriteFiles) at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable1 schemas, IEnumerable1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable1 schemaFilters, IEnumerable1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>cDisplayClass0_1.<.ctor>b0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>cDisplayClass3_0`1.b0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action) Object reference not set to an instance of an object.

I'm using the following command:

dotnet ef dbcontext scaffold "Data Source=localhost;Initial Catalog=MyDatabase;User Id=secret; Password=secret" Microsoft.EntityFrameworkCore.SqlServer -o Domain -c MyDbContext -f

tonysneed commented 6 years ago

Does the dotnet ef dbcontext scaffold command throw an exception without including the ScaffoldingDesignTimeServices class in your project? It looks like the error is thrown by EF Core and has nothing to do with the Handlebars templating add-in.

From the message it looks like you simply need to make the IsActive property nullable in both the database and your model. If you still have problems, I suggest you post the issue to the EF Core repo or on Stack Overflow.

andregizero commented 6 years ago

If I remove ScaffoldingDesignTimeServices.cs from the project I can run the scaffolding command without any problems. If I add the file back the NullReferenceException occurs again. So it certainly looks like it's triggered by Handlebars.

tonysneed commented 6 years ago

Would you be able to post a repo to GitHub so I can step through the code?

andregizero commented 6 years ago

Unfortunately the code as well as the database belongs to my employer so I cannot share that. Is there a way I can enable tracing or debug this myself?

tonysneed commented 6 years ago

Let me ask @bricelam: Is there a way to attach the VS debugger to the process running the dotnet ef dbcontext scaffold command so that we can set breakpoints and step through the code?

@andredahlqvist Could you provide a sample that reproduces your issue but does not use anything proprietary?

andregizero commented 6 years ago

Sure, I will try to narrow it down.

bricelam commented 6 years ago

To debug, add a call to Debugger.Launch() somewhere in your code, e.g. in your or the app's IDesignTimeServices.ConfigureDesignTimeServices() implementation.

tonysneed commented 6 years ago

@andredahlqvist If you provide a sample repo, we should be able to debug the error by adding Debugger.Launch() and setting a breakpoint. We can also set VS to break on all exceptions.

andregizero commented 6 years ago

Sorry for the delay. Here is a repository that shows how to reproduce the crash. Instructions in the README.md file.

https://github.com/andredahlqvist/crashhandlebars

tonysneed commented 6 years ago

I’ll debug this to what’s happening.

tonysneed commented 6 years ago

@andredahlqvist There is something wrong with the bak file in your project. After restoring I don't see any tables, and when I try to create a database diagram it says I don't have permission.

Instead of a bak file, can you instead provide a SQL script to create the table?

andregizero commented 6 years ago

@tonysneed Actually that's on purpose. I noticed that it didn't matter which tables I had in the database, I could even reproduce it without any tables.

tonysneed commented 6 years ago

So you're trying to reverse engineer a table that doesn't exist in the database?

andregizero commented 6 years ago

@tonysneed I realize that's silly, and it may not be the same crash as I saw when I was actually running against a database with tables, but I assumed the crash could actually be unrelated to the reverse engineering part. Either way, it shouldn't crash when the table you are pointing to doesn't exist.

tonysneed commented 6 years ago

I thought you were reproducing the original error, which took place with a table that has a column with a default constraint? Is this still the case?

andregizero commented 6 years ago

Like I said, it happens no matter what table I try it on. If it makes you feel happier I can send you a bak file with a random table that it crashes on.

tonysneed commented 6 years ago

I'm just trying to understand how to reproduce the issue. From what you're saying, I simply need to try to reverse engineer a table that does not exist in the database using ReverseEngineerOptions.EntitiesOnly. Is that correct?

andregizero commented 6 years ago

It does crash if I do that and that's the simplest testcase I could come up with. That's why I wrote those instructions in the README.md.

tonysneed commented 6 years ago

OK so the expected result should be the message: Unable to find a table in the database matching the selected table dummy.

andregizero commented 6 years ago

Yeah, that's what I wrote in the README.md (as you can see the crash appears to happen in CheckOutputFiles, just like in the original stack trace I posted in this issue).

You should receive the following stack trace:

Unable to find a table in the database matching the selected table dummy. System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.CheckOutputFiles(ScaffoldedModel scaffoldedModel, String outputDir, Boolean overwriteFiles) at Microsoft.EntityFrameworkCore.Scaffolding.Internal.ReverseEngineerScaffolder.Save(ScaffoldedModel scaffoldedModel, String outputDir, Boolean overwriteFiles) at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable1 schemas, IEnumerable1 tables, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable1 schemaFilters, IEnumerable1 tableFilters, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>cDisplayClass0_1.<.ctor>b0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>cDisplayClass3_0`1.b0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action) Object reference not set to an instance of an object.

_

tonysneed commented 6 years ago

OK, I was confused because in your original post you were not specifying a table. Were you able to resolve that issue?

andregizero commented 6 years ago

The crash happens in the same method so I believe this is the same issue.

tonysneed commented 6 years ago

But can you reproduce the issue with an existing table? I don't think it has anything to do with whether the table exists or not.

andregizero commented 6 years ago

Feel like I'm repeating myself: it happens no matter what table I try it on, i.e. existing tables too.

tonysneed commented 6 years ago

I understand now. Your repro would be clearer if you would not introduce the variable of the non-existent table. That would save me time in troubleshooting.

tonysneed commented 6 years ago

Fixed by PR #24. I'll include this with release v1.1.0.

tonysneed commented 6 years ago

Release here: https://github.com/TrackableEntities/EntityFrameworkCore.Scaffolding.Handlebars/releases/tag/v1.1.0 Package here: https://www.nuget.org/packages/EntityFrameworkCore.Scaffolding.Handlebars/1.1.0