如何将 MVVM 与 EF 一起使用(在 SQLite 中使用非常复杂的数据库)?
Posted
技术标签:
【中文标题】如何将 MVVM 与 EF 一起使用(在 SQLite 中使用非常复杂的数据库)?【英文标题】:How to use MVVM with EF (with a pretty complex database in SQLite)? 【发布时间】:2021-08-23 20:49:19 【问题描述】:我正在尝试拥有一个 MVVM 架构,而模型也是 EF 模型。
在代码中:
型号:
public class NotaireDBContext : DbContext
public DbSet<Paquet> Paquets get; set;
public DbSet<Personne> Personnes get; set;
public DbSet<Contrat> Contrats get; set;
protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseSqlite(@"Data Source=db/Notaire.db");
public class Paquet
public int PaquetId get; set;
public string Numero get; set;
public DateTime Date get; set;
public string Volume get; set;
public string Page get; set;
public string Etat get; set;
public List<Contrat> Contrats get; = new List<Contrat>();
public class Personne
public int PersonneId get; set;
public string Nom get; set;
public string Prenom get; set;
public string Nom_pere get; set;
public PieceIdentite Piece_identite get; set;
public string Num_piece get; set;
public string Lieu_naissance get; set;
public string Date_naissance get; set;
public string Commune get; set;
public string Numero_acte get; set;
public string Laiv_carte get; set; //??????????????
public string Adresse get; set;
public string Nationalite get; set;
public string Fonction get; set;
public class Contrat
public int ContratId get; set;
public string Numero get; set;
public DateTime Date get; set;
public List<Personne> Partie_1 get; set;
public List<Personne> Partie_2 get; set;
public int PaquetId get; set;
public Paquet Paquet get; set;
观看次数:
PaquetsView.xaml(这是所有 paquets 的视图)
<ScrollViewer Background="#EBEEF5" HorizontalScrollBarVisibility="Disabled"
FlowDirection="RightToLeft">
<ItemsControl x:Name="PaquetsControl" Padding="4">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin" Value="5"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:PaquetControl/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<!--<controls:PaquetControl/>
<controls:PaquetControl/>-->
</ItemsControl>
</ScrollViewer>
我在 PaquetsView.xaml.cs 中像这样绑定它的 ItemsSource :
public partial class PaquetsView : UserControl
private NotaireDBContext db = new NotaireDBContext();
public PaquetsView()
InitializeComponent();
PaquetsControl.ItemsSource = (from p in db.Paquets select p).ToList();
PaquetView.xaml 的 DataTemplate -> ItemsControl 位于另一个 xaml 文件 (PaquetControl.xaml) 中,该文件是一个用户控件,由 TextBlocks 和带有菜单(和菜单项)的按钮组成,显示 Paquet 中保存的数据,以及应该能够编辑/删除所说的 Paquet。 一部分:
...
<Button x:Name="MoreButton" Style="DynamicResource MoreButtonTemplate"
Grid.Column="2" Click="MoreButtonClicked" Margin="0,-4,-4,0">
<Button.ContextMenu>
<ContextMenu Background="White" FlowDirection="RightToLeft">
<MenuItem Header="Edit" Click="EditMenuItemClick"/>
<MenuItem Header="Archive" Click="ArchiveMenuItemClick"/>
<MenuItem Header="حذف" Click="DeleteMenuItemClick"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
...
<TextBlock Grid.Column="0" Text="Binding Path=Numero" FontSize="22" Foreground="Black"/>
...
<TextBlock Grid.Row="1" Text="Binding Path=Date, StringFormat=yyyy/MM/dd"
Foreground="Black" FontSize="16"/>
...
<!--other TextBlock binded-->
现在我想知道如何通过更新视图使其成为 CRUD。
总结一下,我有一个用于数据持久性的 SQLite DB(代码优先),我可以使用 DBContext 获取该数据,但现在我发现使用 MVVM 比每次都创建 DBContext 更好。
【问题讨论】:
如果你说俄语,那么这里有一个有用的链接cyberforum.ru/wpf-silverlight/…如果你不明白,那就写吧。我会尽量澄清。 首先,@EldHasp,非常感谢,我尝试使用浏览器翻译阅读它,但没有太大帮助。因此,如果您能澄清一下,将不胜感激。 【参考方案1】:这是一个很大的话题,我怀疑它是否适合这里采用的格式。 因此,我将仅简要概述要点。
习惯上使用 MVVM 模式来实现 WPF。 它是一个严格的 3 层架构:View (WPF) -> ViewModel -> Model。 模型负责处理“真实”数据——这就是所谓的业务逻辑。 View 负责创建 GUI。 WPF 的特点是 UI 元素本身通过绑定请求所需的数据。 (主要)为 DataContext 创建绑定。 因此,有必要在其中放置一些特殊的自定义类型,负责 View 和 Model 之间的链接。 这种类型称为 ViewModel。 在典型的实现中,模型基本上是通过方法接收/返回数据。 绑定需要属性。 因此,ViewModel 的主要功能之一就是在其属性中提供 View 所需的所有数据。
当应用程序使用数据库时,Sharpe 习惯于在存储库(数据)模式中实现这一点。 从 MVVM 的角度来看,这样的存储库是模型的一部分。 但是,为了更简单的理解,为了便于软件维护,Repository 通常在单独的层中实现。 结果,我们得到了一个四层架构:View -> ViewModel -> Model -> Repository。
根据 OOP 的规则和原则,SOLID 在分层架构中,每一层只“知道”(拥有信息)底层。 并且所有非公开信息都必须封装在层内。
EF 实体反映数据库数据,它们是可变的,并且可以具有相应的属性。 更改源时,这些类型可以更改。 假设您在某个时候想要使用一组 XML 文件而不是数据库。 他们需要不同类型的实体。 因此,此类实体是存储库的内部实现。 并且要与模型交换数据,存储库必须是模型类型或通用 DTO 类型。
在下一级,ViewModel 还必须从 Model 接收数据。 但是这里不能使用模型类型,因为它们可以与业务逻辑隐式关联,并且有可能创建导致不可预知的错误的寄生连接。 在此级别(ViewMode-> Model),仅 DTO 类型用于数据交换。 它们最好是不可变的。
View 与 ViewModel 的下一级交换。 首先,GUI 通常需要可变属性。要自动更新属性视图,该类型必须实现 INotifyPropertyChanged。 其次,要从 GUI 调用操作,ViewModel 必须在其属性中提供 COMMANDS - 这是 ICommand 实现。 对于我在这里的答案,我使用的是BaseInpc and RelayCommand classes。 第三,在 View 的类型中,往往需要额外的属性来保证 GUI 操作的逻辑:一个被选中的元素,一个展开的元素,而不是记录的 Id,一个反映它的元素等。 由于这些原因,在 ViewModel 级别,您已经需要自己的类型以及 DTO 以外的实现。
基于上述结果,我们可以得到四种不同的实现,用于反映数据库中某些记录的类型。 每种类型的使用区域将在一层或两层。 为了不让这一切感到困惑,最好将每一层都放在一个单独的项目中。 仅在层内使用的类型在此项目中实现。 多个层使用的类型(例如,DTO)在单独的库中实现(可能用于简单任务和一个通用库)。 为了保持抽象,最好通过接口的初步声明来完成所有实现。 并通过这些接口在各层之间传递信息。
【讨论】:
以上是关于如何将 MVVM 与 EF 一起使用(在 SQLite 中使用非常复杂的数据库)?的主要内容,如果未能解决你的问题,请参考以下文章
使用 MVVM 创建具有现有外部属性的 EF Core 实体
如何将 RelayCommand 与 MVVM Light 框架一起使用
如何首先将 EF Core 代码与 azure synapse 一起使用
EF Core 5 - 如何将 EF.Functions.Like 与映射到 JSON 字符串的自定义属性一起使用?