can Dapper implement multiple delete insert or update as QueryMultiple? - dapper

I have seen QueryMultiple from Dapper official doc as below, It is convenient!
var sql = #"
select * from Customers where CustomerId = #id
select * from Orders where CustomerId = #id
select * from Returns where CustomerId = #id";
using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
var customer = multi.Read<Customer>().Single();
var orders = multi.Read<Order>().ToList();
var returns = multi.Read<Return>().ToList();
...
}
Now, when I delete record from Parent-table,I want to delete related record from Child-table.
can Dapper fit it? It looks that as below.
var sql = #"delete from tb_role where roleid=#ID
delete from tb_rolepermission where roleid=#ID
delete from tb_userrole where roleid=#ID
";
var param = new { ID=id };
connection.EXECUTEMultiple(sql, param)..........
Any help will be appreciated!

Yes, you can can simply call connection.Execute and it already allows multiple commands like you are trying to do, the same as ExecuteQuery allows on SqlCommand, which is all Dapper is calling anyways.

Related

Dapper SqlBuilder OrWhere using AND instead of OR

I was trying to use the Where and OrWhere methods of SqlBuilder for Dapper, but it is not acting like how I would expect.
The edited portion of this question is basically what I ran into. Since it didn't receive a response, I'll ask it here.
var builder = new SqlBuilder();
var sql = builder.AddTemplate("select * from table /**where**/ ");
builder.Where("a = #a", new { a = 1 })
.OrWhere("b = #b", new { b = 2 });
I expected select * from table WHERE a = #a OR b = #b
but I got select * from table WHERE a = #a AND b = #b
Is there any way to add an OR to the where clause using the SqlBuilder?
I think it's just a matter of changing the following in the SqlBuilder class to say OR instead of AND, but I wanted to confirm.
public SqlBuilder OrWhere(string sql, dynamic parameters = null)
{
AddClause("where", sql, parameters, " AND ", prefix: "WHERE ", postfix: "\n", IsInclusive: true);
return this;
}
Nevermind. I looked through the SqlBuilder code and found that if there is a mixture of Where and OrWhere, it will do the following:
Join all the AND clauses
Join all the OR clauses separately
Attach the OR clauses at the end of the AND clauses with an AND
If you don't have more than 1 OrWhere, then you won't see any OR.
I'll modify my query logic to take this into account
You have to change your query into:
var builder = new SqlBuilder();
var sql = builder.AddTemplate("select * from table /**where**/ ");
builder.OrWhere("a = #a", new { a = 1 })
.OrWhere("b = #b", new { b = 2 });
In case you want to try another alternative, DapperQueryBuilder may be easier to understand:
var query = cn.QueryBuilder($#"
SELECT *
FROM table
/**where**/
");
// by default multiple filters are combined with AND
query.FiltersType = Filters.FiltersType.OR;
int a = 1;
int b = 2;
query.Where($"a = {a}");
query.Where($"b = {b}");
var results = query.Query<YourPOCO>();
The output is fully parametrized SQL (WHERE a = #p0 OR b = #p1).
You don't have to manually manage the dictionary of parameters.
Disclaimer: I'm one of the authors of this library

How to create two tables side by side in flow document

I want to create two tables side by side in flow document.
I don't want to use blockuicontainer.
It is all composition, you need to put the two tables inside another table which has the dimensions of one row with two columns, something like this:
Table table1 = CreateTable1();
Table table2 = CreateTable2();
var containingTable = new Table();
var containingRowGroup = new TableRowGroup();
var containingColumn1 = new TableColumn();
var containingColumn2 = new TableColumn();
containingTable.Columns.Add(containingColumn1);
containingTable.Columns.Add(containingColumn2);
containingTable.RowGroups.Add(containingRowGroup);
var containingCell1 = new TableCell();
var containingCell2 = new TableCell();
containingCell1.Blocks.Add(new Section(table));
containingCell2.Blocks.Add(new Section(table2));
var containingRow = new TableRow();
containingRow.Cells.Add(containingCell1);
containingRow.Cells.Add(containingCell2);
containingRowGroup.Rows.Add(containingRow);
document.Blocks.Add(new Section(containingTable));

How to set Query Parameters

How to map the OLE DB source SQL command query parameters with variables using EzAPI ?
Basically I need to do something like below.
Thanks in advance.
Here is how I had to do it for SSIS 2012. I had to find the GUID of the variable in question and set it that way.
EzOleDbSource source = new EzOleDbSource(this);
source.Connection = sourceconnection;
source.SqlCommand = sourcecomannd;
source.AccessMode = AccessMode.AM_SQLCOMMAND;
source.SetComponentProperty("ParameterMapping", "\"Parameter0:Input\",{C2BCD5B0-1FDB-4A74-8418-EEF9C1D19AC3};");
To get the GUID you can query the Variables in the EZPackage object.
Application a = new Application();
var package = a.LoadPackage(packagelocation, null);
var ezpackage = new EzPackage(package);
var firstOrDefault = ezpackage.Variables.OfType<Microsoft.SqlServer.Dts.Runtime.Variable>()
.AsQueryable()
.FirstOrDefault(x => x.Name.Equals("MyParameter"));
if (firstOrDefault != null)
{
var guid =
firstOrDefault.ID;
}
I have accepted Geek's answer because it is the real answer for my question. But I found instead of mapping variables to parameters we can use variables directly in the query. For example: exec your_sp_name "#[User::your_variable_name]"
UPDATE : Above method is not working.
Use the the accepted answer method. To take the GUID of the variable, I used the follwing method.
string guid = string.Empty;
foreach (var x in this.Variables)
{
if (x.Name == "cdc_capture_log_id")
{
guid = x.ID;
}
}
Where this = EzPackage. Same as above.

Audit of what records a given user can see in SalesForce.com

I am trying to determine a way to audit which records a given user can see by;
Object Type
Record Type
Count of records
Ideally would also be able to see which fields for each object/record type the user can see.
We will need to repeat this often and for different users and in different orgs, so would like to avoid manually determining this.
My first thought was to create an app using the partner WSDL, but would like to ask if there are any easier approaches or perhaps existing solutions.
Thanks all
I think that you can follow the documentation to solve it, using a query similar to this one:
SELECT RecordId
FROM UserRecordAccess
WHERE UserId = [single ID]
AND RecordId = [single ID] //or Record IN [list of IDs]
AND HasReadAccess = true
The following query returns the records for which a queried user has
read access to.
In addition, you should add limit 1 and get from record metadata the object type,record type, and so on.
I ended up using the below (C# using the Partner WSDL) to get an idea of what kinds of objects the user had visibility into.
Just a quick'n'dirty utility for my own use (read - not prod code);
var service = new SforceService();
var result = service.login("UserName", "Password");
service.Url = result.serverUrl;
service.SessionHeaderValue = new SessionHeader { sessionId = result.sessionId };
var queryResult = service.describeGlobal();
int total = queryResult.sobjects.Count();
int batcheSize = 100;
var batches = Math.Ceiling(total / (double)batcheSize);
using (var output = new StreamWriter(#"C:\test\sfdcAccess.txt", false))
{
for (int batch = 0; batch < batches; batch++)
{
var toQuery =
queryResult.sobjects.Skip(batch * batcheSize).Take(batcheSize).Select(x => x.name).ToArray();
var batchResult = service.describeSObjects(toQuery);
foreach (var x in batchResult)
{
if (!x.queryable)
{
Console.WriteLine("{0} is not queryable", x.name);
continue;
}
var test = service.query(string.Format("SELECT Id FROM {0} limit 100", x.name));
if(test == null || test.records == null)
{
Console.WriteLine("{0}:null records", x.name);
continue;
}
foreach (var record in test.records)
{
output.WriteLine("{0}\t{1}",x.name, record.Id);
}
Console.WriteLine("{0}:\t{1} records(0)", x.name, test.size);
}
}
output.Flush();
}

How to Add a command/SQL statement to a strongly typed TableAdapter's Update/Insert command?

See this question. I have the following code that executes against a SQLIte database using a strongly typed dataset.
messagesAdapter.Update(messages);//messages is a DataTable
var connection = messagesAdapter.Connection;
var retrieveIndexCommand= connection.CreateCommand();
retrieveIndexCommand.CommandText = #"Select last_insert_rowid()";
connection.Open();
var index = retrieveIndexCommand.ExecuteScalar();
connection.Close();
This does not work as the last_inser_rowid() always returns zero. This caused by the fact that it needs to be called during the same connection that is used by the TableAdapter's Update command. How can I change the the TableAdapter's Insert or Update command so that it return the index?
If you are inserting a single row, you can use this:
// cast if necessary
using (var insert = (SQLiteCommand)this.Adapter.InsertCommand.Clone()) {
insert.CommandText += "; SELECT last_insert_rowid()";
foreach (SQLiteParameter parameter in insert.Parameters) {
parameter.Value = row[parameter.SourceColumn];
}
}
var index = Convert.ToInt32(insert.ExecuteScalar());
You can also use it to insert multiple rows and assign your id to each one:
using (var insert = (SQLiteCommand)this.Adapter.InsertCommand.Clone())
{
insert.CommandText += "; SELECT last_insert_rowid()";
// this filter only added rows
foreach (MyDataSet.MessageRow row in messages.GetChanges(DataRowState.Added))
{
foreach (SQLiteParameter parameter in insert.Parameters)
{
parameter.Value = row[parameter.SourceColumn];
}
// use the name of your rowid column
row.ID = Convert.ToInt32(insert.ExecuteScalar());
row.AcceptChanges();
}
}
// then you can perfom the other updates
messagesAdapter.Update(messages);
Note: Be sure to open / close your connection

Resources