【问题标题】:Add data to database using MVVM pattern使用 MVVM 模式将数据添加到数据库
【发布时间】:2013-12-09 01:52:02
【问题描述】:

我正在尝试将数据保存到数据库。

假设我有一个名为 Customers 的表,其中包含三个字段:

Id
FirstName
LastName

我使用 ADO.Net 实体数据模型创建了我的模型。

这是我的 ViewModel 代码

public class myViewModel : INotifyPropertyChanged
{
    private string _firstName;
    public string FirstName
    {
        get
        {
            return _firstName;
        }
        set
        {
            _firstName = value;
            OnPropertyChanged("FirstName");
        }
    }

    private string _lastName;
    public string LastName
    {
        get
        {
            return _lastName;
        }
        set
        {
            _lastName = value;
            OnPropertyChanged("LastName");
        }
    }

    protected virtual void OnPropertyChanged(string PropertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(PropertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

}

这是我的 MainWindow.xaml 文件:

<Window x:Class="Lab_Lite.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:Lab_Lite.ViewModels"
        Title="MainWindow" Height="350" Width="525" WindowState="Maximized">

    <Window.DataContext>
        <vm:MainWindowViewModel />
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Row="0" Grid.Column="0" Text="FirstName" />
        <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding FirstName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" />

        <TextBlock Grid.Row="1" Grid.Column="0" Text="LastName" />
        <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding LastName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" />

        <Button Grid.Row="2" Grid.Column="1" Content="Save" />
    </Grid>
</Window>

这里有两个问题:

1. How my ViewModel knows that FirstName property declared in ViewModel is 
   referenced to FirstName Column in my database?
2. How to save changes to database when UpdateSourceTrigger is set to Explicit?

我想我已经在某种程度上使用命令找到了第二个问题的答案。但是我不知道它是否正确,因为我不知道我的第一个问题的答案。

更新

假设我有两个这样的表:

客户:

CustomerID
Name
GenderID //Foreign Key

性别:

GenderID
Value

现在SaveCustomerChanges 方法中CurrentCustomer.Gender 的值应该是多少?

【问题讨论】:

    标签: c# wpf silverlight xaml mvvm


    【解决方案1】:

    我强烈建议您使用数据库优先的 ORM,例如实体框架 (EF),因为您已经创建了一个数据库。 Entity Framework 将自动为您创建 POCO(模型类,普通旧 C# 对象),还将创建一个名为 **YourDbName**Context 的类,即您的 DbContext。此时,您的应用程序将在您每次运行应用程序时创建一个上下文实例,您将能够使用该上下文访问您的数据库。 EF 还将跟踪您所做的任何更改,因此您可以通过以下方式解决问题:

    EF 生成 POCO:

    public partial class Customer
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    

    在您的视图模型中,您可以从数据库中检索List&lt;Customer&gt;()

    public List<Customer> Customers { get; set; } //Load from context in constructor, really though you should do it in a service layer
    public Customer CurrentCustomer { get; set; } //Current customer you need to edit
    

    所以现在您在视图模型中有两个选项: 为了成为自然的 MVVM,您不应该将 CurrentCustomer 绑定到视图。这不符合模式。为了解决这个问题,您可以创建单独的属性,就像上面一样,您可以在 getter 中返回 CurrentCustomer.PropertyName 并在 setter 中使用它,如下所示:

    public string FirstName
    {
        get
        {
            return CurrentCustomer.FirstName;
        }
        set
        {
            CurrentCustomer.FirstName = value;
            OnPropertyChanged("FirstName");
        }
    }
    

    通过这样做,您不必担心将 viewmodel 属性映射到 POCO 属性,但是您在视图中所做的任何更改现在都会导致 Entity Framework 跟踪更改,在这种情况下,您现在需要做的就是在保存方法中调用dbContext.SaveChanges();

    如果您希望能够执行任何类型的取消或撤消操作,请按照您现在的方式设置属性:

    private string _firstName;
    public string FirstName
    {
        get
        {
            return _firstName;
        }
        set
        {
            _firstName = value;
            OnPropertyChanged("FirstName");
        }
    }
    

    在您的保存方法中,您必须将视图模型属性映射到 CurrentCustomer 的属性,然后应该会导致跟踪更改:

    private void SaveCustomerChanges()
    {
       //Could use Automapper to handle mapping for you.
       CurrentCustomer.FirstName = this.FirstName;
       CurrentCustomer.LastName = this.LastName;
       dbContext.SaveChanges(); //dbContext will be named diff for you
    }
    

    此时更改应该已经完成​​并更新了数据库表。

    现在,如果您不使用实体框架,则需要设置某种数据访问层,您可以将Customer 对象传递给该层,然后您需要从数据库中检索该对象并更新它的价值。

    查看this as well!

    编辑: 要调用SaveCustomerChanges(),您需要使用ICommand 连接此方法。

    首先创建一个RelayCommand类:

    public class RelayCommand : ICommand
    {
        private Action<object> _action;
    
        public RelayCommand(Action<object> action)
        {
            _action = action;
        }
    
        #region ICommand Members
    
        public bool CanExecute(object parameter)
        {
            return true;
        }
    
        public event EventHandler CanExecuteChanged;
    
        public void Execute(object parameter)
        {
            _action(parameter);
        }
    
        #endregion
    }
    

    现在在您的视图模型中:

    public ICommand SaveChangesCommand { get; set; }
    

    在您的视图模型构造函数中

    SaveChangesCommand = new RelayCommand(SaveCustomerChanges);
    

    然后在 XAML 中连接 SaveChangesCommand:

    <Button Content="Save" Command="{Binding SaveChangesCommand }" />
    

    现在,当您单击“保存”时,该命令应该会触发 SaveCustomerChanges() 方法。

    【讨论】:

    • 首先感谢您回答我的问题。我过去使用过实体框架,在这个示例项目中我也使用过实体框架,并且我在我的问题中也提到了它,我使用 ADO.net 实体数据模型生成我的模型。现在我也将有一个取消按钮。因此,我将在这里遵循您的第二种方法。在这里你没有提到当我点击保存按钮时如何调用 SaveCustomerChanges。
    • 需要使用ICommand连接你的保存按钮的方法。看看上面我发布的一个例子。这也可以用于您的取消按钮。
    • 感谢您的时间和辛勤工作。这工作得很好。
    • 没问题..查看此链接,她对 WPF 非常了解,并且有好文章可供阅读:rachel53461.wordpress.com/2011/05/08/simplemvvmexample
    • 我收到一个错误,指出SaveCustomerChanges 的某些参数在SaveChangesCommand = new RelayCommand(SaveCustomerChanges); 这一行中无效。所以我在我们之前创建的 SaveCustomerChanges 方法中添加了一个 object 类型的参数。现在它工作正常。现在我有另一个问题。我稍后会更新我的问题。
    猜你喜欢
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 2016-02-27
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    • 2019-10-19
    • 2018-01-22
    相关资源
    最近更新 更多