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
New Set() overloads for UPDATE #3798
base: master
Are you sure you want to change the base?
Conversation
Add suspiciously missing call to ProcessSourceQueryable It's present in 3 out of 4 identical methods... IUpdatable has a single implementation, that it's casted to everywhere. Add Query to the interface and stop casting. Eliminate redundant allocations Fix stuff
/azp run test-all |
Azure Pipelines successfully started running 1 pipeline(s). |
To follow-up on our recent discussion about guards and throw helpers, notice how frequent this kind of short methods are in this PR: public static IUpdatable<T> Set<T>(
this IUpdatable<T> source,
[InstantHandle] Expression<Func<T, T>> setters)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (setters == null) throw new ArgumentNullException(nameof(setters));
return SetInitializer(source.Query, Methods.LinqToDB.Update.SetUpdatablePrev, setters);
} Using guard helpers would shorten the code and after inlining public static IUpdatable<T> Set<T>(
this IUpdatable<T> source,
[InstantHandle] Expression<Func<T, T>> setters)
{
Guard.NotNull(source);
Guard.NotNull(setters);
return SetInitializer(source.Query, Methods.LinqToDB.Update.SetUpdatablePrev, setters);
} |
@sdanyliv can you please carefully review In my tests it works, but I'm really not sure it's the proper, reliable way:
For your reference, this method works from the lambda |
Test baselines changed by this PR. Don't forget to merge/close baselines PR after this pr merged/closed. |
Actually it is not correct. I suggest to postpone this PR until version 5. Query translation will be much more simpler. |
Syntax
t.Update(old => new T { A = 1, B = 2 })
is great but not always usable.When one wants to add setters dynamically or set multiple fields with
ROW (A, B) = ...
, one needs to use the.Set()
family of APIs.These only allow defining setters one-by-one, so I'm adding some new overloads to make it more convenient to use.
Set a new initializer
Basically works exactly like
Update
above, but can be called multiple times amongst other.Set()
calls.Set a ROW with single query
Consider this:
It works and it is conceptually equivalent to the generated SQL.
But that is not optimal C#:
SqlRow<T1, T2>
, no implicit conversions. Assigningint
toint?
has to be wrapped intoAsNullable()
.SqlRow
, one generally has to add.Single()
.Sql.Row
is limited to 8 elements, it is impossible to update more fields. Larger tables are far from uncommon.I'm removing all of those 4 pain points with the following new overload that accepts a
IQueryable<T>
, that should select an initializer like the basicUpdate()
example above: