I am working on application using Entity Framework, WPF, C# with a local sql-server database (two tables : Patient and MedicalSheet). while updating a record I have an exception that says :
A first chance exception of type 'System.Data.Entity.Infrastructure.DbUpdateConcurrencyException' occurred in EntityFramework.dll
Additional information: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
My DAL code looks like :
public static void UpdatePatient(Patient patient)
{
using (context ctx = new context())
{
ctx.Entry(patient).State = EntityState.Modified;
ctx.SaveChanges();
}
}
I have an update button for each row in the dataGrid, once clicking on it, it instanciate an new window that loads data from dataGrid into multiple textBoxes, the event handler of the update button looks like this :
private void EditInDatagrid_btn(object sender, RoutedEventArgs e)
{
new ModernDialog
{
Title = "Update patient DataGrid",
Content = new EditPatient((Patient)patientGrid.SelectedItem){
Width = 600,
Height = 400
},
}.ShowDialog();
}
The UserControl of the new update window (that pops-up after clicking the update button) code looks like :
public partial class EditPatient : UserControl
{
Patient patient = new Patient();
public EditPatient(Patient patient)
{
InitializeComponent();
fNameBoxEditing.Text = patient.firstName;
lNomBoxEditing.Text = patient.lastName;
.....
}
private void ValiderEditing_btn(object sender, RoutedEventArgs e)
{
patient.firstName = PrenomBoxEditing.Text;
patient.lastName = NomBoxEditing.Text;
PatientDAL.UpdatePatient(patient);
MessageBoxButton btn = MessageBoxButton.OK;
ModernDialog.ShowMessage("Patient infos modified succeeded!", "", btn);
}
}
add this.patient = patient into EditPatient constructor
Related
I have these 3 relevant tables below :
I have a form. Say it is called fmEditPurchase. Inside that form, I can edit Purchase informations, and add / delete PurchasedProduct.
There can be many changes in that form, but the changes will only be applied if I click on the save button, which returns DialogResult.OK to parent form. Below method is located in the main form.
private void Purchase_EditPurchase(object sender, DataGridViewCellEventArgs e)
{
if (dgvPurchase.SelectedRows.Count == 1)
{
int index = dgvPurchase.SelectedCells[0].RowIndex;
DataGridViewRow selectedRow = dgvPurchase.Rows[index];
int id = (int)selectedRow.Cells["ID"].Value;
Purchase edit = null;
using (var context = new dbKrunchworkContext())
{
edit = context.Purchases.Where(x => x.ID == id).FirstOrDefault();
if (edit != null)
{
fmAddEditPurchase editForm = new fmAddEditPurchase(edit);
if (editForm.ShowDialog() == DialogResult.OK)
{
//Section 1
foreach (var item in editForm.DeletedPP)
{
context.Entry(item).State = EntityState.Deleted;
context.Entry(item.Product).State = EntityState.Unchanged;
}
//Section 2
context.Entry(editForm.Purchase).State = EntityState.Modified;
//Section 3
foreach (var item in editForm.Purchase.PurchasedProducts)
{
context.Entry(item.Product).State = EntityState.Unchanged;
}
tslbMessage.Text =
string.Format("Product Data Edited");
context.SaveChanges();
Purchase_RefreshDGVPurchase();
}
}
}
}
}
So, to summarize, the changes on a particular Purchase record can include the removal / addition of PurchasedProduct and every other fields, which everything will be applied at eafter the Save button is pressed.
The problem is, when I'm editing, and removing a PurchasedProduct and saving, below error popped up.
The problem persist even after I rearrange the order of section 1, 2, and 3 (Look at top code to see where are the section 1,2,3, which are marked in the comments.).
I also can't do the SaveChanges() in the fmEditPurchase, since it's able to be cancelled to make 0 changes.
How to fix it? Thanks
According to your comment:
a purchase record can't have 2 PurchasedProduct record with a same
product (just add the quantity instea)
You don't need to set the PK to Product_ID. FK should be enough. If you wanna increase the quantity just look for the record searching by Product_ID, update it and save. In that way deleting will be possible.
Finally solved it, while Rodolfo's answer contribute to the solution, but it's not enough.
These are what I did :
I add my database context as parameter to the edit dialog constructor, and also a field inside that to store the context.
private dbKrunchworkContext context;
public fmAddEditPurchase(dbKrunchworkContext context)
{
//Bla bla
this.context = context;
//Bla bla
}
Before I initialize & show the dialog, I initialize the context using using(var context = new dbKrunchworkContext) { } and pass the value to the dialog.
using (var context = new dbKrunchworkContext())
{
edit = context.Purchases.Where(x => x.ID == id).FirstOrDefault();
if (edit != null)
{
fmAddEditPurchase editForm = new fmAddEditPurchase(context, edit);
if (editForm.ShowDialog() == DialogResult.OK)
{
//Blabla
}
}
}
In the new dialog, every time I'm going to use a context, I use the context field instead of using a newly instatiated one.
private void RefreshPurchasedProduct()
{
BindingSource bi = new BindingSource();
//Bla bla
bi.DataSource = Purchase.PurchasedProducts.
Join(context.Products, x => x.Product.ID, y => y.ID, (x, y) =>
new { y.Product_Name, x.Price, x.Quantity }).ToList();
//Bla bla
}
This way, there'll be no (annoying) The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
Hope this helps anyone stumbled upon this similar problem of mine.
P.S. Some of the solution out there may prefer solve it with the static context, never tried it, but if me, I prefer this way, since it'll be cleaner this way, and less code to maintain.
I have a database consist of 3 column which are Id(int), Title(nvarchar) and Description(nvarchar). I added a new column name more(nvarchar) and generated a new database context to replace the old one. I am not able to run my application after adding a new column. What am I missing? Thanks
Below is the error message:
A first chance exception of type 'System.Data.SqlServerCe.SqlCeException' occurred in Microsoft.Phone.Data.Internal.ni.dll
Extra:
After removing the new column more(nvarchar), and regenerated a new database context to replace it again, it works as normal. Meaning its back as the old one without adding a new column to the table.
Below is some code for the MainPage.xaml.cs:
namespace PhoneApp
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// Set the data context of the LongListSelector control to the sample data
DataContext = App.ViewModel;
// Sample code to localize the ApplicationBar
//BuildLocalizedApplicationBar();
}
// Load data for the ViewModel Items
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
using (DatabaseContext c = new DatabaseContext(DatabaseContext.ConnectionString))
{
c.CreateIfNotExists();
c.LogDebug = true;
//output todolist data from database
MLongListSelector.ItemsSource = c.ToDoList.ToList();
}
}
// Handle selection changed on LongListSelector
private void MainLongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If selected item is null (no selection) do nothing
if (MLongListSelector.SelectedItem == null)
return;
//select the item selected from the class.property
var title = (MLongListSelector.SelectedItem as PhoneApp.ToDoList).Title;
var desc = (MLongListSelector.SelectedItem as PhoneApp.ToDoList).Description;
var id = (MLongListSelector.SelectedItem as PhoneApp.ToDoList).Id;
//send data through Title and Desc
NavigationService.Navigate(new Uri("/ToDoDetailPage.xaml?Title=" + title + "&Desc=" + desc + "&Id=" + id, UriKind.Relative));
// Navigate to the new page
//NavigationService.Navigate(new Uri("/ToDoDetailPage.xaml", UriKind.Relative));
// Reset selected item to null (no selection)
MLongListSelector.SelectedItem = null;
}
private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var si = MainLongListSelector.SelectedItem as PhoneApp.ViewModels.ItemViewModel;
if (MainLongListSelector.SelectedItem == null)
return;
if (si.LineOne.Equals("+ To Do List"))
NavigationService.Navigate(new Uri("/todolistPage.xaml", UriKind.Relative));
else if (si.LineOne.Equals("+ Reminder"))
NavigationService.Navigate(new Uri("/reminderPage.xaml", UriKind.Relative));
// Reset selected item to null (no selection)(//important)
MainLongListSelector.SelectedItem = null;
}
}
}
I ran into a similar issue. As far as I could tell the issue is attempting to modify the schema against an existing database. In my case the code does not initialize the DB if it already exists.
if (db.DatabaseExists() == false)
{
// Create database.
db.CreateDatabase();
}
...so the schema changes were not reflected, resulting in a null reference when selecting the new column. I resolved by restarting the phone emulator which removed the previous db file.
I have a Web Form application using VS2013 and Entity Framework 6. Just upgraded from VS2012 and EF5 with no changes required.
There is an article editor form that once an item is inserted, will redirect the user to another form by Id. (Like a wizard)
Inserting records works without issue. The problem is capturing the new record Id. InsertItem does return the new Id from the DB.
I have tried creating an event handler which does not seem to have the value.
Any idea how to capture the returned Id? Alternatives will be appreciated.
Thanks in advance.
// Web Form ArticleEditor code behind
public partial class ArticleEditor : System.Web.UI.Page
{
// page level variables
private readonly IArticleRepository _repository = new ArticleRepository();
// more stuff here
frmArticle_OnItemInserted(object sender, formViewInsertedEventArgs e)
{
// I assume the value can be captured here???
}
// FormView
<asp:FormView runat="server" ID="frmArticle" RenderOuterTable="True"
ItemType="WebApplication.BLL.Model.Article" DataKeyNames="ArticleId"
DefaultMode="ReadOnly"
SelectMethod="GetItem"
InsertMethod="InsertItem"
UpdateMethod="UpdateItem"
DeleteMethod="DeleteItem"
OnItemInserted="frmArticle_OnItemInserted"
CssClass="FormView">
<InsertItemTemplate>
// controls here
</InsertItemTemplate>
</FormView>
// repository ArticleRepository
private readonly AppDbContext _db = new AppDbContext();
public int InsertItem(ModelMethodContext modelMethodContext)
{
// create new model object
var obj = new Article();
// attempt to save model
modelMethodContext.TryUpdateModel(obj);
if (!modelMethodContext.ModelState.IsValid)
{
// model is in an invalid state
return 0;
}
_db.Articles.Add(obj);
_db.SaveChanges();
return obj.ArticleId;
}
I'm still in the learning Phase of WPF, EF and MVVM and now I got the following problem. I can delete and insert new items in my DataGridView but I don't know how to update my items.
All I do is select an emptyrow which already has a primary key and then I put the data into it. It's working (updating database) but the GridView is not refreshing. I Need to restart the program first to see my updated data.
My Execute Command to Update my Database. I'm in the ViewModel class
public void ExecuteUpdate(object obj)
{
try
{
SelectedIndex.Child_Update(new Farbe { FarbauswahlNr = SelectedIndex.FarbauswahlNr, Kurztext = SelectedIndex.Kurztext, Ressource = SelectedIndex.Ressource, Vari1 = SelectedIndex.Vari1, Vari2 = SelectedIndex.Vari2 });
//ListeAktualisieren --> Refreshing the List
ListeAktualisieren();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
Here is my Refresh Method which SHOULD Refresh the GridView. I'm in the ViewModel class
public void ListeAktualisieren()
{
farbliste.ListeAktualisieren(db);
farbliste.Model = farbliste.Model.Concat(farbliste.Addlist).ToList();
Model = farbliste.Model;
farbliste.Addlist.Clear();
}
The method is calling my Business List which also got a Refresh Method. Reading from my database here. I'm in the Business List class
public void ListeAktualisieren(TestDBEntities db)
{
Model.Clear();
foreach (var item in db.Farben)
{
//Insert and delete working
add = new Farbe { FarbauswahlNr = item.FarbauswahlNr, Kurztext = item.Kurztext, Ressource = item.Ressource, Vari1 = Convert.ToBoolean(item.Var1), Vari2 = item.Vari2 };
Addlist.Add(add);
}
}
Model is the Source of my GridView which is not Refreshing changed data when Updated but is showing new data rows when inserting or deleting.
You need Observablecollections and Classes with implemented INotifyPropertyChanged. Add the new element to the Observablecollection by insert and raise the event propertychanged by a change.
The rest should be done by WPF.
Edit: The Sourcecollection for the DataGrid needs to be the Observablecollection.
Edit2: To be nice I put the result of the comments here ;-)
Each row of the DataGrid is an element of the collection. Each cell of one row listens to a PropertyChangedEvent of its element (the String is Casesensitive so be carefull). If the getter of the property isn't called after the propertychangedevent the binding didn't receive the event.
This piece of Code can help asure that you don't call with nonexistent strings:
private void VerifyPropertyName(string PropertyName)
{
if (string.IsNullOrEmpty(PropertyName))
return;
if (TypeDescriptor.GetProperties(this)(PropertyName) == null) {
string msg = "Ungültiger PropertyName: " + PropertyName;
if (this.ThrowOnInvalidPropertyName) {
throw new isgException(msg);
} else {
Debug.Fail(msg);
}
}
}
Try adding this to your binding section
ItemsSource="{Binding Path=Model, UpdateSourceTrigger= PropertyChanged"}
i am newbie of c# and win phone 7
i create a simple database i read this example
http://f5debug.net/2012/02/26/learn-windows-phone-7-development-in-31-days-day-26-working-with-creating-a-local-database-in-wp7/
i open Db in Mainpage
public partial class MainPage : PhoneApplicationPage
{
// short connection string format
private const string strConnectionString = #"isostore:/ManutenzioneDB.sdf";
// Costruttore
public MainPage()
{
InitializeComponent();
using (SampleData.EventoDataContext Empdb = new SampleData.EventoDataContext(strConnectionString))
{
// se il db non esiste creo il db
if (Empdb.DatabaseExists() == false)
{
Empdb.CreateDatabase();
// MessageBox.Show("Employee Database Created Successfully!!!");
}
}
now in Main page i create a button than open an other page
private void button1_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/InsertData.xaml", UriKind.Relative));
}
now i don't know can access to Db from InsertData page (InsertData.xaml.cs),
best regads
Antonio
Simpler than you think. :)
var db = new SampleData.EventoDataContext();
db.MyTable.InsertOnSubmit(new MyTable() { ... });
db.Submit();
"MyTable" is the name of the table you defined inside the database.
Make sure you define a primary key, or inserting into the table will fail.
You will need to initialize your table inside the {...} part.
To get items from the table:
foreach (var item in db.MyTable.Where(x => x.SomeProp == 1))
{
//…
}
This will return all the rows where SomeProp is 1. You can now inspect item to see what the row contains.
Try to study the vici cool stored procedure. It is very very simple to create, add, and retrieve data from any db in WP7 applications
http://viciproject.com/wiki/projects/coolstorage/home