-
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
Consider suppressing C# 11 required property warnings in ExecuteUpdate #28557
Comments
@roji I thought that missing |
@Bosch-Eli-Black you may be right - I'll look into this. |
After reviewing some of the comments in #795 (such as this one) related to the various approaches to designing the Problems with
|
Thanks for your thoughts @aradalvand.
I personally think this argument isn't very strong. Updating shadow properties is generally a somewhat niche scenario, and losing the strong typing for non-shadow properties in the same update seems like a very small problem. After all, you've already opted into weakly-typed because of the shadow properties. However, I do agree that required properties pose a problem here. Let us discuss this together in the team and see what we think. |
Fair enough, I just wanted to point out some of the other subtle quirks that this approach has and
Sure! Thank you all. |
See #795 (comment) #795 (comment) The version 3 syntax (#795 (comment)) avoids the requiredness check by splitting the expression at the assignment: db.Customers
.Where(...)
.ExecuteUpdate(
c => new { c.Age, c.IsActive, Shadow = EF.Property(c, "Shadow") }, // shadows work too
c => new { Age = c.Age + 1, IsActive = true, Shadow = 123 }
) This is somewhat similar to a join's key selectors from a in ...
join b in ... on new { a.Prop1, a.Prop2 } equals new { b.Prop1, b.Prop2 } though it's still rather verbose. |
@bachratyg I'm not sure I quite understand what you're saying but that looks way too overly verbose and complicated. |
@aradalvand the approach you propose (one Set per column to be updated) cannot be superior if it cannot express some more complex commands efficiently. I have linked some examples above, most use data from a different table/query. The currently favored (?) new {...} approach can handle these (but not required properties). How would I write such a query with your proposal? What I wrote above can handle both the requiredness and the complexity e.g. both of these are correct: .ExecuteUpdate(c => c.Age, c => c.Age + 1);
.ExecuteUpdate(c => new { c.Age, c.IsActive }, c => new { Age = c.Age + 1, IsActive = true }); but yes, the verbosity is unpleasant. |
In this example: .ExecuteUpdate(c => new { c.Age, c.IsActive }, c => new { Age = c.Age + 1, IsActive = true }); The second argument (lambda expression) is going to lack strong typing because it's an anonymous type. Am I right? So how is this any better than the following, which is, again, not type safe, but achieves the same result? .ExecuteUpdate(c => new { Age = c.Age + 1, IsActive = true }); |
Not necessarily if the signature is ExecuteUpdate<TEntity, TExpr>(
this IQueryable<TEntity> source,
Expression<Func<TEntity, TExpr>> columnSelector,
Expression<Func<TEntity, TExpr>> expressionSelector) Then the result type of both arguments must match otherwise the compiler will complain. This is the same as the key selectors on Queryable.Join. |
@bachratyg Oh okay I get it now. Interesting, but there seems to be several problems with that:
Correct me if I'm wrong but I don't think there's anything this could express that the |
Note that for single column updates, there's no need for an anonymous type, this "just works": courses.ExecuteUpdate(e => e.Deleted, e => false); Here's a query I don't see how could be done efficiently with single property .Set(...): db.Customers.ExecuteUpdate(
c => new { c.BestOrder, c.AverageOrder, ... },
c => (from o in c.Orders
group o by 1 into g // imagine a query with arbitrary complexity here, this is just a basic example
select new
{
BestOrder = g.Max(o => o.TotalValue),
AverageOrder = g.Average(o => o.TotalValue), ...
}).First() // Always a single row, this could be omitted with some signature tweaking
) I only want to scan the Orders table once, but the result of that scan is needed in more than one column. |
Proposal by @bachratyg may work better though auto-completion issue remains. See #6560 for our past experience in trying to get intellisense to work better. |
context.Customers.Where(...).ExecuteUpdate(c => c.Age = c.Age + 1 && c.IsActive = true ); How about this ? |
@
I don't think this is a valid lamda expression |
Is it possible to make this syntax valid? Such condition is quite common. |
I think the long form would work fine: context.Customers.Where(...).ExecuteUpdate(c => {
c.Age++;
c.IsActive = true;
}); |
@Bosch-Eli-Black that's not a valid lambda expression either. Note that almost all of the above have already been proposed and discussed in #795 (several times, in fact), though I understand that it's a very long issue and hard to read through. In any case, we're actively looking into the ExecuteUpdate API shape. |
I am closing this issue as its original purpose - suppressing the diagnostic for C# 11 require properties - is impossible. We'll continue discussing in #795. |
ExecuteUpdate accepts a NewExpression for expressing the properties to be changed:
If Customer has any C# 11 required properties on it, this will generate a compiler warning, since the property is uninitialized.
We could write a diagnostics suppressor that suppresses C# 11 required properties if they occur within the ExecuteUpdate lambda.
Raised by @aradalvand in #795 (comment)
The text was updated successfully, but these errors were encountered: