-
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
Allow using foreign keys in Dataverse reverse engineering #34689
base: main
Are you sure you want to change the base?
Conversation
@dotnet-policy-service agree |
@@ -1028,7 +1025,7 @@ private void GetIndexes(DbConnection connection, IReadOnlyList<DatabaseTable> ta | |||
[i].[has_filter], | |||
[i].[filter_definition], | |||
[i].[fill_factor], | |||
COL_NAME([ic].[object_id], [ic].[column_id]) AS [column_name], | |||
[c].[name] AS [column_name], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wonder why COL_NAME was used previously??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was my main concern, I haven't found a situation yet where this produces different results but I assume it must be there for some reason. It was introduced in 746ff59 but I can't see any specific reasoning behind it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! It was there because earlier there was no join with sys.columns - and it was just left there
https://github.com/dotnet/efcore/blob/32434d2d86a75e091e331940384115e447ff33de/src/EFCore.SqlServer/Scaffolding/Internal/SqlServerDatabaseModelFactory.cs - so nothing to be concerned about
@MarkMpn LGTM - I have verified that the same results appear in AdventureWorks for the new SQL statement with this query: SELECT
SCHEMA_NAME([t].[schema_id]) AS [table_schema],
[t].[name] AS [table_name],
[i].[name] AS [index_name],
[i].[type_desc],
[i].[is_primary_key],
[i].[is_unique_constraint],
[i].[is_unique],
[i].[has_filter],
[i].[filter_definition],
[i].[fill_factor],
COL_NAME([ic].[object_id], [ic].[column_id]) AS [column_name],
[ic].[is_descending_key],
[ic].[is_included_column]
FROM [sys].[indexes] AS [i]
JOIN [sys].[tables] AS [t] ON [i].[object_id] = [t].[object_id]
JOIN [sys].[index_columns] AS [ic] ON [i].[object_id] = [ic].[object_id] AND [i].[index_id] = [ic].[index_id]
JOIN [sys].[columns] AS [c] ON [ic].[object_id] = [c].[object_id] AND [ic].[column_id] = [c].[column_id]
EXCEPT
SELECT
SCHEMA_NAME([t].[schema_id]) AS [table_schema],
[t].[name] AS [table_name],
[i].[name] AS [index_name],
[i].[type_desc],
[i].[is_primary_key],
[i].[is_unique_constraint],
[i].[is_unique],
[i].[has_filter],
[i].[filter_definition],
[i].[fill_factor],
[c].[name] AS [column_name],
[ic].[is_descending_key],
[ic].[is_included_column]
FROM [sys].[indexes] AS [i]
JOIN [sys].[tables] AS [t] ON [i].[object_id] = [t].[object_id]
JOIN [sys].[index_columns] AS [ic] ON [i].[object_id] = [ic].[object_id] AND [i].[index_id] = [ic].[index_id]
JOIN [sys].[columns] AS [c] ON [ic].[object_id] = [c].[object_id] AND [ic].[column_id] = [c].[column_id]
|
@MarkMpn If you are interested, I can try to add this fix to EF Core Power Tools (for EF Core 6 only) and you can verify against a Dataverse? |
That would be great, thanks! |
bool IsValidPrimaryKey(DatabasePrimaryKey primaryKey) | ||
{ | ||
if (_engineEdition != EngineEdition.DynamicsTdsEndpoint) | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use brackets, not one line return statements
I implemented a fix for this in the latest daily build, would be grateful if you could try it out. |
Thanks, that seems to work great! Most of the tables now don't have the warning about a missing primary key: There's possibly more Dataverse-specific logic we can do to infer the primary key based on other metadata we have available, but this covers all the main data tables at least. Generating the code for this doesn't produce any warnings, and the related tables can be queried using: var results = ctx.Accounts
.Include(a => a.ContactParentcustomers)
.Select(a => new { a.Name, Contacts = a.ContactParentcustomers.Select(c => c.Fullname).ToList() }); |
@MarkMpn Wonderful! Would you be interested in this for EF Core 8 and later in Power Tools? |
Absolutely! Power Tools is my default way of using EF Core so it would be great to see this merged in there too. |
Implemented in latest daily |
Thanks, yes that's working great. |
Reverse engineering Dataverse tables ignores primary keys and therefore foreign keys, presumably because Dataverse does not support the
COL_NAME
function being used in the query to retrieve the index details.This PR mainly changes that query to use the column name from the
sys.columns
catalog view instead, which is supported by Dataverse.It also introduces checks on the primary and foreign keys to ensure it only uses single
uniqueidentifier
column keys for Dataverse as the metadata can expose various other internal keys of different types which break the code generation, such as a foreign key of a string type referencing a primary key of a uniqueidentifier type. As the developer is not able to make any changes to these internal schemas to correct them, it's necessary to simply ignore them during the code generation instead.