Dapper Bulk Delete how to report progress - dapper

I am using Dapper Plus to do a bulk insert using a query from another table my question is here how does one report progress. As you see I am using the background worker process to run my code which works fine however as the bulk delete method does not have a reportprogress event how would I handle this.
public StockDeativationForm()
{
InitializeComponent();
this._backgroundWorker.DoWork += new DoWorkEventHandler(this.BackgroundWorkerDoWork);
this._backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(this.BackgroundWorkerProgressChanged);
this._backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.BackgroundWorkerRunWorkerCompleted);
}
private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
ProcessStockItems();
}
private void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar2.Value = e.ProgressPercentage;
}
private void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.CompleteProcess();
}
private void CompleteProcess()
{
MessageBox.Show("Stock items Deleted", "Stock Item Delete", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
base.Close();
}
public StockDeativationForm()
{
InitializeComponent();
this._backgroundWorker.DoWork += new DoWorkEventHandler(this.BackgroundWorkerDoWork);
this._backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(this.BackgroundWorkerProgressChanged);
this._backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.BackgroundWorkerRunWorkerCompleted);
}
private void ProcessStockItems()
{
string conStr = ConfigurationManager.AppSettings["DeleteStock"];
using (var connection = new SqlConnection(conStr))
{
DialogResult _dialogResult = MessageBox.Show(null, "Are you sure you want to delete stock? This will delete all stock items", "Delete Stock", MessageBoxButtons.YesNo);
if (_dialogResult == DialogResult.Yes)
{
connection.BulkDelete(connection.Query<StockItems>("Select ItemID FROM StockItem").ToList());
}
}
}
How does one report progress back using this method of bulkdelete
connection.BulkDelete(connection.Query<StockItems>("Select ItemID FROM StockItem").ToList());

Disclaimer: I'm the owner of Dapper Plus
You are right,
Perhaps using the log event could work?
StringBuilder log = new StringBuilder();
connection.UseBulkOptions(options => options.Log = s => {
if(s.Contains("...xyz...")) {
log.AppendLine(s);
}
}).BulkDelete(connection.Query<StockItems>("Select ItemID FROM StockItem").ToList());
Another solution will be to report this request to our support team and ask for a Report Progress/Notify event.

Related

Pass operation from user control to Worker_DoWork in other window

I am just new woking with ProgressBar in WPF. I have a user control like this:
public partial class Import : UserControl
{
public Import()
{
InitializeComponent();
}
private void filePickerButton_Click(object sender, RoutedEventArgs e)
{
// Create the OpenFIleDialog object
Microsoft.Win32.OpenFileDialog openPicker = new Microsoft.Win32.OpenFileDialog();
// Add file filters
// We are using excel files in this example
openPicker.DefaultExt = ".xslt";
openPicker.Filter = "Excel Files|*.xls;*.xlsx;*.xlsm";
// Display the OpenFileDialog by calling ShowDialog method
Nullable<bool> result = openPicker.ShowDialog();
// Check to see if we have a result
if (result == true)
{
// Application now has read/write access to the picked file
filePathTextBox.Text = openPicker.FileName.ToString();
}
}
private void btn_Import_Click(object sender, RoutedEventArgs e)
{
//import all data from excel file to datatable
Workbook wb = new Workbook(filePathTextBox.Text);
// Accessing the worksheet in the Excel file
Worksheet worksheetPro = wb.Worksheets[1];
Worksheet worksheetCat = wb.Worksheets[0];
// Exporting all data by ExportDataTable
DataTable dataTablePro = worksheetPro.Cells
.ExportDataTable(1, 0, worksheetPro.Cells.Rows.Count - 1, worksheetPro.Cells.Columns.Count, false);
DataTable dataTableCat = worksheetCat.Cells
.ExportDataTable(1, 0, worksheetCat.Cells.Rows.Count - 1, worksheetCat.Cells.Columns.Count, false);
//dump data from datatable to SQL server
string connectionString = #"Data Source=DESKTOP-L6OBVA4\SQLEXPRESS;Initial Catalog=QLDB;Integrated Security=True";
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
{
//mapping columns of Datatable with the name of DB
bulkCopy.ColumnMappings.Add(dataTablePro.Columns[0].ColumnName, "Tên");
bulkCopy.ColumnMappings.Add(dataTablePro.Columns[1].ColumnName, "Giá");
bulkCopy.ColumnMappings.Add(dataTablePro.Columns[2].ColumnName, "Số Lượng");
bulkCopy.ColumnMappings.Add(dataTablePro.Columns[3].ColumnName, "Miêu Tả");
//set the destination table name in DB will be affected
bulkCopy.DestinationTableName = "dbo.Products";
try
{
//coppy all rows from nominated datatable and dump it to DB
bulkCopy.WriteToServer(dataTablePro);
dataTablePro.Clear();
using (SqlBulkCopy bulkCopyCat = new SqlBulkCopy(connection))
{
bulkCopyCat.ColumnMappings.Add(dataTableCat.Columns[0].ColumnName, "Loại");
bulkCopyCat.DestinationTableName = "dbo.Categories";
bulkCopyCat.WriteToServer(dataTableCat);
dataTableCat.Clear();
MessageBox.Show("Success!!!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
The purpose of this user control is: Choose an excel file, then import all data to datatable, finally, dump all data to SQL server. I need to make a processing bar for operation of dumping from datatable to SQL server cause I think it takes long time. So next thing, I create a Process bar window:
public partial class ProgressBar : Window
{
public ProgressBar()
{
InitializeComponent();
}
private void Window_ContentRendered(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += worker_DoWork;
worker.ProgressChanged += worker_ProgressChanged;
worker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
(sender as BackgroundWorker).ReportProgress(i);
//do my operation here
}
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbStatus.Value = e.ProgressPercentage;
}
}
you can see above snippet code, I have a method named:
worker_DoWork()
it is where I plan to put my operation. And the last thing, I want to take these code lines from user control then put it into worker_DoWork() cause I think these lines take time to handle:
try
{
//coppy all rows from nominated datatable and dump it to DB
bulkCopy.WriteToServer(dataTablePro);
dataTablePro.Clear();
using (SqlBulkCopy bulkCopyCat = new SqlBulkCopy(connection))
{
bulkCopyCat.ColumnMappings.Add(dataTableCat.Columns[0].ColumnName, "Loại");
bulkCopyCat.DestinationTableName = "dbo.Categories";
bulkCopyCat.WriteToServer(dataTableCat);
dataTableCat.Clear();
MessageBox.Show("Success!!!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
what should I do to get it? I heard about delegate and event can give me a choice but i could not find it out by myself. Thanks!
If you do not care about multiple instances of progress dialog. Then try something like this:
Import.xaml:
<Grid>
<Button x:Name="filePicker" Content="ClickMe" Click="filePicker_Click" DockPanel.Dock="Top"/>
<ProgressBar x:Name="progressBar" Minimum="0" Maximum="100" Value="75" DockPanel.Dock="Top" Visibility="Collapsed" />
</Grid>
Import.xaml.cs:
private void filePicker_Click(object sender, RoutedEventArgs e)
{
progressBar.Visibility = Visibility.Visible;
// here you call your batch code
var task = new Task(() => Thread.Sleep(3000));
// after task is done hide progress dialog
task.ContinueWith(x => Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => this.progressBar.Visibility = Visibility.Collapsed)));
task.Start();
}
(I did not bother with updating the status. It is always 75%.).

How can I update my WinForm label on timer?

I can't update my WinForm label properties.
Details: I am trying to check my database and get some values posted, but I can't even update a mere label it seems. I'm using SharpDevelop.
The code:
//this is my form
public partial class MainForm : Form
{
//Declaring timer
public static System.Timers.Timer aTimer = new System.Timers.Timer();
public MainForm()
{
InitializeComponent();
//Timer
aTimer.Elapsed +=new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 2000; //milisecunde
aTimer.Enabled = true;
label1.Text="some_text";
}
private static void OnTimedEvent(object source, ElapsedEventArgs e) {Check();}
public static void Check()
{
//Database checks here..
try{label1.Text="new_text";}catch(Exception e) {MessageBox.Show(e.ToString());}
MessageBox.Show("BAAAA");
}
void Button1Click(object sender, EventArgs e)
{
label1.Text = "mergeeeeee?!";
}
}
EDIT: I've removed all static modifiers. Also updated the post with the new code (try catch is added and the messagebox after it + a button that changes the label).
The try catches the following error:
. Really could use some help, been researching answers for more than 6 hours.
Try this (use a System.Windows.Forms.Timer instead of System.Timers.Timer):
//Declaring timer
public System.Windows.Forms.Timer aTimer = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
//Timer
aTimer.Tick += aTimer_Tick;
aTimer.Interval = 2000; //milisecunde
aTimer.Enabled = true;
label1.Text = "some_text";
}
void aTimer_Tick(object sender, EventArgs e)
{
Check();
}
public void Check()
{
try
{
//Database checks here..
label1.Text = string.Format("new_text {0}", DateTime.Now.ToLongTimeString());
}
catch (Exception ex)
{
throw ex;
}
MessageBox.Show("BAAAA");
}
The Elapsed event of the System.Timers.Timer is fired on a non-UI thread (change your original code to not swallow exceptions and you should see the cross-thread exception).
I used the following code for my project and it worked.
It has a button to activate the timer and the timer raises an event when 500 milliseconds passed.
private void ActiveTimer_Click(object sender, EventArgs e)
{
EnableTimer();
}
private void EnableTimer()
{
System.Timers.Timer raiseTimer = new System.Timers.Timer();
raiseTimer.Interval = 500;
raiseTimer.Elapsed += RaiseTimerEvent;
raiseTimer.AutoReset = true;
raiseTimer.Enabled = true;
}
private void RaiseTimerEvent(object sender, System.Timers.ElapsedEventArgs e)
{
this.Invoke(new Action(() =>
{
label1.Text += "500 ms passed\n";
}));
}

Deleting from a Data Grid View

I have created a windows form application. I want this application to be able to use Linq to SQL to search for a record, and then for that record to be selected from a data grid view and deleted.
The form contains a textbox to enter the parameter, a search button and a delete button and a datagrid.
I have the search part working correctly and the data grid is populated but don't know how to implement clicking on the record in the data grid and deleting it.
Update - I have solved the solution. Changes have only been made to the btn_Delete_Click event handler so I have included the updated code for his button after the main code.
namespace DeleteForm
{
public partial class Form1 : Form
{
LinqtoStudentDataContext linqStud = new LinqtoStudentDataContext();
public Form1()
{
InitializeComponent();
}
private void btnDelete_Click(object sender, EventArgs e)
{
}
private void btnSearch_Click(object sender, EventArgs e)
{
var lastName = from stud in linqStud.Students
where txtFind.Text == stud.LastName
select stud;
dataGridView1.DataSource = lastName;
}
}
}
Updated code -
private void btnDelete_Click(object sender, EventArgs e)
{
if (this.dataGridView1.SelectedRows.Count > 0)
{
dataGridView1.Rows.RemoveAt(this.dataGridView1.SelectedRows[0].Index);
//linqStud.Students.DeleteAllOnSubmit();
linqStud.SubmitChanges();
}
}
First, set selection mode of DataGridView to FullRowSelect. Next, when assigning DataSource you should call ToList() - you can't use query as data source:
private void btnSearch_Click(object sender, EventArgs e)
{
var lastName = txtFind.Text;
var students = from stud in linqStud.Students
where stud.LastName == lastName
select stud;
dataGridView1.DataSource = students.ToList();
}
Get selected rows, and remove databound items (students) from context:
private void btnDelete_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.SelectedRows)
{
var student = row.DataBoundItem as Student;
linqStud.Students.Remove(student);
linqStud.SaveChanges();
}
}

DataGridView CRUD Operation with LINQ to SQL

I have a datagridview with BindingSource to Linq to SQL as datasource. When I try to insert or delete the data, the gridview is not refreshed.
SampleDataContext context = new SampleDataContext();
BindingSource bindingSource = new BindingSource();
public Form1()
{
InitializeComponent();
bindingSource.DataSource = context.Persons;
PersonGridView.DataSource = bindingSource;
}
private void AddButton_Click(object sender, EventArgs e)
{
context.Persons.InsertOnSubmit(new Person { Name = , Address = });
context.SubmitChanges();
}
private void DeleteButton_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in PersonGridView.SelectedRows)
{
var person = context.Persons.FirstOrDefault(x => x.ID == int.Parse(row.Cells[0].Value.ToString()));
context.Persons.DeleteOnSubmit(person);
}
context.SubmitChanges();
}
Am I missing something here ?
Best Regards,
Brian
Viola after try many solutions I Have a better solution just change insert and delete operation to bindingsource
SampleDataContext context = new SampleDataContext();
BindingSource bindingSource = new BindingSource();
public Form1()
{
InitializeComponent();
bindingSource.DataSource = context.Persons;
PersonGridView.DataSource = bindingSource;
}
private void AddButton_Click(object sender, EventArgs e)
{
bindingSource.Add(new Person { Name = "Hello", Address = "Hahahaha123" });
context.SubmitChanges();
}
private void DeleteButton_Click(object sender, EventArgs e)
{
foreach (DataGridViewRow row in PersonGridView.SelectedRows)
{
var person = context.Persons.FirstOrDefault(x => x.ID == int.Parse(row.Cells[0].Value.ToString()));
bindingSource.Remove(person);
}
context.SubmitChanges();
}

Silverlight Datagrid Refresh

So I have a datagrid in Silverlight that is bound to a WCF that populates a list of class. I basically a pass a parameter to a Linq query. When I do a second query I get double the results, a third triple and so forth. What can I do to make it so when I send a call out to the service that I only get one set of results. I have attached my code in case it helps anyone.
private void button1_Click(object sender, RoutedEventArgs e)
{
dgOrder.ItemsSource = null;
Uri address = new Uri(Application.Current.Host.Source, "../Services/Service1.svc");
//var client = new Services.dataserviceClient("CustomBinding_dataservice", address.AbsoluteUri);
var client = new ServiceReference2.Service1Client("CustomBinding_Service1", address.AbsolutePath);
client.GetOrderCompleted += (s, ea) =>
{
dgOrder.AutoGenerateColumns = false;
//dgOrder.ColumnWidth.Value = 100;
dgOrder.Columns.Add(CreateTextColumn("SKU", "SKU"));
dgOrder.Columns.Add(CreateTextColumn("productname", "Product Name"));
dgOrder.Columns.Add(CreateTextColumn("itemnumber", "Item Number"));
dgOrder.Columns.Add(CreateTextColumn("cost", "Cost"));
dgOrder.Columns.Add(CreateTextColumn("asin", "ASIN"));
dgOrder.Columns.Add(CreateTextColumn("pendingorder", "Rank"));
dgOrder.Columns.Add(CreateTextColumn("rank", "Node"));
//dgOrder.Columns.Add(CreateTextColumn("w4", "AMZN"));
dgOrder.Columns.Add(CreateTextColumn("amazon", "AMZN"));
dgOrder.Columns.Add(CreateTextColumn("ourprice", "OurPrice"));
dgOrder.Columns.Add(CreateTextColumn("bbprice", "BuyBox"));
dgOrder.Columns.Add(CreateTextColumn("afner", "AFN"));
dgOrder.Columns.Add(CreateTextColumn("quantity", "INV"));
dgOrder.Columns.Add(CreateTextColumn("w4", "W4"));
dgOrder.Columns.Add(CreateTextColumn("w3", "W3"));
dgOrder.Columns.Add(CreateTextColumn("w2", "W2"));
dgOrder.Columns.Add(CreateTextColumn("w1", "W1"));
dgOrder.Columns.Add(CreateTextColumn("order", "Order"));
dgOrder.Columns.Add(CreateTextColumn("total", "Total"));
dgOrder.Columns.Add(CreateTextColumn("profit", "Profit"));
dgOrder.Columns.Add(CreateTextColumn("percent", "Percent"));
dgOrder.Columns.Add(CreateHyperlink("asin"));
dgOrder.ItemsSource = ea.Result;
Original = ea.Result;
};
client.GetOrderAsync(txtCompany.Text);
}
The problem is , you are creating a new(duplicate) event handler every time you press the Button. Due to having an extra event for each button pres you do, you get extra sets of data. You need to create your Event.Completed method outside the Button.Cliked event.
To clarify:
public partial class NewPage : Page
{
Uri address = new Uri(Application.Current.Host.Source, "../Services/Service1.svc");
ServiceReference2.Service1Client client = new ServiceReference2.Service1Client("CustomBinding_Service1", address.AbsolutePath);
public NewPage()
{
client.GetOrderCompleted += (s, ea) =>
{
//YOUR CODE
};
}
private void button1_Click(object sender, RoutedEventArgs e)
{
dgOrder.ItemsSource = null;
client.GetOrderAsync(txtCompany.Text);
}
}

Resources