I have been struggling for weeks with my WPF appliaction named "ContactManager" when i want to add records to the database. I have two entites:
public partial class Contact : EntityBase
{
public int ContactId { get; set; }
[StringLength(20)]
public string FirstName { get; set; }
[StringLength(20)]
public string LastName { get; set; }
[StringLength(20)]
public string Organization { get; set; }
[StringLength(20)]
public string JobTitle { get; set; }
public string ImagePath { get; set; }
public string CellPhone { get; set; }
public string HomePhone { get; set; }
public string OfficePhone { get; set; }
public string PrimaryEmail { get; set; }
public string SecondaryEmail { get; set; }
public virtual Address Address { get; set; } = new Address();
public class Address : EntityBase
{
[ForeignKey("Contact")]
public int AddressId { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Zip { get; set; }
public string State { get; set; }
public virtual Contact Contact { get; set; }
The add method:
public int Add(Contact entity)
{
Context.Contacts.Add(entity);
var o = SaveChanges();
Context.Dispose();
Context = new CMEntities();
return o;
}
internal int SaveChanges()
{
try
{
return Context.SaveChanges();
}
}
When the database is empty it is working but after closing and restarting the app I get the following exception:
SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.Addresses'. Cannot insert duplicate key in object 'dbo.Addresses'. The duplicate key value is (1). The statement has been terminated.
I do not understand why Sql server (or entity framework??) wants to insert key 1 instead of the next id...
if i delete rows in table Addresses it is working again, it inserts the row without problem with the next/right addressid.( that is the addressid is not 1 but 5 because of the previous rows of contacts )
In my opinion the schema of( keys etc ) tables are correct the problem is with other issue, maybe binding or context i have not got a clue...
(I made a simpler example omitting MVC, it is working. )
Here is the code of MVC app:
namespace CMnew.Model
{
public partial class ContactRepository : IDisposable
{
public CMEntities Context { get; set; } = new CMEntities();
private List<Contact> _contactStore;
public ContactRepository()
{
if (this.GetAll() == null)
{
_contactStore = new List<Contact>();
}
else
{
_contactStore = this.GetAll();
}
}
public List<Contact> FindByLookup(string lookupName)
{
IEnumerable<Contact> found = from c in _contactStore
where c.LookupName.StartsWith(lookupName, StringComparison.OrdinalIgnoreCase)
select c;
return found.ToList();
}
public List<Contact> FindAll()
{
return new List<Contact>(_contactStore);
}
public void Save(Contact contact)
{
if (_contactStore.Contains(contact))
{
this.SaveToDatabase(contact);
}
else
{
_contactStore.Add(contact);
this.Add(contact);
}
}
public int SaveToDatabase(Contact entity)
{
return SaveChanges();
}
public void Delete(Contact contact)
{
_contactStore.Remove(contact);
DeleteFromDatabase(contact);
}
public int DeleteFromDatabase(Contact entity)
{
Context.Entry(entity).State = EntityState.Deleted;
return SaveChanges();
}
public Contact GetOne(int? id) => Context.Contacts.Find(id);
public List<Contact> GetAll() => Context.Contacts.ToList();
public int Add(Contact entity)
{
Context.Contacts.Add(entity);
var o = SaveChanges();
Context.Dispose();
Context = new CMEntities();
return o;
}
internal int SaveChanges()
{
try
{
return Context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
throw;
}
catch (DbUpdateException ex)
{
throw;
}
catch (CommitFailedException ex)
{
throw;
}
catch (Exception ex)
{
throw ex;
}
}
bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
Context.Dispose();
}
disposed = true;
}
}
}
namespace CMnew.Presenters
{
public class ApplicationPresenter : PresenterBase<Shell>, INotifyPropertyChanged
{
private readonly ContactRepository _contactRepository;
private ObservableCollection<Contact> _currentContacts;
public event PropertyChangedEventHandler PropertyChanged;
public ApplicationPresenter(Shell view, ContactRepository contactRepository) : base(view)
{
_contactRepository = contactRepository;
_currentContacts = new ObservableCollection<Contact>(_contactRepository.FindAll());
}
// public ObservableCollection<Contact> CurrentContacts { get; set; }
public ObservableCollection<Contact> CurrentContacts
{
get { return _currentContacts; }
set
{
_currentContacts = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentContacts)));
}
}
public string StatusText { get; set; }
public void Search(string criteria)
{
if (!string.IsNullOrEmpty(criteria) && criteria.Length > 2)
{
CurrentContacts = new ObservableCollection<Contact>(_contactRepository.FindByLookup(criteria));
StatusText = string.Format("{0} contacts found.", CurrentContacts.Count);
}
else
{
CurrentContacts = new ObservableCollection<Contact>(_contactRepository.FindAll());
}
}
public void NewContact()
{
OpenContact(new Contact());
}
public void SaveContact(Contact contact)
{
if (!CurrentContacts.Contains(contact))
{
CurrentContacts.Add(contact);
}
_contactRepository.Save(contact);
StatusText = string.Format("Contact '{0}' was saved.", contact.LookupName);
}
public void DeleteContact(Contact contact)
{
if (CurrentContacts.Contains(contact))
{
CurrentContacts.Remove(contact);
}
_contactRepository.Delete(contact);
StatusText = string.Format("Contact '{0}' was deleted.", contact.LookupName);
}
public void CloseTab<T>(PresenterBase<T> presenter)
{
View.RemoveTab(presenter);
}
private void OpenContact(Contact contact)
{
if (contact == null) return;
View.AddTab(new EditContactPresenter(this, new EditContactView(), contact));
}
public void DisplayAllContacts()
{
throw new NotImplementedException();
}
}
}
namespace CMnew.Presenters
{
public class EditContactPresenter : PresenterBase<EditContactView>
{
private readonly ApplicationPresenter _applicationPresenter;
private Contact _contact;
public EditContactPresenter(ApplicationPresenter applicationPresenter, EditContactView view, Contact contact) : base(view, "Contact.LookupName")
{
_applicationPresenter = applicationPresenter;
_contact = contact;
}
public Contact Contact
{
get { return _contact; }
set { _contact = value; }
}
public void SelectImage()
{
string imagePath = View.AskUserForImagePath();
if (!string.IsNullOrEmpty(imagePath))
{
Contact.ImagePath = imagePath;
}
}
public void Save()
{
_applicationPresenter.SaveContact(Contact);
}
public void Delete()
{
_applicationPresenter.CloseTab(this);
_applicationPresenter.DeleteContact(Contact);
}
public void Close()
{
_applicationPresenter.CloseTab(this);
}
public override bool Equals(object obj)
{
EditContactPresenter presenter = obj as EditContactPresenter;
return presenter != null && presenter.Contact.Equals(Contact);
}
}
}
namespace CMnew.Views
{
/// <summary>
/// Interaction logic for EditContactView.xaml
/// </summary>
public partial class EditContactView : UserControl
{
public EditContactView()
{
InitializeComponent();
}
public EditContactPresenter Presenter
{
get { return DataContext as EditContactPresenter; }
}
private void Save_Click(object sender, RoutedEventArgs e)
{
Presenter.Save();
}
private void Delete_Click(object sender, RoutedEventArgs e)
{
Presenter.Delete();
}
private void Close_Click(object sender, RoutedEventArgs e)
{
Presenter.Close();
}
private void SelectImage_Click(object sender, RoutedEventArgs e)
{
Presenter.SelectImage();
}
public string AskUserForImagePath()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.ShowDialog();
return dlg.FileName;
}
}
}
<UserControl x:Class="CMnew.Views.EditContactView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CMnew.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<DockPanel Margin="5">
<Border DockPanel.Dock="Top">
<DockPanel LastChildFill="False">
<TextBlock DockPanel.Dock="Left" Text="{Binding Contact.LastName}"/>
<TextBlock DockPanel.Dock="Left" Text=", "/>
<TextBlock DockPanel.Dock="Left" Text="{Binding Contact.FirstName}"/>
<TextBlock DockPanel.Dock="Right" Text="{Binding Contact.Organization}"/>
</DockPanel>
</Border>
<StackPanel DockPanel.Dock="Bottom" Style="{StaticResource buttonPanel}">
<Button Content="Save" Click="Save_Click"/>
<Button Content="Delete" Click="Delete_Click"/>
<Button Content="Close" Click="Close_Click"/>
</StackPanel>
<WrapPanel>
<GroupBox BorderBrush="{StaticResource lightBlueBrush}">
<GroupBox.Header>
<Border Background="{StaticResource lightBlueBrush}" Style="{StaticResource groupBoxHeader}">
<TextBlock Text="General"/>
</Border>
</GroupBox.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="175"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.RowSpan="4">
<Border Background="Gray"
CornerRadius="6"
Margin="2 2 0 0"
Opacity=".5"/>
<Border Margin="2 2 4 4"
Background="White"/>
<Viewbox Margin="2 2 4 4">
<Image Source="{Binding Contact.ImagePath}" />
</Viewbox>
<Border BorderBrush="{StaticResource lightBlueBrush}"
BorderThickness="2"
Background="Transparent"
CornerRadius="6"
Margin="0 0 2 2"/>
<Button Style="{StaticResource openButton}"
Background="White"
Foreground="{StaticResource lightBlueBrush}"
BorderBrush="{StaticResource lightBlueBrush}"
ToolTip="Change Picture"
Click="SelectImage_Click" />
</Grid>
<Label Grid.Column="1"
Content="_First Name:"
Target="{Binding ElementName=firstName}"/>
<TextBox x:Name="firstName"
Grid.Column="2"
Text="{Binding Contact.FirstName}"/>
<Label Grid.Row="1"
Grid.Column="1"
Content="_Last Name:"
Target="{Binding ElementName=lastName}"/>
<TextBox x:Name="lastName"
Grid.Row="1"
Grid.Column="2"
Text="{Binding Contact.LastName}"/>
<Label Grid.Row="2"
Grid.Column="1"
Content="Or_ganization:"
Target="{Binding ElementName=organization}"/>
<TextBox x:Name="organization"
Grid.Row="2"
Grid.Column="2"
Text="{Binding Contact.Organization}"/>
<Label Grid.Row="3"
Grid.Column="1"
Content="_Job Title:"
Target="{Binding ElementName=jobTitle}"/>
<TextBox x:Name="jobTitle"
Grid.Row="3"
Grid.Column="2"
Text="{Binding Contact.JobTitle}"/>
</Grid>
</GroupBox>
<GroupBox BorderBrush="{StaticResource greenBrush}">
<GroupBox.Header>
<Border Background="{StaticResource greenBrush}"
Style="{StaticResource groupBoxHeader}">
<TextBlock Text="Address"/>
</Border>
</GroupBox.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="Line _1:"
Target="{Binding ElementName=line1}" />
<TextBox x:Name="line1"
Grid.Column="1"
Grid.ColumnSpan="3"
Text="{Binding Contact.Address.Line1}" />
<Label Grid.Row="1"
Content="Line _2:"
Target="{Binding ElementName=line2}" />
<TextBox x:Name="line2"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="3"
Text="{Binding Contact.Address.Line2}" />
<Label Grid.Row="2"
Content="Ci_ty:"
Target="{Binding ElementName=city}" />
<TextBox x:Name="city"
Grid.Row="2"
Grid.Column="1"
Text="{Binding Contact.Address.City}" />
<Label Grid.Row="2"
Grid.Column="2"
Content="_State:"
Target="{Binding ElementName=state}" />
<TextBox x:Name="state"
Grid.Row="2"
Grid.Column="3"
Text="{Binding Contact.Address.State}" />
<Label Grid.Row="3"
Grid.Column="0"
Content="_Zip:"
Target="{Binding ElementName=zip}" />
<TextBox x:Name="zip"
Grid.Row="3"
Grid.Column="1"
Text="{Binding Contact.Address.Zip}" />
<Label Grid.Row="3"
Grid.Column="2"
Content="Countr_y:"
Target="{Binding ElementName=country}" />
<TextBox x:Name="country"
Grid.Row="3"
Grid.Column="3"
Text="{Binding Contact.Address.Country}" />
</Grid>
</GroupBox>
<GroupBox BorderBrush="{StaticResource redBrush}">
<GroupBox.Header>
<Border Background="{StaticResource redBrush}"
Style="{StaticResource groupBoxHeader}">
<TextBlock Text="Phone"/>
</Border>
</GroupBox.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="_Office:"
Target="{Binding ElementName=office}"/>
<TextBox x:Name="office"
Grid.Column="1"
Text="{Binding Contact.OfficePhone}" />
<Label Grid.Row="1"
Content="_Cell:"
Target="{Binding ElementName=cell}" />
<TextBox x:Name="cell"
Grid.Row="1"
Grid.Column="1"
Text="{Binding Contact.CellPhone}" />
<Label Grid.Row="2"
Content="_Home:"
Target="{Binding ElementName=home}" />
<TextBox x:Name="home"
Grid.Row="2"
Grid.Column="1"
Text="{Binding Contact.HomePhone}" />
</Grid>
</GroupBox>
<GroupBox BorderBrush="{StaticResource brownBrush}">
<GroupBox.Header>
<Border Background="{StaticResource brownBrush}"
Style="{StaticResource groupBoxHeader}">
<TextBlock Text="Email"/>
</Border>
</GroupBox.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Content="_Primary:"
Target="{Binding ElementName=primaryEmail}"/>
<TextBox x:Name="primaryEmail"
Grid.Column="1"
Text="{Binding Contact.PrimaryEmail}"/>
<Label Grid.Row="1"
Content="S_econdary:"
Target="{Binding ElementName=secondaryEmail}"/>
<TextBox x:Name="secondaryEmail"
Grid.Row="1"
Grid.Column="1"
Text="{Binding Contact.SecondaryEmail}"/>
</Grid>
</GroupBox>
</WrapPanel>
</DockPanel>
</UserControl>