赞
踩
本篇文章主要分享本人对MVVM,三层架构与ORM框架的一些心得,如果各路大神有其他看法可以在评论区评论,欢迎各位提出指导意见。废话不多说直接上图上代码。
这个软件是以学生信息管理系统为例子,UI 层提供对学生信息的增加,删除,修改,查询功能,对应到底层对数据库实现增删改查的操作.下面我就以三层架构的思维从上往下一一描述。
1.UI 层
这里采用了MVVM 的设计架构,目的是让视图代码和数据模型降低耦合,实现属性,方法的绑定。在控件上我稍微使用了控件模板和样式。
(1)View 代码:
- <Window x:Class="MVVMTest.View.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:MVVMTest.View"
- xmlns:prism="http://prismlibrary.com/"
- xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
- mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
- <Window.Resources>
-
- <Style x:Key="buttonStyle" TargetType="Button">
- <Setter Property="Margin" Value="30,5,30,5" />
- <Setter Property="FontSize" Value="20"/>
- <Setter Property="Background" Value="White"/>
- <Setter Property="Template">
- <Setter.Value>
- <ControlTemplate TargetType="Button">
- <Border CornerRadius="10" BorderBrush="Blue" BorderThickness="1" Background="{TemplateBinding Background}">
- <!--继承父控件的Content样式-->
- <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
- </Border>
- <!--触发器,可以根据需求给控件增加不同的触发方法-->
- <ControlTemplate.Triggers>
- <Trigger Property="IsMouseOver" Value="true">
- <Setter Property="Background" Value="Aqua"></Setter>
- </Trigger>
- <Trigger Property="IsPressed" Value="true">
- <Setter Property="Background" Value="ForestGreen"></Setter>
- </Trigger>
- </ControlTemplate.Triggers>
- </ControlTemplate>
- </Setter.Value>
- </Setter>
- </Style>
- </Window.Resources>
- <Grid >
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="0.7*"/>
- <ColumnDefinition Width="0.3*"/>
- </Grid.ColumnDefinitions>
- <DataGrid Name="dataGrid" Grid.Column="0" CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding studentModel.StudentList, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" CanUserSortColumns="False" IsReadOnly="True" >
- <DataGrid.Columns>
- <DataGridTextColumn Header="名字" Width="*" Binding="{Binding Name}"></DataGridTextColumn>
- <DataGridTextColumn Header="年龄" Width="*" Binding="{Binding Year}"></DataGridTextColumn>
- <DataGridTextColumn Header="地址" Width="*" Binding="{Binding Address}"></DataGridTextColumn>
- <DataGridTextColumn Header="电话号码" Width="*" Binding="{Binding PhoneNumber}"></DataGridTextColumn>
- </DataGrid.Columns>
- <i:Interaction.Triggers>
- <i:EventTrigger EventName="SelectionChanged">
- <i:InvokeCommandAction Command="{Binding selectItemChangedCommand}" CommandParameter="{Binding ElementName=dataGrid, Path=SelectedItem}"/>
- </i:EventTrigger>
- </i:Interaction.Triggers>
- </DataGrid>
- <Grid Grid.Column="1">
- <Grid.RowDefinitions>
- <RowDefinition/>
- <RowDefinition/>
- </Grid.RowDefinitions>
- <GroupBox Grid.Row="0" Header="学生信息">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition/>
- <RowDefinition/>
- <RowDefinition/>
- <RowDefinition/>
- </Grid.RowDefinitions>
- <StackPanel Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
- <Label Content="姓名:"/>
- <TextBox Name="txbName" Margin="10,0,10,0" Width="150" Text="{Binding studentModel.Name, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, FallbackValue=Error}"/>
- </StackPanel>
- <StackPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
- <Label Content="年龄:"/>
- <TextBox Name="txbYear" Margin="10,0,10,0" Width="150" Text="{Binding studentModel.Year, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, FallbackValue=Error}" />
- </StackPanel>
- <StackPanel Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
- <Label Content="地址:"/>
- <TextBox Name="txbAddress" Margin="10,0,10,0" Width="150" Text="{Binding studentModel.Address, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, FallbackValue=Error}" />
- </StackPanel>
- <StackPanel Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
- <Label Content="电话:"/>
- <TextBox Name="txbPhone" Margin="10,0,10,0" Width="150" Text="{Binding studentModel.PhoneNumber, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged, FallbackValue=Error}" />
- </StackPanel>
- </Grid>
- </GroupBox>
- <GroupBox Grid.Row="1" Header="数据操作">
- <Grid>
- <Grid.RowDefinitions>
- <RowDefinition/>
- <RowDefinition/>
- <RowDefinition/>
- <RowDefinition/>
- </Grid.RowDefinitions>
- <Button Grid.Row="0" Style="{StaticResource buttonStyle}" Command="{Binding buttonQueryCommand}" Content="查询"/>
- <Button Grid.Row="1" Style="{StaticResource buttonStyle}" Command="{Binding buttonInsertCommand}" Content="新增"/>
- <Button Grid.Row="2" Style="{StaticResource buttonStyle}" Command="{Binding buttonUpdataCommand}" Content="修改"/>
- <Button Grid.Row="3" Style="{StaticResource buttonStyle}" Command="{Binding buttonDeleteCommand}" Content="删除"/>
- </Grid>
- </GroupBox>
- </Grid>
- </Grid>
- </Window>
PS:在界面底下构造需要把Viewmodel 的数据绑定到前端中,可以组合引用
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- using MVVMTest.ViewModel;
- using MVVMTest.View;
-
-
- namespace MVVMTest.View
- {
- /// <summary>
- /// MainWindow.xaml 的交互逻辑
- /// </summary>
- public partial class MainWindow : Window
- {
- public MainWindow()
- {
- InitializeComponent();
- DataContext = MainViewModel.Instance;
- }
-
- }
-
- }
(2)ViewModel 代码(这里跟事件的绑定我使用了Prism 框架,因为不想自己造轮子,其他的框架也是可以的,这块业务我使用了单例去设计)
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using MVVMTest.Model;
- using Prism.Commands;
-
- namespace MVVMTest.ViewModel
- {
- public class MainViewModel
- {
- static MainViewModel()
- {
- }
- private MainViewModel()
- {
- IniViewModel();
- BusinessLogic.BusinessLogic.Instance.SetRequest(studentModel.GetType());
- }
- public static MainViewModel Instance { get; } = new MainViewModel(); //这里使用单例去做业务处理
-
- //控件命令列表
- // Prism 框架下的事件绑定,可带参和不带参
- private DelegateCommand _buttonQueryCommand;
- public DelegateCommand buttonQueryCommand =>
- _buttonQueryCommand ?? (_buttonQueryCommand = new DelegateCommand(ViewQuery));
-
- private DelegateCommand _buttonInsertCommand;
- public DelegateCommand buttonInsertCommand =>
- _buttonInsertCommand ?? (_buttonInsertCommand = new DelegateCommand(ViewInsert));
-
- private DelegateCommand _buttonUpdataCommand;
- public DelegateCommand buttonUpdataCommand =>
- _buttonUpdataCommand ?? (_buttonUpdataCommand = new DelegateCommand(ViewUpdata));
-
- private DelegateCommand _buttonDeleteCommand;
- public DelegateCommand buttonDeleteCommand =>
- _buttonDeleteCommand ?? (_buttonDeleteCommand = new DelegateCommand(ViewDelete));
-
- private DelegateCommand<object> _selectItemChangedCommand;
- public DelegateCommand<object> selectItemChangedCommand =>
- _selectItemChangedCommand ?? (_selectItemChangedCommand = new DelegateCommand<object>(GetModelObject));
-
- public StudentModel studentModel { get; set; }
-
- private StudentModel selectStudentModel = new StudentModel();
-
- private void IniViewModel()
- {
- studentModel = new StudentModel();
- }
- private void ViewQuery()
- {
- studentModel.StudentList = BusinessLogic.BusinessLogic.Instance.QueryData();
- }
- private void ViewInsert()
- {
- BusinessLogic.BusinessLogic.Instance.InsertData(studentModel);
- }
- private void ViewUpdata()
- {
- selectStudentModel.Name = studentModel.Name;
- selectStudentModel.Year = studentModel.Year;
- selectStudentModel.Address = studentModel.Address;
- selectStudentModel.PhoneNumber = studentModel.PhoneNumber;
- BusinessLogic.BusinessLogic.Instance.UpdataData(selectStudentModel);
- }
- private void ViewDelete()
- {
- BusinessLogic.BusinessLogic.Instance.DeleteData(selectStudentModel);
- }
- private void GetModelObject(object obj)
- {
- if(obj!=null)
- {
- selectStudentModel = obj as StudentModel;
- }
- }
-
- }
- }
Model 层(Model 层主要用来创建数据模型 和 对数据库的映射,我这里使用了SqlSuger Code First 去实现数据库映射,同是界面对数据模型双向绑定 INotifyPropertyChanged 这个接口主要实现通知客户端数据刷新,System自带接口)
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.ComponentModel;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using SqlSugar;
-
-
- namespace MVVMTest.Model
- {
- [SugarTable("StudentData")] //映射表名
- public class StudentModel : INotifyPropertyChanged
- {
-
- private string _Name { get; set; }
- [SugarColumn(IsNullable =true)]
- public string Name
- {
- get { return _Name; }
- set
- {
- _Name = value;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
- }
- }
-
- private int _Id { get; set; }
- [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] //主键
- public int Id { get { return _Id; } set { _Id = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Id")); } }
-
-
- private string _Year { get; set; }
- [SugarColumn(IsNullable = true)]
- public string Year { get { return _Year; } set { _Year = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Year")); } }
-
- private string _Address { get; set; }
- [SugarColumn(IsNullable = true)]
- public string Address { get { return _Address; } set { _Address = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Address")); } }
-
- private string _PhoneNumber { get; set; }
- [SugarColumn(IsNullable = true)]
- public string PhoneNumber { get { return _PhoneNumber; } set { _PhoneNumber = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PhoneNumber")); } }
-
- [SugarColumn(IsIgnore = true)]
- public List<StudentModel> StudentList { get { return studentData; } set { studentData = value;PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("StudentList")); } }
-
- private List<StudentModel> studentData = new List<StudentModel>() { };
-
-
- public event PropertyChangedEventHandler PropertyChanged;
-
- }
- }
2.业务逻辑层(这里我也用了单例,并且保证线程安全)
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Data;
- using MVVMTest.DataAccess.DataBase;
- using MVVMTest.Common;
- using MVVMTest.Model;
- using System.Data;
- using System.Collections;
- using System.Reflection;
-
- namespace MVVMTest.BusinessLogic
- {
- class BusinessLogic
- {
- private BusinessLogic()
- {
-
- }
- private static readonly object obj=new object();
- private volatile static BusinessLogic instance = null;
- SqlSugerHelper sqlSugerHelper = new SqlSugerHelper();
- public static BusinessLogic Instance
- {
- get
- {
- if(instance==null)
- {
- lock(obj)
- {
- if(instance == null)
- instance = new BusinessLogic();
- }
-
- }
- return instance;
- }
-
- }
- public void SetRequest(Type dataModel)
- {
- sqlSugerHelper.IniDB(GlobelEnum.DatabaseType.SqlServer, dataModel);
- }
- public void InsertData(StudentModel studentModel)
- {
- sqlSugerHelper.Insert(studentModel);
- }
- public List<StudentModel> QueryData()
- {
- List<StudentModel> dataTable = new List<StudentModel>();
- dataTable = sqlSugerHelper.Query();
- return dataTable;
- }
- public void DeleteData(StudentModel studentModel)
- {
- sqlSugerHelper.Delete(studentModel);
- }
- public void UpdataData(StudentModel studentModel)
- {
- sqlSugerHelper.Updata(studentModel);
- }
- private DataTable ListToDt<T>(IEnumerable<T> collection)
- {
- var props = typeof(T).GetProperties();
- var dt = new DataTable();
- dt.Columns.AddRange(props.Select(p => new
- DataColumn(p.Name, p.PropertyType)).ToArray());
- if (collection.Count() > 0)
- {
- for (int i = 0; i < collection.Count(); i++)
- {
- ArrayList tempList = new ArrayList();
- foreach (PropertyInfo pi in props)
- {
- object obj = pi.GetValue(collection.ElementAt(i), null);
- tempList.Add(obj);
- }
- object[] array = tempList.ToArray();
- dt.LoadDataRow(array, true);
- }
- }
- return dt;
- }
-
- }
- }
3.数据访问层(这里针对不同的数据库我使用了工厂模式去实现,由用户使用的时候再去选择实例哪一个数据库,这里的代码可能处理的不太好,欢迎大家发表不同意见)
(1)数据库基类
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Data;
- using SqlSugar;
-
- namespace MVVMTest.DataAccess.DataBase
- {
- public abstract class SqlBase
- {
- public abstract SqlSugarClient IniDb(Type DataModel, string DataBaseName, string ServerName) ;
-
- }
- }
(2)数据库子类(SqlSever)(这里设计SqlSuger Code First 的代码)
- using SqlSugar;
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace MVVMTest.DataAccess.DataBase
- {
- public class SqlSever : SqlBase
- {
-
- public override SqlSugarClient IniDb(Type DataModel, string DataBaseName, string ServerName )
- {
- SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
- {
- ConnectionString =string.Format("server={0};database={1};uid=数据库账户;pwd=密码, ServerName, DataBaseName),
- DbType = SqlSugar.DbType.SqlServer,//设置数据库类型
- IsAutoCloseConnection = true,//自动释放数据务,如果存在事务,在事务结束后释放
- InitKeyType = InitKeyType.Attribute //从实体特性中读取主键自增列信息
- });
- db.Aop.OnLogExecuting = (sql, pars) =>
- {
- Console.WriteLine(sql + "\r\n" +
- db.Utilities.SerializeObject(pars.ToString())); //打印数据库日志
- Console.WriteLine();
- };
- //创建数据库 如果该库不存在,则进行创建。(这里创建的是名字为 Student 数据库)
- db.DbMaintenance.CreateDatabase();
- //初始化数据表,如果没有则创建
- db.CodeFirst.InitTables(DataModel);
- return db;
- }
- }
- }
(3)数据库子类(Sqlite)
- using SqlSugar;
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace MVVMTest.DataAccess.DataBase
- {
- public class Sqlite : SqlBase
- {
-
- public override SqlSugarClient IniDb(Type DataModel, string DataBaseName, string ServerName)
- {
- SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
- {
- ConnectionString = string.Format("server={0};database={1};uid=数据库账户;pwd=密码", ServerName, DataBaseName),
- DbType = SqlSugar.DbType.Sqlite,//设置数据库类型
- IsAutoCloseConnection = true,//自动释放数据务,如果存在事务,在事务结束后释放
- InitKeyType = InitKeyType.Attribute //从实体特性中读取主键自增列信息
- });
-
- db.Aop.OnLogExecuting = (sql, pars) =>
- {
- Console.WriteLine(sql + "\r\n" +
- db.Utilities.SerializeObject(pars.ToString()));
- Console.WriteLine();
- };
- //创建数据库 如果该库不存在,则进行创建。(这里创建的是名字为 Student 数据库)
- db.DbMaintenance.CreateDatabase();
- //初始化数据表,如果没有则创建
- db.CodeFirst.InitTables(DataModel);
- return db;
- }
-
- }
- }
(4) 数据库工厂
- using MVVMTest.Common;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
-
- namespace MVVMTest.DataAccess.DataBase
- {
- public class DataBaseFactory
- {
- private DataBaseFactory()
- {
-
- }
- static DataBaseFactory() { }
- public static DataBaseFactory Instance { get; } = new DataBaseFactory();
-
- public SqlBase Create(GlobelEnum.DatabaseType databaseType)
- {
- SqlBase dataBaseFactory = null;
- switch(databaseType)
- {
- case GlobelEnum.DatabaseType.MySql:
- break;
- case GlobelEnum.DatabaseType.SqlServer:
- dataBaseFactory = new SqlSever();
- break;
- }
- return dataBaseFactory;
- }
- }
- }
(5)数据库访问接口
- using MVVMTest.Common;
- using MVVMTest.Model;
- using SqlSugar;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using MVVMTest.Model;
- using System.Data;
-
- namespace MVVMTest.DataAccess.DataBase
- {
- public class SqlSugerHelper
- {
-
- SqlBase sqlBase;
- SqlSugarClient sqlSugarClient;
- public void IniDB(GlobelEnum.DatabaseType databaseType, Type dataModel)
- {
-
- sqlBase = DataBaseFactory.Instance.Create(databaseType);
- sqlSugarClient = sqlBase.IniDb(dataModel, "Student", "服务器名称");
- }
- public void Insert(StudentModel studentModel)
- {
-
- sqlSugarClient.Insertable(studentModel).ExecuteCommand();
- //var a = sqlSugarClient.Ado.SqlQuery<StudentModel>("select * from StudentData"); // 数据库语句
- }
- public List<StudentModel> Query()
- {
- List<StudentModel> studentModels = new List<StudentModel>();
- studentModels=sqlSugarClient.Queryable<StudentModel>().ToList();
- sqlSugarClient.Close();
- return studentModels;
- }
-
- public void Delete(StudentModel studentModel)
- {
- sqlSugarClient.Deleteable(studentModel).ExecuteCommand();
- }
- public void Updata(StudentModel studentModel)
- {
- sqlSugarClient.Updateable(studentModel).ExecuteCommand();
- }
-
- }
- }
公共类
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
-
- namespace MVVMTest.Common
- {
- public static class GlobelEnum
- {
- public enum SqlCommand
- {
- Invalid=-1,
- IniDB=0,
- Query=1,
- Insert=2,
- Updata=3,
- Delete=4,
- }
-
- public enum DatabaseType
- {
- Invalid=0,
- Sqlite=1,
- SqlServer=2,
- MySql=3,
- }
-
- public enum ORMType
- {
- Invalid = 0,
- CodeFirst=1,
- DBFirst=2,
- ModelFirst=3,
- }
-
- }
- }
公共类中有一些是不需要的枚举,可以不用完全借鉴
欢迎各位大神指导评论
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。