How to write bulkify trigger - testing

How to resolve this?
trigger notedate on Note (After insert) {
Id pId;
datetime createdate;
for(note notedet : trigger.new){
pId= notedet.ParentId;
createdate = notedet.LastModifiedDate;
}
contact con =[select id,Last_Activity_Date__c from contact where id =:pId ];
con.Last_Activity_Date__c = createdate ;
update con;
system.debug('con++'+con);
}

Related

Dapper for NET Core: Insert into a table and return id of inserted row [duplicate]

This question already has answers here:
How do I perform an insert and return inserted identity with Dapper?
(9 answers)
Closed 6 months ago.
I have the following method in my repository. As of now, i believe the int returned is simply one indicating whether or not the operation was successful. I want the int to be the id (which is the single column of the table) to be returned after a successful execution. How do i accomplish this?
public async Task<int> AddNewGroup()
{
using(_connection)
{
_connection.Open();
var id = await _connection.ExecuteAsync("INSERT INTO groups").Single();
}
}
You can run a query which has 2 parts, first is your INSERT part and second is a SELECT part. In the SELECT part, you can return(select) whatever column value you want.
For example, If your group table has a primary key column called GroupId and you have set that column for Identity value generation(automatic value generation), you can call the SCOPE_IDENTITY() to get the generated value.
We will use the QueryAsync method.
public async Task<int> AddNewGroup()
{
using(_connection)
{
_connection.Open();
var q = #"INSERT INTO Groups(Name,Description) VALUES
(#name, #desc); SELECT CAST(SCOPE_IDENTITY() as int)"
var result = await _connection.QueryAsync<int>(q,
new { #name="some name", #desc="some desc"});
return result.Single();
}
}
You don't have to create by hand the insert query, you can use Dapper.Contrib github which helps you to manage CRUD operations.
Using Dapper.Contrib you can do something like:
public async Task<int> AddNewGroup(Group entity)
{
using (_connection)
{
_connection.Open();
var id = await _connection.InsertAsync(entity);
}
}
If you're using SQL Azure / SQL Server, you need to return the inserted value from the query using something like
INSERT INTO groups OUTPUT inserted.id VALUES (...)
and then instead using ExecuteAsync use ExecuteScalarAsync
Reference to the OUTPUT clause here:
https://learn.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql?view=sql-server-2017
public static void Main()
{
string sql = #"INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country)
Values (#CustomerName, #ContactName, #Address, #City, #PostalCode, #Country);
SELECT CustomerID FROM Customers WHERE CustomerID = SCOPE_IDENTITY();";
using (var connection = new SqlConnection(GetConnectionString()))
{
Customer c = new Customer("Brian Adams", "Brian", "12 Jones Place", "New York", "NY12", "CA");
var id = connection.QueryFirstOrDefault<int>(sql, c);
Console.WriteLine("The Customer ID is " + id);
sql = "Select * FROM CUSTOMERS WHERE CustomerID = #ID";
var rc = connection.QueryFirstOrDefault<Customer>(sql, new{ #ID = id });
}
}
}
The "correct" way that I took is (Showing repository method using Guid Id to return):
public async Task<Guid> CreateClient(ClientEntity clientModel)
{
const string sql = #"
INSERT INTO dbo.Clients
(
ClientCode,
Name,
IsActive
)
OUTPUT Inserted.ClientId
VALUES
(
#ClientCode,
#Name,
#IsActive
)";
using var dbConnection = await _databaseProvider.GetConnection();
var result = await dbConnection.ExecuteScalarAsync(sql, new
{
ClientCode = clientModel.Code,
Name = clientModel.Name,
IsActive = clientModel.IsActive
});
if (result != null)
{
return Guid.Parse(result.ToString());
}
else {
return Guid.Empty;
}
}
You can use the RETURNING id in the insert statement. This is using C# and dapper.
private readonly NpgsqlConnection _connection = new NpgsqlConnection();
var sqlInsert = $""""
INSERT INTO tabel_name (column_name)
VALUES ('value')
RETURNING id;
"""";
var id = await _connection.ExecuteScalarAsync(sqlInsert);
And if you want to determine the key type coming back you can use:
var id = await _connection.ExecuteScalarAsync<int>(sqlInsert);
Where you specify the type in the <> brackets. If you do not specify, it will return the object type.

Update SQL table very slow

I have problem when I try to update SQL table with
I have datagridview and I need to update SQL table and take the value form my datagridview . my datagridview have more than 10000 rows
I take time more than 1:30 hour very slow
datagridview name "dgv_balance"
Here is the code:
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString = "My Connection"
cn.Open();
using (SqlCommand cmd_select = new SqlCommand())
{
for (int i = 0; i < dgv_balance.RowCount; i++)
{
cmd_select.Connection = cn;
cmd_select.CommandType = CommandType.StoredProcedure;
cmd_select.CommandText = "clients_balances_select_glid_date";
cmd_select.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_select.Parameters.AddWithValue("#date", Convert.ToDateTime(dgv_balance.Rows[i].Cells[2].Value));
if (cmd_select.ExecuteScalar().ToString()=="")
{
using (SqlCommand cmd_insert = new SqlCommand())
{
cmd_insert.Connection = cn;
cmd_insert.CommandType = CommandType.StoredProcedure;
cmd_insert.CommandText = "clients_balances_insert_data";
cmd_insert.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_insert.Parameters.AddWithValue("#name", Convert.ToString(dgv_balance.Rows[i].Cells[1].Value));
cmd_insert.Parameters.AddWithValue("#date", Convert.ToString(dgv_balance.Rows[i].Cells[2].Value));
cmd_insert.Parameters.AddWithValue("#balance", Convert.ToString(dgv_balance.Rows[i].Cells[3].Value));
cmd_insert.ExecuteNonQuery();
cmd_insert.Parameters.Clear();
}
}
else
{
using (SqlCommand cmd_update= new SqlCommand())
{
cmd_update.Connection = cn;
cmd_update.CommandType = CommandType.StoredProcedure;
cmd_update.CommandText = "clients_balances_update_balance";
cmd_update.Parameters.AddWithValue("#glid", Convert.ToString(dgv_balance.Rows[i].Cells[0].Value));
cmd_update.Parameters.AddWithValue("#date", Convert.ToString(dgv_balance.Rows[i].Cells[2].Value));
cmd_update.Parameters.AddWithValue("#balance", Convert.ToString(dgv_balance.Rows[i].Cells[3].Value));
cmd_update.ExecuteNonQuery();
cmd_update.Parameters.Clear();
}
}
cmd_select.Parameters.Clear();
}
}
}
You may have to call SELECT command for one time only before you loop through your datagridview rows and cache the result data and check on the result while iterating your datagridview instead of calling it on each row. This way you will reduce your commands by 10000.
It also better if you could show us your procedures' queries.
Or if your datagridview is the ONLY source for your data then you can delete all your previous data in your database and make one insert call for all of your datagridview data.
Try this:
using (SqlConnection cn = new SqlConnection())
{
cn.ConnectionString = "MyConnection" ;
cn.Open();
SqlDataAdapter da = new SqlDataAdapter();
DataTable dt = new DataTable();
using (SqlCommand cmd_select = new SqlCommand())
{
cmd_select.Connection = cn; cmd_select.CommandType = CommandType.StoredProcedure; cmd_select.CommandText = "clients_balances_select_glid_date";
da.SelectCommand = cmd_select;
da.Fill(dt);
for (int i = 0; i < dgv_balance.RowCount; i++)
{
if(/* check here if dt contains this row*/)
{
// Insert
}
else
{
// Update
}
}
}
}
I think you should insert or update all data one time.
Create index for glId column. If glId is primary key, it's indexed.
Assumes that List ClientBalance is list items you need update or insert.
public class ClientBalance
{
GlId int {get;set;}
ClientName string {get;set;}
Balance decimal {get;set;}
DateInput DateTime {get;set;}
}
You could serialize list Item to xml string and pass it to store procedure
public string Serialize<T>(T value) where T : new()
{
var serializeXml = string.Empty;
if (value != null)
{
try
{
var xmlserializer = new XmlSerializer(typeof(T));
var stringWriter = new StringWriter();
var writer = XmlWriter.Create(stringWriter);
xmlserializer.Serialize(writer, value);
serializeXml = stringWriter.ToString();
writer.Close();
}
catch (Exception ex)
{
return string.Empty;
}
}
return serializeXml;
}
Create a new store procedure for insert or update item like that:
CREATE PROCEDURE [dbo].[clients_balances_insert_or_update]
(
#xmlObject nvarchar(max)
)
AS
BEGIN
-- TABLE INCLUDE DATE FROM XML
DECLARE #tblBalances AS TABLE
(
GlId int,
DateInput datetime,
ClientName nvarchar(50),
Balance decimal(18,2)
)
DECLARE #idoc int -- xml id
-- PARSE XML TO OBJECT
EXEC sp_xml_preparedocument #idoc OUTPUT, #xmlObject
INSERT INTO #tblBalances
(
GlId, DateInput, ClientName, Balance
)
SELECT s.GlId, s.DateInput, s.ClientName, s.Balance
FROM OPENXML (#idoc, '/ArrayOfClientBalance/ClientBalance', 8) WITH (
GlId int 'GlId',
DateInput datetime 'DateInput',
ClientName NVARCHAR(50) 'ClientName',
Balance DECIMAL(18,2) 'Balance'
) s
EXEC sp_xml_removedocument #idoc
-- USE MERGE FOR INSERT OR UPDATE DATE
-- Use transaction
BEGIN TRAN InsertOrUpdate
BEGIN TRY
MERGE Target AS T
USING #tblBalances AS S
ON (T.GlId = S.GlId)
WHEN NOT MATCHED BY TARGET
THEN INSERT( GlId, DateInput, ClientName, Balance) VALUES( GlId, DateInput, ClientName, Balance)
WHEN MATCHED
THEN UPDATE SET DateInput = S.DateInput, Balance = s.Balance
COMMIT TRAN InsertOrUpdate;
END TRY
BEGIN CATCH
ROLLBACK TRAN InsertOrUpdate;
THROW;
END CATCH
END
Hope this helpfully!

How to insert another table data from select query for exist table

Actually I'm creating one database application where if person first day login then his sales_count will be 1, same person login again then its sales_count will be 2 , same user login next day then its sales_count again 1.
For this I created two tables Login and Sales_Details. In Login I have:
User_name, Password and Unique no.
Now, in sales_details I want to fetch only User_name,Unique_no from login detail but at same time I want to increment sales_count in sales_details table also update today date.
Sales_details has
Sales_id,User_name,Unique_No,Sales_count,To_Date field
Actually I tried but nothing happen if To_date is null then insert today date+sales_count as 1 in sales_details
Below I'm pasting my whole code:
string todaydate = DateTime.Now.ToString("dd/MM/yyyy");
string access = "select To_Date from Sales_Details";
cmd = new OleDbCommand(access, con);
con.Open();
using (OleDbDataReader read = cmd.ExecuteReader()){
while (read.Read()){
string date2 = read["To_Date"].ToString();
if (todaydate == date2){
cmd = new OleDbCommand("update Sales_Details set Sales_count= IIF(IsNull(Sales_count), 0, Sales_count) + 1, [To_Date]=Date() where [Unique_No]=#Unique_No", con);
cmd.Parameters.AddWithValue("#Unique_No", txtinput.Text);
con.Open();
int n = cmd.ExecuteNonQuery();
if (n == 0) {
MessageBox.Show("Invalid Unique No.");
} else {
this.DialogResult = DialogResult.OK;
}
con.Close();
} else {
int counter=1;
cmd = new OleDbCommand("insert into Sales_Details select User_name,Unique_No from Login where Unique_No=#Unique_No Union select ISNULL(Sales_Count+1,0) as [#Sales_Count],DATE() AS [To_date]", con);
cmd.Parameters.AddWithValue("#Unique_No", txtinput.Text);
cmd.Parameters.AddWithValue("#Sales_count",counter);
int n1 = cmd.ExecuteNonQuery();
if (n1 == 0){
MessageBox.Show("Invalid Unique No.");
} else {
this.DialogResult = DialogResult.OK;
}
}
}
}
con.Close();

Deleting the last row in a table. SQL/Netbeans

In java, i am trying to delete the last row of my database. The database has 15 rows and i want to the delete the 15th one. The columns are called Initials and Score.
Intials Scores
rows# 1. ADS 2343
2. DDE 5454
15. TBK 332
I can't have it selecting TBK because i'm wanting it to delete the 15th one no matter what it is so a new one can be added. Everywhere I've looked it's always has to be specific or a delete all rows. Can anyone help? Many thanks to those who help. :)
Assuming id is an identity column
DELETE FROM table
WHERE id = (SELECT MAX(id) FROM table)
OP : I am trying to delete the last row of my database.
make resultset updatable : ResultSet.CONCUR_UPDATABLE);
set cursor to last record : resultSet.last();
delete last Record : resultSet.deleteRow();
for further use of rs you should set : resultSet.beforeFirst();
private static int delLastRow(ResultSet resultSet) {
if (resultSet == null) {
return 0;
}
try {
resultSet.last();
int delID = resultSet.getInt(1);
resultSet.deleteRow();
System.out.println("Deleted id :" + delID);
resultSet.beforeFirst();
return delID;
} catch (SQLException exp) {
exp.printStackTrace();
} finally {
try {
resultSet.beforeFirst();
} catch (SQLException exp) {
exp.printStackTrace();
}
}
return 0;
}
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
//rs will be scrollable, will not show changes made by others,
//and will be updatable
String sql;
sql = "SELECT * FROM `order details`";
ResultSet rs = stmt.executeQuery(sql);
System.out.println("Deleted id :"+ delLastRow(rs));
....
}

How to change this statement to detached criteria

This statement is to check if the user is existing in the database.
public boolean isExisting(int userId) {
String sql = "{call isExistingUser(?)}";
Session session = null;
boolean isExisting = false;
try {
session = getSession();
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0, userId);
List<?> list = query.list();
isExisting = list.get(0) != null ? (Boolean) list.get(0) : false;
} finally {
if (session != null)
session.close();
}
return isExisting;
}
This is the stored procedure:
CREATE DEFINER=cbsadmin#% PROCEDURE isExistingUser(IN userId int)
BEGIN
SELECT USER_ID FROM USER_LOGIN_STATUS WHERE USER_ID = userId;
END
It is not possible to query a Stored procedure using detached criteria in NHibernate.
You need to use SQL query only.
See here.