cmd.AddTableParam - lobodava/artisan-orm GitHub Wiki
cmd.AddTableParam builds or accepts a DataTable, adds it as a SqlDbType.Structured parameter, and sets the SQL type name from DataTable.TableName. It configures the command; it does not execute SQL.
The corresponding user-defined table type must already exist. Match its schema-qualified name, column order, types, and nullability. A stored procedure declares its TVP parameter READONLY.
| Call | Behavior |
|---|---|
AddTableParam(name, dataTable) |
Uses the supplied table and its TableName
|
AddTableParam(name, users) |
Uses registered CreateDataTable and CreateDataRow methods |
AddTableParam(name, users, tableName) |
Uses the same registered mapper and overrides the table name |
AddTableParam(name, users, tableName, columnNames) |
Auto-maps the named readable properties into columns in the requested order |
The table describes entity collections such as IEnumerable<User>. Integer ID lists have separate convenience overloads; see ID parameters.
Inside a RepositoryBase subclass, this method configures and executes a procedure. Its int result is the procedure's T-SQL RETURN value, not an affected-row count:
public int SaveUsers(IList<User> users)
{
return ExecuteCommand(cmd =>
{
cmd.UseProcedure("dbo.SaveUsers");
cmd.AddTableParam("@Users", users);
});
}The mapper must provide CreateDataTable() and CreateDataRow(User). Use RequiredMethod.BothForDataTable for a write-only mapper, or AllMain when the entity also needs CreateObject. The collection is enumerated while constructing the parameter.
The four-argument overload takes an explicit comma- or semicolon-separated property list. This example assumes dbo.UserTableType has Id, Login, Name, and Email columns in that order with compatible types:
public int SaveUsersWithProjection(IList<User> users)
{
return ExecuteCommand(cmd =>
{
cmd.UseProcedure("dbo.SaveUsers");
cmd.AddTableParam("@Users", users, "dbo.UserTableType", "Id,Login,Name,Email");
});
}Omitting columnNames from this call selects a different overload: AddTableParam("@Users", users, "dbo.UserTableType") still requires a registered mapper. It does not auto-map all properties.
To use all eligible public readable simple properties deliberately, construct the table explicitly:
public int SaveUsersWithAllProperties(IList<User> users)
{
return ExecuteCommand(cmd =>
{
cmd.UseProcedure("dbo.SaveUsers");
cmd.AddTableParam("@Users", users.AsDataTable("dbo.UserTableType"));
});
}An explicit column list is usually a better fit for a fixed UDTT: reflection property order is not a substitute for checking the SQL contract. The current auto-mapper skips unknown property names; inspect the resulting schema instead of assuming a typo will throw. Its generated delegates are cached by type, table name, and selected properties.
For new parent/child graphs, prepare temporary IDs and foreign keys before materializing child parameters. TVPs are read-only in T-SQL; translate temporary IDs through a join with an ID map, rather than trying to update the TVP. See graph saving.
Source: parameter overloads, DataTable conversion.
See also: