-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recognize filters created by fluent API and reverse engineer to fluent API. #10183
Comments
Unfortunately, reducing expressions returned by the database requires parsing Transact-SQL. We tried this in the past, but it was very error-prone, so we decided to avoid doing it for now. From what I remember, the parenthesis were actually required in certain cases, so we couldn't just blindly strip them from every expression. |
@azabluda In addition to the explanation from @bricelam, can I ask why you are diffing the original and scaffolded models? What is the workflow that results in a need to diff these two things? Also, related, why are you reverse engineering the model from the database of Migrations are being used to update the database? (I'm not saying these things are inherently wrong, but they seem unusual, so it would be great if we could understand the scenarios/requirements that lead to you doing these things.) Closing this as by-design for now, but if we get additional information we could reconsider. |
@bricelam thank you for the explanation! I fully agree that parsing Transact-SQL is a pain, but the problem seems to be easier to address from another end. Let's simply take the form of @ajcvickers I'm currently investigating the options for those of our projects where the use of out-of-the-box Migrations is problematic. There may be various reasons, both technical and non-technical, objective and subjective, historical, etc. The standard EF approach to database migrations is to maintain the history of increments, which may lead to rather fragile workflows if f.ex. we are not always in full control over all database schemas we are deploying to. In the past we used to have a custom solution for such environments which followed the alternative approach. Instead of applying the increments we used to compare the target datamodel against the current one to dynamically determine the migration steps. This method proved to be very reliable in general, and with some neatly designed extensions we managed to overcome most of its obvious drawbacks, e.g. the inherent inability to perform a trivial "table/column rename" migration without a lossy DROP/CREATE operation. After spending some time studying the code of EFCore I came to a conclusion that most mechanisms to enable the alternative workflow were already there. In fact my first tests largely exceeded my own expectations (great job guys! 👍 no seriously, you're awesome!). I only observed some minor issues like #10134 and #9188, but generally I'm looking very positive into using EFCore built-in scaffolding and diffing instead of our custom tool. I also notice your team's regularly touching the topic of roundtripability of RevEng and Migrations, which sounds quite encouraging to me. I generally agree with your 'closed-by-design' resolution. After all I can workaround the problem by applying some custom pre-processing to both models prior to diffing. Yet if the EFCore team is gradually moving towards roundtripability anyway, then I would gladly mark my workarounds |
@azabluda Have you looked at SSDT database projects? They allow the workflow you describe (I think) ? |
@azabluda Thanks for the information. It will help us make decisions going forward with regards to round-tripping. |
Reopening so we can discuss again as a team. (No commitment to change anything at this time.) |
@ErikEJ Thanks for the hint! I need to check how we can leverage SSDT database projects while still defining the model primarily with EFCore CodeFirst. Could be a bit more challenging though to find a similar technology for our Oracle based customers... 🤔 @ajcvickers Ah, glad to hear that! It really feels like EFCore came fairly close to a very solid solution, so not doing the final touch ups would be a pity. Linking #3599. |
After further discussion in triage we realized that reverse engineering should recognize that "([FOLDER_ID] IS NOT NULL)" is the consequence of having @azabluda Do you think this would fix the issue you are seeing? It depends somewhat on exactly what you are diffing. |
@ajcvickers Your statement is certainly correct, but depending on the actual implementation it may or may not necessarily fix the original issue. At least I can imagine both implementations. I apologize for not making my point clear from the very beginning. I actually do not reverse engineer the database into C# code, but I only scaffold the Let us consider a simple degenerate case of my (generally broader) scenario. I start with the
The idea behind all this is that I want to be able to compare an arbitrary database with my If you wish, I can create and share with you a simple repro. |
@azabluda I suspect that you may have to either:
The latter may happen with the proposed fix, but like you said it depends on how it is implemented. |
If the difference is only in Index.Filter then it could possibly work. When building code first model, conventions/data-annotation/fluent API populates whole model to have all info required (including setting annotations). So ideally those 2 models would be same (except for filter thing we know above). |
@ajcvickers I'm going to proceed with your first suggestion as a workaround for now. For the permanent solution I still believe it would be much easier to make the standard code first model builder include parentheses rather than to teach RevEng to strip them out. But I certainly may not see the whole picture, so I trust you find the best solution. @bricelam Thanks for the link. I'm encouraged to see it among stretch goals of EFCore team. Although I'm still not planning to really generate the actual code from the database, I'm sure this effort will have a general positive effect on the consistency between IModel's generated by the model builder and reverse engineering. |
@bricelam to add a note as to why this is hard to fix. |
Today, the provider doesn't play a role in deciding whether "core" configuration would be applied by convention. We need to add additional provider APIs to enable this. |
I define a unique index for a entity
Folder
with a nullable propertyFolder.FolderId
(link to parent folder)The debugger shows a Relational:Filter "[FOLDER_ID] IS NOT NULL" annotation defined on that index. The generated DDL looks fine
Now if I reverse engineer this database
then the Relational:Filter becomes "([FOLDER_ID] IS NOT NULL)" (note the two round brackets). Diffing the original and the scaffolded models yields unnecessary DROP/CREATE INDEX operations, which at first glance doesn't look correct. Wouldn't it make sense to reduce the Relational:Filter to a canonical form during scaffolding?
Further technical details
EF Core version: 2.0.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10 Pro
IDE: Visual Studio 2017
The text was updated successfully, but these errors were encountered: