使用MVVM模式将数据添加到数据库

时间:2013-12-09 01:52:02

标签: c# wpf silverlight xaml mvvm

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

假设我有一个名为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?

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

更新

假设我有两个这样的表:

客户:

CustomerID
Name
GenderID //Foreign Key

性别:

GenderID
Value

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

1 个答案:

答案 0 :(得分:9)

我强烈建议您先使用数据库优先使用ORM,例如实体框架( EF ),因为您已经创建了数据库。实体框架将自动为您创建您的POCO(模型类,Plain Old C#Objects),并且还将创建一个名为**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; }
}

在您的viewmodel中,您可以从数据库中检索List<Customer>()

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

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

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

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

如果您希望能够进行任何取消或撤销操作,请立即按照现有方式设置您的媒体资源:

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

在您的保存方法中,您必须将viewmodel属性映射到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
}

此时应进行更改并更新数据库表。

现在,如果您没有使用Entity Framework,则需要设置某种数据访问层,您可以在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
}

现在在你的viewmodel中:

public ICommand SaveChangesCommand { get; set; }

在viewmodel构造函数中

SaveChangesCommand = new RelayCommand(SaveCustomerChanges);

然后在XAML中连接SaveChangesCommand:

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

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