UpdateFrom() updates rows with values from joined tables in a single statement, without reading the rows into .NET.
The query's joins and filters select the rows to update, and the set expression can use columns of any joined table:
// Apply each UK warehouse's markup to the price of its parts
var q = db.From<Part>()
.Join<Warehouse>((p, w) => p.WarehouseId == w.Id)
.Where<Warehouse>(w => w.Country == "UK");
int updated = db.UpdateFrom<Part, Warehouse>((p, w) => new Part { Price = p.Price * w.Markup }, q);
UPDATE "Part" SET "Price" = "_u"."_v0"
FROM (
SELECT "Part"."Id" AS "_id", ("Part"."Price"*"Warehouse"."Markup") AS "_v0"
FROM "Part" INNER JOIN "Warehouse" ON ("Part"."WarehouseId" = "Warehouse"."Id")
WHERE ("Warehouse"."Country" = @0)
) "_u"
WHERE "Part"."Id" = "_u"."_id"
-- @0 = 'UK'
Without it, updating rows from another table means selecting them into .NET and updating each one, or writing RDBMS-specific SQL.
Example Data Model​
The examples on this page use these tables:
public class Site
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Warehouse
{
public int Id { get; set; }
public int SiteId { get; set; }
public string Name { get; set; }
public string Country { get; set; }
public decimal Markup { get; set; }
public bool Active { get; set; }
}
public class Part
{
public int Id { get; set; }
public string Name { get; set; }
public int WarehouseId { get; set; }
public string Country { get; set; }
public string Location { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
}
Copy values from a joined table​
The set expression's parameters are the query's table followed by the joined tables, in the order of the generic arguments:
// Each part's country is the country of its warehouse
db.UpdateFrom<Part, Warehouse>((p, w) => new Part { Country = w.Country },
db.From<Part>().Join<Warehouse>((p, w) => p.WarehouseId == w.Id));
Only the columns in the set expression are updated. UpdateFrom() returns the number of rows updated.
Filter the rows to update by a joined table​
When the values only use the query's table, use the single table overload, with the joins in the query:
// Clear the stock of parts in inactive warehouses
var q = db.From<Part>()
.Join<Warehouse>((p, w) => p.WarehouseId == w.Id)
.Where<Warehouse>(w => !w.Active);
db.UpdateFrom(p => new Part { Stock = 0 }, q);
UPDATE "Part" SET "Stock" = "_u"."_v0"
FROM (
SELECT "Part"."Id" AS "_id", @0 AS "_v0"
FROM "Part" INNER JOIN "Warehouse" ON ("Part"."WarehouseId" = "Warehouse"."Id")
WHERE "Warehouse"."Active"=0
) "_u"
WHERE "Part"."Id" = "_u"."_id"
-- @0 = 0
Multiple columns, values and params​
Set multiple columns with any mix of columns, calculations, constants and captured values. Constants and captured values are sent as params:
var discount = 0.5m;
db.UpdateFrom<Part, Warehouse>((p, w) => new Part {
Country = w.Country,
Location = "Clearance",
Price = p.Price * discount,
}, q);
Multiple joined tables​
Use values from up to 3 joined tables:
// Each part in stock is located at the site of its warehouse
var q = db.From<Part>()
.Join<Warehouse>((p, w) => p.WarehouseId == w.Id)
.Join<Warehouse, Site>((w, s) => w.SiteId == s.Id)
.Where(p => p.Stock > 0);
db.UpdateFrom<Part, Warehouse, Site>((p, w, s) => new Part { Location = s.Name }, q);
Async​
int updated = await db.UpdateFromAsync<Part, Warehouse>((p, w) => new Part { Country = w.Country }, q);
The query isn't modified, so it can be reused, e.g. to select the updated rows:
await db.UpdateFromAsync(p => new Part { Stock = p.Stock + 1 }, q);
var parts = await db.SelectAsync(q);
RDBMS support​
Each RDBMS uses its own syntax for updating from other tables:
| RDBMS | Generated SQL |
|---|---|
| SQL Server | UPDATE t SET ... FROM t INNER JOIN ... WHERE ... |
| MySQL, MariaDB | UPDATE t INNER JOIN ... SET ... WHERE ... |
| PostgreSQL, SQLite 3.33+ | UPDATE t SET ... FROM (SELECT t.Id, ... FROM t INNER JOIN ... WHERE ...) u WHERE t.Id = u.Id |
| Oracle, Firebird | NotSupportedException |
For example the markup example above generates:
db.UpdateFrom<Part, Warehouse>((p, w) => new Part { Price = p.Price * w.Markup }, q);
UPDATE "Part" SET "Price" = ("Part"."Price"*"Warehouse"."Markup")
FROM "Part" INNER JOIN "Warehouse" ON ("Part"."WarehouseId" = "Warehouse"."Id")
WHERE ("Warehouse"."Country" = @0)
db.UpdateFrom<Part, Warehouse>((p, w) => new Part { Price = p.Price * w.Markup }, q);
UPDATE `Part` INNER JOIN `Warehouse` ON (`Part`.`WarehouseId` = `Warehouse`.`Id`)
SET `Part`.`Price` = (`Part`.`Price`*`Warehouse`.`Markup`)
WHERE (`Warehouse`.`Country` = @0)
PostgreSQL and SQLite update from a sub query of the rows to update with their new values, which keeps the query's joins and filters exactly as they are. This requires the table to have a primary key.
INFO
If a row matches multiple rows of a joined table, it's updated with the values from one of them, so join on columns that match at most one row, e.g. a foreign key to a primary key.
UpdateFrom() can't be combined with GroupBy(), Skip(), Take(), ForUpdate(), TopPerGroup(), set operations
like Union() or WithRecursive(), and can't update the primary key. Oracle and Firebird throw a
NotSupportedException before anything is updated, use UpdateOnly() instead.