简体   繁体   English

使用实体框架实现MVVM模式-添加删除

[英]Implementing the MVVM Pattern with Entity Framework - Add Removing

I'm trying to implement the MVVM Pattern on my WPF project that uses Entity Framework to get / manipulates data. 我正在尝试在使用实体框架获取/操作数据的WPF项目上实现MVVM模式。 I'm confused, i want to know where validating changes on my collections of model objects to database should be??? 我很困惑,我想知道验证模型对象到数据库集合的更改应该在哪里??? my application is as follow : in my view i've a datagrid of persons, two textboxes that will load the name / surname of the selected person , a buton to updated changes of rows and a button to delete the selected row. 我的应用程序如下:在我看来,我有一个人员数据网格,两个文本框将加载所选人员的姓名/名字,一个用于更新行更改的按钮,以及一个用于删除所选行的按钮。

In my ModelView , i have an observableCollection that will be loaded at the initilization of the class with information from my database ( entities) + two Relaycommands for Add/Remove buttons ( please find the code below). 在我的ModelView中,我有一个observableCollection,它将在类初始化时使用来自我的数据库(实体)的信息+两个用于“添加/删除”按钮的Relaycommands(请在下面的代码中)加载。

The problem is that i didn't understood well the philosophy of MVVM, where and when and how modifications on my data should be pushed to database? 问题是我不太了解MVVM的原理,应将何时何地以及如何将对数据的修改推送到数据库? For now, when i update a row in my database, and save my DB context modifications on my observable collection are submitted, but it's not the cdase when i remove an item, i've to manually look for it in database and remove it ( i've attached my observablecollection to a NotifyCollectionChangedEventHandler event that will handle this)... i don't get the point of using Observable collection!!! 现在,当我更新数据库中的一行,并将数据库上下文修改保存到我的可观察集合中时,就提交了,但是当我删除一个项目时,它不是cdase,我必须在数据库中手动查找并将其删除(我已经将我的observablecollection附加到一个可以处理此事件的NotifyCollectionChangedEventHandler事件上)...我不明白使用Observable集合的意义!!!

Is there any simple explanation of a "perfect" mvvm architecture using database data??? 有没有关于使用数据库数据的“完美” mvvm体系结构的简单解释? Thanks! 谢谢! my ViewModel 我的ViewModel

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows;
using MVVMOK.Models;
using MVVMOK.Base;
using System.Collections.Specialized;

namespace MVVMOK.ViewModel
{
    class MainWindowViewModel : ViewModelBase
    {
        private DW_MargoEntities contexte;



        //Constructor
        public MainWindowViewModel()
        {
            contexte = new DATABASEEntities();
            collectionOfCollaborators = new ObservableCollection<Collaborator>();
            foreach (Collaborator c in contexte.Collaborator)
            {
                collectionOfCollaborators.Add(c);
            }


            //Abonnement pour l'ajout ou la suppression d'éléments :
            collectionOfCollaborators.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(collectionOfCollaboratorsChanged);

            //Assignation des commandes : 
            this._deleteComand = new RelayCommand(new Action<object>(DeleteRow));
            this._updateCommand = new RelayCommand(new Action<object>(UpdateDB));
        }
        //liste des propriétés publiques:


        //Propriété pour représenter l'élément séléctionné du datagrid
        private  Collaborator selectedItem;
        public Collaborator _selectedItem
        {
            get { return selectedItem; }
            set
            {
                if (value != selectedItem)
                {
                    selectedItem = value;
                    OnPropertyChanged("_selectedItem");
                };
            }
        }
        //Propriété pour représenter l'élément séléctionné:
        private ObservableCollection<Collaborator> collectionOfCollaborators;
        public ObservableCollection<Collaborator> _collectionOfCollaborators
        {
            get { return collectionOfCollaborators; }
            set
            {
                this.collectionOfCollaborators = value;
                OnPropertyChanged("_collectionOfCollaborators");
            }
        }

        //Commandes : 
        public ICommand _updateCommand
        {
            get;
            set;
        }
        public ICommand _deleteComand
        {
            get;
            set;
        }

        void collectionOfCollaboratorsChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            Collaborator f = new Collaborator();
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:

                    for(int i = 0; i<e.NewItems.Count;i++)
                    {

                        if (e.NewItems[i].GetType().Equals(f.GetType()))
                        {
                            contexte.Collaborator.Add(e.NewItems[i] as Collaborator);
                        }
                    }
                    contexte.SaveChanges();
                    break;

                case NotifyCollectionChangedAction.Remove:

                    for (int i = 0; i < e.OldItems.Count; i++)
                    {

                        if (e.OldItems[i].GetType().Equals(f.GetType()))
                        {
                            contexte.Collaborator.Remove(e.OldItems[i] as Collaborator);
                        }
                    }
                    contexte.SaveChanges();
                    break;
                //Reset = Clear

            }
        }



        //Services :
        public void UpdateDB(object msg)
        {
            contexte.SaveChanges();
        }


        public void DeleteRow(object msg)
        {

            _collectionOfCollaborators.Remove(_selectedItem);
            contexte.SaveChanges();
        }
    }
}

My model 我的模特

namespace MVVMOK.Models
{
    using System;
    using System.Collections.Generic;

    public partial class Collaborator
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
    }
}

My XAML 我的XAML

<Window x:Class="MVVMOK.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:MVVMOK.ViewModel"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <!-- Declaratively create an instance of our SongViewModel -->
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid Height="237" HorizontalAlignment="Left" Margin="12,12,0,0" Name="grid1" VerticalAlignment="Top" Width="479">
            <DataGrid AutoGenerateColumns="False" Height="237" HorizontalAlignment="Left" Name="dataGrid1" VerticalAlignment="Top" Width="479" ItemsSource="{Binding Path=_collectionOfCollaborators, Mode=TwoWay}" SelectionMode="Single" SelectedItem="{Binding Path=_selectedItem, Mode=TwoWay}"  >
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Path=Id}" Header="ID" />
                    <DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" Width="4*" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="104,255,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text ="{Binding Path=_selectedItem.Name, Mode=TwoWay}" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="104,283,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text ="{Binding Path=_selectedItem.Surname, Mode=TwoWay}" />
        <Label Content="Name" Height="28" HorizontalAlignment="Left" Margin="50,255,0,0" Name="label1" VerticalAlignment="Top" />
        <Label Content="Surname" Height="28" HorizontalAlignment="Left" Margin="37,283,0,0" Name="label2" VerticalAlignment="Top" />
        <Button Content="Delete Row" Height="23" HorizontalAlignment="Left" Margin="416,260,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding Path=_deleteComand}"/>
        <Button Content="Update All" Height="23" HorizontalAlignment="Left" Margin="335,260,0,0" Name="button2" VerticalAlignment="Top" Width="75" Command="{Binding Path=_updateCommand}"/>
    </Grid>
</Window>

I don't have an answer to why you aren't seeing your expected results but I thought I would give you some ideas on how to structure this a bit better. 对于您为什么看不到预期的结果,我没有任何答案,但我想我会给您一些构想,以更好地组织这件事。

What you really want to do when data changes is apply a command. 数据更改时您真正想做的就是应用命令。 For instance the delete command should be applied. 例如,应该应用delete命令。 When handling this command you can perform any validation and either persist the change or flag an error. 处理此命令时,您可以执行任何验证,并且可以保留更改或标记错误。 So your DeleteRow class which you have wrapped in the relay command should really be a separate class in a Model tier of your application. 因此,您包装在relay命令中的DeleteRow类实际上应该是应用程序模型层中的一个单独的类。 You can have a web tier that uses MVVM, but it should be persistence ignorant, it should apply a command and then react appropriately if the command succeeds or fails. 您可以拥有一个使用MVVM的Web层,但是它应该对持久性不了解,它应该应用命令,然后在命令成功或失败时做出适当的反应。

this._deleteComand = new RelayCommand(new Action<object>(DeleteRow));

could be something more like 可能更像

this._deleteComand = new RelayCommand(new Action<object>() => {new DeleteCommandHandler().Apply(new DeleteCommand(){SelectedItem = _selectedItem})});

The DeleteCommandHandler and DeleteCommand will form part of your model (I would use a different class library for this). DeleteCommandHandler和DeleteCommand将构成模型的一部分(为此我将使用其他类库)。

Now your handlers need to know about your persistence mechanism, so inside your handler you can create your DW_MargoEntities context and do the work to delete. 现在,您的处理程序需要了解您的持久性机制,因此在您的处理程序中,您可以创建DW_MargoEntities上下文并进行删除。

The advantages of this is your view model is no longer responsible for updating your model so your view models will be a lot simpler and won't have a direct dependency on what database you use. 这样做的好处是您的视图模型不再负责更新模型,因此您的视图模型将更加简单,并且不会直接依赖于所使用的数据库。

Once you have a command handler pattern setup I would move towards dependency injection for your context. 设置好命令处理程序模式后,我将转向为上下文注入依赖项。

For instance rather than saying new DeleteCommandHandler(), you could ask an Inversion of Control container such as Structure Map to build it. 例如,您可以不要求说一个新的DeleteCommandHandler(),而可以请求一个Inversion of Control容器(例如Structure Map)来构建它。

ObjectFactory.GetInstance<DeleteCommandHandler>();

Then your DeleteCommandHandler class could look like 然后您的DeleteCommandHandler类可能看起来像

class DeleteCommandHandler
{
    DW_MargoEntities context;
    public DeleteCommandHandler(DW_MargoEntities context)
    {
        this.context = context;
    }

    public bool Apply(DeleteCOmmand command)
    {
        if (not valid) {return false;}
        var item = context.LoadEntityById<EntityTypeHere>(command.SelectedItem) // Query the item

        context.Delete(item);
        return true;
    }
}

Sorry for being a bit vague, it's a lot to explain and it's getting a bit late here. 抱歉,我含糊不清,需要解释很多,现在有点迟了。 Have a read on the command pattern http://en.wikipedia.org/wiki/Command_pattern 阅读命令模式http://en.wikipedia.org/wiki/Command_pattern

I think there is not "THE" way in mvvm there are always several and like always it depends. 我认为mvvm中没有“ THE”方式,总是有几种,并且总是取决于它。

But the to your solution there is an interface called IDataErrorInfo which can help you out. 但是,您的解决方案中有一个名为IDataErrorInfo的接口可以为您提供帮助。

For a example take a look at this article... http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM 例如,看一下本文... http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM

Or here: http://blindmeis.wordpress.com/2012/04/16/wpf-mvvm-idataerrorinfo-validation-errortemplate/ 或者在这里: http : //blindmeis.wordpress.com/2012/04/16/wpf-mvvm-idataerrorinfo-validation-errortemplate/

And maybe you should think about hiding entity framework from your view models with the repository pattern or a simply DataService . 也许您应该考虑使用存储库模式或简单的DataService在视图模型中隐藏实体框架。

hope that helps... 希望有帮助...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM