I would like to expand the question asked in this thread
Associate a List with an Observable Collection
giving him the ability to permanently store data. The structure is basically the same, except that I installed the Entity Framework Core, created a DbContext class for storing records. I added a button to save the dataset to SQL Server. I did not encounter a compilation error, but when I tried to save the data in the database, I got this exception at runtime:
Message = The entity type 'Fruit' requires a primary key definition.
The complete exception is generally given below.
System.InvalidOperationException event thrown
HResult = -2146233079
Message = The entity type 'Fruit' requires a primary key definition.
Source = Microsoft.EntityFrameworkCore
Stacktrace:
at Microsoft.EntityFrameworkCore.Internal.ModelValidator.ShowError (String message)
at Microsoft.EntityFrameworkCore.Internal.ModelValidator.EnsureNonNullPrimaryKeys (model-model)
at Microsoft.EntityFrameworkCore.Internal.ModelValidator.Validate (model-model)
at Microsoft.EntityFrameworkCore.Internal.RelationalModelValidator.Validate (reference model)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel (DbContext context, IConventionSetBuilderSetBuilder convention, IModelValidator validator)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource. <> c__DisplayClass14_0.b__0 (Object k)
in System.Collections.Concurrent.ConcurrentDictionary 2.GetOrAdd(TKey key, Func 2 valueFactory)
at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel (DbContext context, IConventionSetBuilderSetBuilder convention, IModelValidator validator)
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel ()
at Microsoft.EntityFrameworkCore.Internal.LazyRef 1.get_Value()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServiceCollectionExtensions.<>c.<AddEntityFramework>b__0_6(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactoryService(FactoryService factoryService, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 1.get_Value()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServiceCollectionExtensions.<>c.<AddEntityFramework>b__0_6(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactoryService(FactoryService factoryService, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 1.get_Value()
at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServiceCollectionExtensions.<>c.<AddEntityFramework>b__0_6(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactoryService(FactoryService factoryService, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 2.VisitCallSite (IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped (ScopedCallSite scopedCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 2.VisitCallSite (IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScoped (ScopedCallSite scopedCallSite, ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor 2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure 2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure 2.VisitCallSite(IServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.<>c__DisplayClass16_0.<RealizeService>b__0(ServiceProvider provider)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure 1 accessor)
at Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.get_StateManager ()
at Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.DetectChanges ()
at Microsoft.EntityFrameworkCore.DbContext.TryDetectChanges ()
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges (Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges ()
in Fruits.MainWindow.SaveFruitCommandBinding_Executed (object sender, ExecutedRoutedEventArgs e) in D: \ Frank \ Test \ Fruits \ Fruits \ MainWindow.xaml.cs: line 50
in System.Windows.Input.CommandBinding.OnExecuted (object sender, ExecutedRoutedEventArgs e)
in System.Windows.Input.CommandManager.ExecuteCommandBinding (object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding)
in System.Windows.Input.CommandManager.FindCommandBinding (CommandBindingCollection commandBindings, object sender, RoutedEventArgs e, ICommand command, Boolean execute)
in System.Windows.Input.CommandManager.FindCommandBinding (object sender, RoutedEventArgs e, ICommand command, Boolean execute)
in System.Windows.Input.CommandManager.OnExecuted (sender of the object, ExecutedRoutedEventArgs e) in System.Windows.UIElement.OnExecutedThunk (sender of the object, ExecutedRoutedEventArgs e) in System.Windows.Input.ExecutedRoutedEventArgs.InvokeegentHandhandler) System.Windows.RoutedEventArgs.InvokeHandler (delegate handler, object-object) in System.Windows.RoutedEventHandlerInfo.InvokeHandler (Object target, RoutedEventArgs routedEventArgs) in System.Windows.EventRoute.InvokeHandlersImpl (object source, reargues, argumentsed System.Windows.UIElement.RaiseEventImpl (DependencyObject sender, RoutedEventArgs arguments) in System.Windows.UIElement.RaiseEvent (RoutedEventArgs args, Boolean trusted) in System.Windows.Input.RoutedCommand.ExecuteImpl (object parameter, target IInputElement, logical value userInitiated) in System.Windows.Input.RoutedCommand.ExecuteCore (object parameter, target IInputElement, logical value userInitiated) in MS.Internal.Commands.Commandel .CriticalExecuteCommandSource (ICommandSource commandSource, Boolean userInitiated) in System.Windows.Controls.Primitives.ButtonBase.OnClick () in System.Windows.Controls.Button.OnClick () in System.Windows.Controls.Primitives.ButtonBaseEObMtBOmBeOptMnBsOnButEOnMB ) in System.Windows.UIElement.OnMouseLeftButtonUpThunk (object sender, MouseButtonEventArgs e) in System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler (Delegate genericHandler, Object genericTarget) in System.Windows.RoutedIventArgs nvokeHandler (delegate handler, object-object) in System.Windows.RoutedEventHandlerInfo.InvokeHandler (Object target, RoutedEventArgs routedEventArgs) in System.Windows.EventRoute.InvokeHandlersImpl (object source, RoutedEventArgs arguments, boolean values โโreRaised.) ReRaiseEventAs (sender of DependencyObject, arguments RoutedEventArgs, RoutedEvent newEvent) in System.Windows.UIElement.OnMouseUpThunk (sender of the object, MouseButtonEventArgs e) in System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler.Weather.Weather.Weather.Web.arget.Weader.Web.delegate.developer.twerget.target.target.arget.target.arget.arvent.rt. InvokeHandler (delegate handler, object-object) in System.Windows.RoutedEventHandlerInfo.InvokeHandler (Object target, RoutedEventArgs routedEvent Args) in System.Windows.EventRoute.InvokeHandlersImpl (object source, arguments RoutedEventArgs, boolean values โโreRaised) in System.Windows.UIElement.RaiseEventImpl (DependencyObject sender, arguments RoutedEventArgs) in System.Windows.UIElement.RaiseTrustedE RouteE) .Windows.UIElement.RaiseEvent (RoutedEventArgs args, Boolean trusted) in System.Windows.Input.InputManager.ProcessStagingArea () in System.Windows.Input.InputManager.ProcessInput (input InputEventArgs) in System.Windows.Input.InputProviderSite.Report InputReport inputReport) in System.Windows.Interop.HwndMouseInputProvider.ReportInput (IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions, Int32 x, Int32 y actions, Int32 wheel) in System.Windows.Interop.HwndMouseInouse putProvider.FilterMessage (IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean & processed) in System.Windows.Interop.HwndSource.InputFilterMessage (IntPtr hwnd, Int32 msg, IntPtr ba, Win32.HwndWrapper.WndProc (IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean & processed) on MS.Win32.HwndSubclass.DispatcherCallbackOperation (Object o) on the System.Windows.Threading.ExceptionRealWrapper delegate. arguments, int32 numArgs) in System.Windows.Threading.ExceptionWrapper.TryCatchWhen (object source, delegate callback, object arguments, Int32 numArgs, catchHandler delegate) in System.Windows.Threading.Dispatcher.LegacyInvokeImpl (DispatcherPriority priority, timeout TimeSpan, delegation method, object arguments, Int32 numArgs) on MS.Win32.HwndSubclass.SubclassWndProc (IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) in MS.Win32.UnsafeNativeMethods.DispatchMessgms (MSG. & MS. Threading.Dispatcher.PushFrameImpl (DispatcherFrame) in System.Windows.Threading.Dispatcher.PushFrame (DispatcherFrame) in System.Windows.Application.RunDispatcher (Object ignore) in System.Windows.Application.RunInternal (window window) in System. Windows.Application.Run (window window) in System.Windows.Application.Run () on Fruits.App.Main () in System.AppDomain._nExecuteAssembly (assembly RuntimeAssembly, String [] args) in System.AppDomain.ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String [] args) in Microsoft.VisualStudio.HostingP rocess.HostProc.RunUsersAssembly () in System.Threading.ThreadHelper.ThreadStart_Context (state of the object) in System.Threading.ExecutionContext.RunInternal (ExecutionContext executeContext, callback ContextCallback, state of the object, Boolean preserveSyncCCton..Contread..textNext ExecutionContext executeContext, ContextCallback callback, object state, Boolean preserveSyncCtx) in System.Threading.ExecutionContext.Run (ExecutionContext executeContext, ContextCallback callback, object state) in System.Threading.ThreadHelper.ThreadStart () InnerException:
This is the updated Fruit class:
namespace Fruits.ViewModels { [Table("Fruits")] public class Fruit : ViewModelBase { #region Constractor public Fruit() { } public Fruit(string name, String clrString) { FruitName = name; // Parse colors like so: (Color)ColorConverter.ConvertFromString(clrString); FruitColor = clrString; _id = Guid.NewGuid(); } public Fruit(string name, Color clr) { FruitName = name; FruitColor = clr.ToString(); _id = Guid.NewGuid(); } #endregion #region Properties private Guid _id; [Key] public Guid ID { get { return _id; } } #region FruitName private string _fruitname; public string FruitName { get { return _fruitname; } set { if (_fruitname != value) { _fruitname = value; OnPropertyChanged("FruitName"); } } } #endregion #region FruitColor private String _fruitcolor; public String FruitColor { get { return _fruitcolor; } set { if (_fruitcolor != value) { _fruitcolor = value; OnPropertyChanged("FruitColor"); } } } #endregion #region Selected Property private bool _isSelected = true; // NOTE: I renamed this property public bool IsSelected { get { return _isSelected; } set { if (_isSelected != value) { _isSelected = value; OnPropertyChanged("IsSelected"); } } } #endregion #endregion } }
Updated MainWindows xaml (to add a save button)
<Window x:Class="Fruits.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Fruits" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <RoutedCommand x:Key="AddFruit" /> <RoutedCommand x:Key='SaveFruit' /> </Window.Resources> <Window.CommandBindings> <CommandBinding Command='{StaticResource AddFruit}' Executed='AddFruitCommandBinding_Executed' CanExecute='AddFruitCommandBinding_CanExecute' /> <CommandBinding Command='{StaticResource SaveFruit}' Executed='SaveFruitCommandBinding_Executed' CanExecute='SaveFruitCommandBinding_CanExecute' /> </Window.CommandBindings> <Grid> <StackPanel Orientation='Vertical' Margin='10'> <CheckBox IsChecked="{Binding ShowSelectedFruitOnly}">Selected Fruit Only</CheckBox> <ListBox x:Name='MyList' ItemsSource="{Binding FruitsView}" ItemTemplate='{StaticResource FruitTemp}' /> <StackPanel Orientation="Horizontal" Margin="0,10,0,0"> <Label Width="100">New Name:</Label> <TextBox Width="200" Text="{Binding NewFruitName, Mode=TwoWay }" /> </StackPanel> <StackPanel Orientation="Horizontal" Margin="0,10,0,0"> <Label Width="100">New Color:</Label> <TextBox Width="200" Text="{Binding NewFruitColor, Mode=TwoWay }" /> <ContentControl Style="{StaticResource ColorSwatch}" Margin="2" VerticalAlignment="Center" Content="{Binding NewFruitColor}" /> </StackPanel> <StackPanel Orientation='Horizontal'> <Button x:Name='AddFruit' Height='auto' Width='auto' Content='Add New Fruit 2' Margin='0,10,0,0' Command='{StaticResource AddFruit}' /> <Button x:Name='SaveFruit' Height='auto' Width='auto' Content='Save Fruit' Margin='100,10,0,0' Command='{StaticResource SaveFruit}' /> </StackPanel> </StackPanel> </Grid> </Window>
and my code behind the main windows (added handler)
using Fruits.ViewModels; using System; using System.Windows; using System.Windows.Input; namespace Fruits { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new MainViewModel(); ViewModel.AddNewFruit("Jackfruit", "Yellow"); ViewModel.AddNewFruit("Watermelon", "ForestGreen"); ViewModel.AddNewFruit("Apple", "Red"); ViewModel.AddNewFruit("Banana", "Yellow"); ViewModel.AddNewFruit("Orange", "DeepSkyBlue"); //ViewModel.Fruits[0].IsSelected = false; //ViewModel.Fruits[1].IsSelected = false; ViewModel.FruitsView.Refresh(); } public MainViewModel ViewModel { get { return DataContext as MainViewModel; } } private void AddFruitCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) { ViewModel.AddNewFruit(); } private void AddFruitCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = ViewModel != null && !String.IsNullOrWhiteSpace(ViewModel.NewFruitName) && !String.IsNullOrWhiteSpace(ViewModel.NewFruitColor) ; } private void SaveFruitCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) { using (var db=new FruitDbContext()) { db.SaveChanges(); } } private void SaveFruitCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } } }
My recently added dbContext:
namespace Fruits.ViewModels { public class FruitDbContext:DbContext { public DbSet<Fruit> Fruits { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionBuilder) { optionBuilder.UseSqlServer(@"Server = xxx; Database=Test; Integrated Security = True"); } } }
Other classes remain unchanged, but I listed them anyway:
ViewModelBase
namespace Fruits.ViewModels { public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string name) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(name)); } } } } ViewModel using System; using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows.Data; using System.Windows.Media; namespace Fruits.ViewModels { #region MainViewModel Class public class MainViewModel : ViewModelBase { public MainViewModel() { Fruits = new ObservableCollection<Fruit>(); } public ICollectionView FruitsView { get; private set; } #region ShowSelectedFruitOnly Property private bool _showSelectedFruitOnly = true; public bool ShowSelectedFruitOnly { get { return _showSelectedFruitOnly; } set { if (value != _showSelectedFruitOnly) { _showSelectedFruitOnly = value; FruitsView.Refresh(); OnPropertyChanged("ShowSelectedFruitOnly"); } } } #endregion ShowSelectedFruitOnly Property #region Add Methods public void AddNewFruit() { Fruits.Add(new Fruit(NewFruitName, NewFruitColor)); NewFruitName = ""; NewFruitColor = ""; } public void AddNewFruit(string name, string color) { Fruits.Add(new Fruit(name, color)); } public void AddNewFruit(string name, Color color) { Fruits.Add(new Fruit(name, color)); } #endregion Add Methods #region NewFruitName Property private String _newFruitName = default(String); public String NewFruitName { get { return _newFruitName; } set { if (value != _newFruitName) { _newFruitName = value; OnPropertyChanged("NewFruitName"); } } } #endregion NewFruitName Property #region NewFruitColor Property private String _newFruitColor = default(String); public String NewFruitColor { get { return _newFruitColor; } set { if (value != _newFruitColor) { _newFruitColor = value; OnPropertyChanged("NewFruitColor"); } } } #endregion NewFruitColor Property #region Fruits Property private static ObservableCollection<Fruit> _fruits; public ObservableCollection<Fruit> Fruits { get { return _fruits; } private set { if (value != _fruits) { _fruits = value; FruitsView = CollectionViewSource.GetDefaultView(Fruits); FruitsView.Filter = FruitFilterPredicate; FruitsView.Refresh(); OnPropertyChanged("Fruits"); } } } protected bool FruitFilterPredicate(Object o) { if (ShowSelectedFruitOnly) { return (o as Fruit).IsSelected; } return true; } #endregion Fruits Property } #endregion MainViewModel Class }
App.xaml
<Application x:Class="Fruits.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Fruits" StartupUri="MainWindow.xaml"> <Application.Resources> <Style x:Key="ColorSwatch" TargetType="ContentControl"> <Setter Property="Width" Value="24" /> <Setter Property="Height" Value="24" /> <Setter Property="IsTabStop" Value="false" /> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Gray" StrokeThickness="1"> <Rectangle.Fill> <SolidColorBrush Color="{Binding}" /> </Rectangle.Fill> </Rectangle> </DataTemplate> </Setter.Value> </Setter> </Style> <DataTemplate x:Key='FruitTemp'> <StackPanel Orientation='Horizontal' Margin='5'> <TextBlock x:Name='tbName' Text='{Binding FruitName}' Margin='10,0,0,0' Width='100' /> <TextBlock x:Name='tbColor' Text='{Binding FruitColor}' Margin='10,0,0,0' Width='100' /> <ContentControl Width="16" Height="16" Style="{StaticResource ColorSwatch}" Content="{Binding FruitColor}" /> <CheckBox x:Name='cbSelected' Content='Selected' Margin='10,0,0,0' IsChecked='{Binding IsSelected}' /> </StackPanel> </DataTemplate> </Application.Resources> </Application>
Structure of my project

My table in SQL Server:
CREATE TABLE [dbo].[Fruits] ( [ID] [uniqueidentifier] NOT NULL, [FruitName] [nvarchar](50) NULL, [FruitColor] [nvarchar](50) NULL, [IsSelected] [nvarchar](1) NULL, CONSTRAINT [PK_Fruit] PRIMARY KEY CLUSTERED ([ID] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
Please advise why the message said that there is no primary key as long as it exists.