-
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
Handle view mapping in ExecuteDelete/Update translation #34709
Conversation
// one that refers to the mutable table. | ||
|
||
// Get the column on the (mutable) table which corresponds to the property being set | ||
var targetColumnModel = property.DeclaringType.GetTableMappings() |
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.
@AndriySvyryd PTAL, this code finds the mutable table column corresponding to the view column that we got from query translation (so that we can modify the SelectExpression to reference the table instead of the view).
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.
There could be multiple column mappings for the same property, but they should still point to the same column, so you should call FirstOrDefault
instead. Or use GroupBy
to be safe
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.
So you're saying there can be multiple column mappings, specifying the same property and same column (basically duplicates)? Does that serve an actual purpose?
Anyway, changed the code to:
var targetColumnModel = property.DeclaringType.GetTableMappings()
.SelectMany(tm => tm.ColumnMappings)
.Where(cm => cm.Property == property)
.Select(cm => cm.Column)
.SingleOrDefault();
d9cbe1c
to
c9a214f
Compare
c9a214f
to
f95a56a
Compare
...Core.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs
Outdated
Show resolved
Hide resolved
...Core.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.ExecuteDelete.cs
Outdated
Show resolved
Hide resolved
|
||
if (targetColumnModel.Name != column.Name) | ||
{ | ||
// If we ever allow mapping the same property to different column names on the view and table, we'll need |
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.
We definitely allow this already
modelBuilder.Entity<Cat>()
.ToTable("Cat", b => b.Property(c => c.Name).HasColumnName("Name"))
.ToView("CatView", b => b.Property(c => c.Name).HasColumnName("ViewName"));
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.
Thanks... Opened #34713 to track this separately, will probably submit a PR for that soon.
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.
Note that this affects other columns in the tree, not just the ones in the update setters, which is what this check looks at. Will remove it for now.
/// <summary> | ||
/// Various helpers for query translation. | ||
/// </summary> | ||
public static class QueryHelpers |
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.
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.
Yep :) This is indeed a thing I wanted to discuss (the naming may need to have EF in it or similar).
Note that the helper method inside - IsMemberAccess - uses extension methods like TryGetEFPropertyArguments, which are completely public (on ExpressionExtension). I think this violates our principle of not exposing public extension methods over non-EF types - users get these in Intellisense when working with extensions. Of course, all this stuff is meant to be provider-facing, we should consider cleaning it up.
ExecuteDelete/Update take as input the SelectExpression that was translated so far, just prior to their appearance; that SelectExpression is assumed to be reading the tables, so references views rather than tables.
Note that the query may reference multiples tables. The additional tables (not the one being mutated) do need to be views, as we're reading from them. But during translation, we don't know which table is being updated - the user can start from one root, and project out a navigation to be deleted. So we only know the target table at the end of translation.
So the approach here is to detect the case where the table to be changed is a view, find the table corresponding to that view, and replace it in the SelectExpression.
Note that handling ExecuteUpdate where the property to set is a complex type and there's a vide mapping isn't yet supported; this is blocking on #34706.
Closes #34677