当前位置: 首页 > 工具软件 > SqlSugar > 使用案例 >

MVVM+三层架构+SqlSugar(code First)

马胜泫
2023-12-01

本篇文章主要分享本人对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,
        }

    }
}


 

公共类中有一些是不需要的枚举,可以不用完全借鉴

欢迎各位大神指导评论
 

 类似资料: