EF - checking that an user cannot enter twice the same key - 12 pgms - 8 working well, 4 send an system error msg !!!
Could someone help me? How to catch that kind of exception? I cannot find the InnerException message number as for example with DBupdateException.
Thanks in advance for your help.
Error msg: System.InvalidOperationException: 'The instance of entity type 'Country' cannot be tracked because another instance with the same key value for {'CountryName'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.'
class:
using System.ComponentModel.DataAnnotations;
using System;
using System.Collections.Generic;
namespace ATChome.DbModel
{
public class Country
{
public int CountryId { get; set; }
public string CountryName { get; set; }
public string CountryIso { get; set; }
public bool IsDeleted { get; set; }
public int UserIdCrea { get; set; }
public DateTime DateCreation { get; set; }
public int UserIdMod { get; set; }
public DateTime DateModification { get; set; }
public byte[] Timestamp { get; set; }
// Relationship Collection Navigation Property
public List<Postalinfo> Postalinfos { get; set; }
}
}
DBContext:
public DbSet<Country>? Countries { get; set; }
// COUNTRY Table
modelBuilder.Entity<Country>().HasKey(c => c.CountryId);
modelBuilder.Entity<Country>().HasIndex(c => c.CountryName).IsUnique();
modelBuilder.Entity<Country>().Property(c => c.CountryName).HasMaxLength(60);
modelBuilder.Entity<Country>().Property(c => c.CountryIso).HasMaxLength(3);
modelBuilder.Entity<Country>().Property(c => c.IsDeleted).HasDefaultValue(0);
modelBuilder.Entity<Country>().Property(c => c.UserIdCrea);
modelBuilder.Entity<Country>().Property(c => c.DateCreation).HasDefaultValueSql("getdate()");
modelBuilder.Entity<Country>().Property(c => c.UserIdMod);
modelBuilder.Entity<Country>().Property(c => c.DateModification).HasDefaultValueSql("getdate()");
modelBuilder.Entity<Country>().Property(c => c.Timestamp).IsRowVersion();
Program C#:
using ATChome.DbModel;
using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
// Imports necessary to add
using System.Windows.Data;
using Microsoft.Data.SqlClient;
namespace ATChome
{
/// <summary>
/// Interaction logic for PageCountries.xaml
/// </summary>
public partial class PageCountries : Window
{
// Context initialization
private readonly AtcDbContext context = new();
Country NewCountry = new();
// WARNING - put readonly in order to avoid message from compiler controls
private readonly CollectionViewSource countryViewSource;
public PageCountries()
{
this.context = context;
InitializeComponent();
countryViewSource = (CollectionViewSource)FindResource(nameof(countryViewSource));
GvAdd.DataContext = NewCountry;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Load the entities into EF Core
context.Countries.Load();
// Binding to the source
countryViewSource.Source = context.Countries.Local.ToObservableCollection();
}
// Filters Box Collection and Refresh Management
// Filter on CountryName
private void TxtCountryName_TextChanged(object sender, TextChangedEventArgs e)
{
// Refresh the view to apply filters.
CollectionViewSource.GetDefaultView(DataGridList.ItemsSource).Refresh();
}
// Filter on CountryIso
private void TxtCountryIso_TextChanged(object sender, TextChangedEventArgs e)
{
// Refresh the view to apply filters.
CollectionViewSource.GetDefaultView(DataGridList.ItemsSource).Refresh();
}
// Filter on IsDeleted refresh
private void IsDeletedFilter_Changed(object sender, RoutedEventArgs e)
{
// Refresh the view to apply filters.
CollectionViewSource.GetDefaultView(DataGridList.ItemsSource).Refresh();
}
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
int refused = 0;
if (e.Item is Country t && t != null) /* If filters have value, process filters.
WARNING introduced comparison type for Culture params and NON sensitive Case */
{
if (this.TxtCountryName != null && t.CountryName != null && t.CountryName.Contains(TxtCountryName.Text, StringComparison.CurrentCultureIgnoreCase) == false)
{
refused++;
}
if (this.TxtCountryIso != null && t.CountryIso != null && t.CountryIso.Contains(TxtCountryIso.Text, StringComparison.CurrentCultureIgnoreCase) == false)
{
refused++;
}
if (this.CbIsDeletedFilter.IsChecked == false && t.IsDeleted == true)
{
refused++;
}
if (refused == 0)
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
}
// - Event handler for Selection in DataGrid -
private void DataGridList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
Country country = (Country)e.AddedItems[0];
if (country.IsDeleted == true)
{
DataGridList.SelectedItem = null;
CollectionViewSource.GetDefaultView(DataGridList.ItemsSource).Refresh();
MessageBox.Show("Non è possibile modificare un Paese cancellato", "ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
}
}
//Event handler for the UI Update Button in Tabcontrol.
private void BtnUpdate1_Click(object sender, RoutedEventArgs e)
{
int mistakeinupdate = 0;
if (string.IsNullOrWhiteSpace(TxtCountryName1.Text))
{
mistakeinupdate = 1;
MessageBox.Show("Inserire un nome Paese per favore", "ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
}
if (string.IsNullOrWhiteSpace(TxtCountryIso1.Text))
{
mistakeinupdate = 2;
MessageBox.Show("Inserire un Codice ISO per favore", "ATC - ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
}
if (mistakeinupdate == 0)
{
// Before Save in DB - Context Update because trigger choice in XAML is Explicit !
BindingExpression be1 = TxtCountryName1.GetBindingExpression(TextBox.TextProperty);
be1.UpdateSource();
BindingExpression be2 = TxtCountryIso1.GetBindingExpression(TextBox.TextProperty);
be2.UpdateSource();
try
{
context.SaveChanges();
// Deselect Item and Refresh all views .
DataGridList.SelectedItem = null;
CollectionViewSource.GetDefaultView(DataGridList.ItemsSource).Refresh();
MessageBox.Show("Paese modificato correttamente", "ATC - CONFERMA", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (DbUpdateException)
{
MessageBox.Show("Problema aggiornamento DataBase in modifica", "ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
}
catch (DBConcurrencyException ex)
{
MessageBox.Show("Non posso aggiornare il DataBase un altro utente lo sta modificando, riprovare per favore", "ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
// Deselect Item and Refresh all views .
DataGridList.SelectedItem = null;
CollectionViewSource.GetDefaultView(DataGridList.ItemsSource).Refresh();
}
}
else
{
return;
}
}
//Event handler for the UI Add Button in Tabcontrol.
private void BtnAdd0_Click(object sender, RoutedEventArgs e)
{
// Initialization
// Check data coming from ADD GUI
int mistakeinadd = 0;
if (string.IsNullOrWhiteSpace(TxtCountryName0.Text))
{
mistakeinadd = 1;
MessageBox.Show("Inserire un nome Paese per favore", "ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
}
if (string.IsNullOrWhiteSpace(TxtCountryIso0.Text))
{
mistakeinadd = 2;
MessageBox.Show("Inserire un Codice ISO per favore", "ATC - ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
}
// Insert in Database
if (mistakeinadd == 0)
{
try
{
****context.Countries.Add(NewCountry);** LINE THAT GIVES ERROR!!!!!!!!!!!!**
context.SaveChanges();
DataGridList.SelectedItem = null;
CollectionViewSource.GetDefaultView(DataGridList.ItemsSource).Refresh();
NewCountry = new Country();
GvAdd.DataContext = NewCountry;
MessageBox.Show("Paese aggiunto correttamente", "ATC - CONFERMA", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (DbUpdateException ex)
{
if (ex.InnerException is SqlException sqlException)
{
switch (sqlException.Number)
{
case 2601: // Unique Key violation exception code
context.Countries.Remove(NewCountry);
MessageBox.Show("Paese già esistente", "ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
break;
default:
context.Countries.Remove(NewCountry);
MessageBox.Show("Problema aggiornamento DataBase, contattare supporto", "ATC - ERRORE", MessageBoxButton.OK, MessageBoxImage.Error);
break;
}
}
}
}
else
{
return;
}
}
// Event handler for the UI Logical Cancel Button in Tabcontrol.
private void BtnCancel1_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(TxtCountryName1.Text))
{
return;
}
else
{
if (MessageBox.Show("Cancellare il Paese ?", "ATC - CONFERMA", MessageBoxButton.YesNo, MessageBoxImage.Exclamation) == MessageBoxResult.Yes)
{
CbIsDeleted1.IsChecked = true;
context.SaveChanges();
// Deselect Item and Refresh all views .
DataGridList.SelectedItem = null;
CollectionViewSource.GetDefaultView(DataGridList.ItemsSource).Refresh();
MessageBox.Show("Paese cancellato", "ATC - CONFERMA", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
return;
}
}
}
// CLOSING Procedure
//Close current PageCountries page with Button.
private void ClosePageCountries_Click(object sender, RoutedEventArgs e)
{
context.Dispose();
this.Close();
}
// Clean up connections when closing window.
protected override void OnClosing(CancelEventArgs e)
{
// clean up database connections
context.Dispose();
}
}
}