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;
}
Related
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
I just noticed that I can't refresh the values fetched from the DB. Storage (i.e. from the client to the DB) works as supposed to. Loading the first time works as charm as well.
However, if someone deletes a row in the DB (say, using SQL Management Studio), that change isn't in effect in my client until I reinstantiate the whole view model. Only calling Refresh() doesn't fetch the change. The same goes for altering the values of loaded in records.
However, additions to the table are brought in...
I (re)load the values shown in the view from the DB by calling the following method in the view model.
public ViewModel()
{
Reload();
...
}
public void Reload()
{
_data.Set<Order>().Load();
_data.Set<TimeFrame>().Load();
Orders = _data.Set<Order>().Local;
TimeFrames = _data.Set<TimeFrame>().Local;
...
}
readonly Data _data;
private ObservableCollection<Order> _orders;
private ObservableCollection<TimeFrame> _timeFrames;
public ObservableCollection<Order> Orders
{
get { return _orders; }
set { _orders = value; OnPropertyChanged("Orders"); }
}
public ObservableCollection<TimeFrame> TimeFrames
{
get { return _timeFrames; }
set { _timeFrames = value; OnPropertyChanged("TimeFrames"); }
}
What am I missing?
Here the problem is that you load your values, then you use the local property.
The Local collection contains all the values that have been loaded in your context.
if the first time, you load values (1,2,3,4) your Local collection will contain values (1,2,3,4). The second time you load it, you will perhaps load values (1, 4, 5) your Local collection will contain values (1,2,3,4,5)
you should do something like
Orders = new ObservableCollection(_data.Set<Order>());
if it is a read only scenario and you don't need to update and save your data, you should even load your data AsNoTracking, so you won't have caching issues and you will have less EF overhead as your entities won't be tracked
Orders = new ObservableCollection(_data.Set<Order>().AsNoTracking());
I have a query regarding maintaining a List in between two windows forms. It's for a project where I need to create an address book.
I have chosen to maintain the contact details in the form of a List. My first windows form (form1) contains a master copy of a list AddressBook, which contains the address book.
I hardcoded 4 entries into the address book list in order to experiment and get the simple functions such as 'add' and 'edit' working.
I have a second windows form called Add, in which I can add new entries to the list. This works fine. I can add a new contact in the ADD form and this shows up in the initial form1, master form.
My problem arises in the EDIT form. I pass the AddressBook (master) list to the EDIT form. The EDIT form takes the master list and I am able to manipulate the records in that list. However when it comes to sending back the new list to the master page (form1), it does not pick it up. I am using the same code as I do in the ADD form which successfully sends back the new list. However this code does not work when sending back an edited list.
Here is my AddressBook property within form1
public List<Contact> addressBook;
public List<Contact> AddressBook
{
get { return addressBook;}
set {addressBook = value;}
}
Within EDIT:
public Edit()
{
InitializeComponent();
temp = Master.AddressBook; // temp is the temporary List I update within EDIT
}
** I then have my algorithm which successfully lets me EDIT the list temp. the list temp now has the edited list**
then when I hit the save button, I use the following code;
Master.AddressBook = temp;
All I need is for the list temp to be sent back to form1.
the code Master.AddressBook = temp; WORKS for when I add values to the list through the ADD form.
ADD FORM:
public Add()
{
InitializeComponent();
temp = Master.AddressBook;
}
**** code to add a new record into the list temp. the new record is called newRecord**********
private void btnAddClose_Click(object sender, EventArgs e)
{
stor.AddressBook = temp; // when I hit close on the form, it updates the master list AddressBook
this.Close();
}
This is all probably very poorly worded but in essence the only bit where my code fails is when I want to change my master Addressbook within form1 by replacing it with the list temp, which is the edited list from my EDIT form.
I think it's something to do with my AddressBook property. But this doesn't explain why I can replace AddressBook with a list containing new records but I can't replace it with a list containing edited records.
One way to accomplish this would be to make the list in Master static.
Master:
public static List<Contact> AddressBook { get; set; }
Note: You do not need the backing variable, and if you do want to use it, best practices would suggest that it be private. If you do decide to use it, it will also need to be static.
In the Add form, you would then gather the data to create a new Contact object and temp should, in fact, be just a Contact object.
Add Form:
private Contact newRecord = null;
public Add()
{
InitializeComponent();
newRecord = new Contact();
}
/**** code to add the user-input to the new Contact object ****/
private void btnAddClose_Click(object sender, EventArgs e)
{
Master.AddressBook.Add(newRecord);
this.Close();
}
Hope this helps.
This is where the Singleton pattern comes in handy: Implementing Singleton in C#
You will notice Application Settings uses this same patttern to allow you to globally access it without having to pass it around.
When I use a Singleton I typically make the class name like (TypeName)Manager (ex: AddressBookManager).
So the class might be something like this:
public static class AddressBookManager
{
#region Singleton
static readonly AddressBookManager instance = new AddressBookManager();
private AddressBookManager(); // prevent creating instances of this
public static AddressBookManager Current { get { return instance; } }
#endregion
AddressBook master = new AddressBook(); // the master address book
public AddressBook Master
{
get { return master; } // get the master address book
set { master = value; } // set the master address book
}
}
Then in each form you would access it like so:
var addressBook = AddressBookManager.Current.Master;
addressBook.Add(newRecord);
The problem you are experiencing with the Edit functionality probably has something to do with the way you are using temporary lists. By using a static, global list and merely adding/editing items inside of it, you don't run that problem. Since your Contact items are a class (not struct), their changes will be reflected in the list automatically since they are reference types.
The great part about Singleton classes is the ability to access them from anywhere in the project. The only caveat is that you need to be extra cautious when working with multi-threaded applications and Singleton classes.
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
I am creating a new window popup window using
PopupWindows.PaymentsSummary paymentsSummary = new PopupWindows.PaymentsSummary
paymentsSummary.ParentWindow = Window.GetWindow(this);
paymentsSummary.ShowDialog();
on my load function in the Payment summary window I have
private void Window_Loaded(object sender, RoutedEventArgs e)
{
basepage.payments.BindPaymentSummaryToDataGrid(uiActiveItems, basepage.user.terminal.TerminalId, true);
basepage.payments.BindPaymentSummaryToDataGrid(uiInActiveItems, basepage.user.terminal.TerminalId, false);
}
The function is
public void BindPaymentSummaryToDataGrid(DataGrid dgrid, int terminalId, bool isActivePayment)
{
BLPinNumber pins = new BLPinNumber();
string pinNumber = String.Empty;
long pinId = pins.getPinId(terminalId, ref pinNumber);
using (var dbEntities = new DatabaseAccess.Schema.Entities())
{
dgrid.DataContext = dbEntities.getPaymentRecordsByPinId((int)pinId, isActivePayment);
}
}
The above code calls a Stored Proc in SQL Server and returns an object,
However when the app runs I get the error when clicking to show the popup on the following line paymentsSummary.ShowDialog();
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I have worked that down to the following code in the XAML for the datagrid
DataGrid ItemsSource="{Binding}" Grid.Column="{Binding}"
If i remove this code it works but the data doesnt load obvioulsy.
So what I believe I need to do is bind the datagrid onShowDialog method.
How do i create this ?
Or is there a better way of doing this using the Entity framework, im used to ASP.NET where working with DATAGRIDS seem easier, if ablight less powerful.
Many thanks
Your problem is lazy loading!, you got 2 options:
select the data with eager loading (change the getPaymentRecordsByPinId).
do not dispose the dbEntities while popup is open.