本篇文章主要分享本人对MVVM,三层架构与ORM框架的一些心得,如果各路大神有其他看法可以在评论区评论,欢迎各位提出指导意见。废话不多说直接上图上代码。
这个软件是以学生信息管理系统为例子,UI 层提供对学生信息的增加,删除,修改,查询功能,对应到底层对数据库实现增删改查的操作.下面我就以三层架构的思维从上往下一一描述。
1.UI 层
这里采用了MVVM 的设计架构,目的是让视图代码和数据模型降低耦合,实现属性,方法的绑定。在控件上我稍微使用了控件模板和样式。
(1)View 代码:
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
{
///
/// MainWindow.xaml 的交互逻辑
///
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
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 StudentList { get { return studentData; } set { studentData = value;PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("StudentList")); } }
private List studentData = new List() { };
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 QueryData()
{
List dataTable = new List();
dataTable = sqlSugerHelper.Query();
return dataTable;
}
public void DeleteData(StudentModel studentModel)
{
sqlSugerHelper.Delete(studentModel);
}
public void UpdataData(StudentModel studentModel)
{
sqlSugerHelper.Updata(studentModel);
}
private DataTable ListToDt(IEnumerable 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("select * from StudentData"); // 数据库语句
}
public List Query()
{
List studentModels = new List();
studentModels=sqlSugarClient.Queryable().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,
}
}
}
公共类中有一些是不需要的枚举,可以不用完全借鉴
欢迎各位大神指导评论