`

打造自己的数据访问层

 
阅读更多

打造自己的数据访问层

 

http://database.51cto.com/art/201105/260494.htm

 

项目开发中,大多数开发人员的核心工作就是如何对数据进行存储及访问。.NET中,ADO.NET可以使用DbConnection进行连接,DataSet进行数据存储,DataAdapter进行数据更新。

 

项目开发中,大多数开发人员的核心工作就是如何对数据进行存储及访问。为了进行数据操作,我们首先得解决几个基本问题:

1、如何与一个数据库建立连接。

2、如何从数据库读取相应的数据。

3、如何对数据表进行增改操作。

.NET中,ADO.NET很方便的解决了上面三个问题,我们可以使用DbConnection进行连接,DataSet进行数据存储,DataAdapter进行数据更新。先看一段代码:

 

  1. //创建DbConnection对象连接数据库
  2. SqlConnection conn = new SqlConnection();
  3. conn.ConnectionString = "server=.;uid=sa;password=123456; database=DATA_BASE; max pool size=300;";
  4. //创建DataAdapter、Command对象,读取数据
  5. SqlDataAdapter da = new SqlDataAdapter();
  6. SqlCommand cmd = new SqlCommand();
  7. cmd.Connection = conn;
  8. cmd.CommandText = "SELECT * FROM TEST";
  9. da.SelectCommand = cmd;
  10. //创建DataSet对象,存储数据,建立与物理表的映射
  11. DataSet ds = new DataSet();
  12. da.Fill(ds, "TEST"); 

上述代码实现对数据库“DATA_BASE”中“TEST”表数据读取,并用DataSet时行存储。

既然读出了TEST表中的数据,接下来要解决的就是如何对TEST表进行增、删、改操作。

为实现增、删、改操作,需要为DataAdapter指定InsertCommand、DeleteCommand以及UpdateCommand,并为每个Command对象绑定参数:

 

 
  1. //新增数据  
  2. cmd = new SqlCommand();  
  3. cmd.Connection = conn;  
  4. cmd.CommandText = "INSERT INTO TEST (ID, NAME, VAL) VALUES (@ID, @NAME, @VAL)";  
  5. SqlParameter param = new SqlParameter("@ID"null);  
  6. param.SourceColumn = "ID";  
  7. cmd.Parameters.Add(param);  
  8. param = new SqlParameter("@NAME"null);  
  9. param.SourceColumn = "NAME";  
  10. cmd.Parameters.Add(param);  
  11. param = new SqlParameter("@VAL"null);  
  12. param.SourceColumn = "VAL";  
  13. cmd.Parameters.Add(param);  
  14. da.InsertCommand = cmd;  
  15.  
  16. //修改数据  
  17. cmd = new SqlCommand();  
  18. cmd.Connection = conn;  
  19. cmd.CommandText = "UPDATE TEST SET NAME = @NAME, VAL = @VAL WHERE ID = @ID";  
  20. param = new SqlParameter("@ID"null);  
  21. param.SourceColumn = "ID";  
  22. cmd.Parameters.Add(param);  
  23. param = new SqlParameter("@NAME"null);  
  24. param.SourceColumn = "NAME";  
  25. cmd.Parameters.Add(param);  
  26. param = new SqlParameter("@VAL"null);  
  27. param.SourceColumn = "VAL";  
  28. cmd.Parameters.Add(param);  
  29. da.UpdateCommand = cmd;  
  30.  
  31. //删除数据  
  32. cmd = new SqlCommand();  
  33. cmd.Connection = conn;cmd.CommandText = "DELETE FROM TEST WHERE ID = @ID";  
  34. param = new SqlParameter("@ID"null);  
  35. param.SourceColumn = "ID";  
  36. cmd.Parameters.Add(param);  
  37. da.DeleteCommand = cmd;

 

完成准备工作后,利用DataTable进行数据操作:

 

  1. DataTable dt = ds.Tables["TEST"];  
  2. dt.PrimaryKey = new DataColumn[] { dt.Columns["ID"] };  
  3. dt.Rows.Add(new object[]{  
  4.     Guid.NewGuid().ToString(), string.Format("测试:{0}", DateTime.Now), string.Format("测试值:{0}", DateTime.Now)  
  5. });  
  6. DataRow dr = dt.Rows.Find("f8dc2c64-f51a-4e99-bde1-a20069b09c3a");  
  7. if (dr != null){  
  8.     dr["NAME"] = string.Format("测试修改:{0}", DateTime.Now);  
  9. }  
  10. dr = dt.Rows.Find("ed7d079b-81ec-4ba4-bf85-688621e495e7");  
  11. if (dr != null){      
  12. dr.Delete();  

最后调用DataAdapter的Update方法保存变更后的数据:

da.Update(ds, "TEST");

利用ADO.NET的上述方法,我们已经完成了对数据库的完整操作。

 

注:上述代码是利用DataAdapter对数据库进行读写的基本原理,非常重要,我们后面的改造都将以此作为依据。

虽然我们已经能完成对数据的操作,但现实际上还是存在很多问题:

1、我们只是对MSSql数据库进行操作,如果要对Oracle或MySql进行操作我们得定义新的Oracle或MySql数据对象,如果能由系统自动判断操作的数据库类型,我们就能省去对数据对象的关注。

2、我们做了太多的准备工作,我们只对一张表进行操作,如查我们要对多张表进行操作,参数又很多,实际上会产生大量的重复代码,我们得考虑消除这些代码。

对于上述问题,如果我们自己实现一个数据访问层,对ADO.NET对象进行封装,只关注实际的数据的操作,而不关注系统是如何与数据库进行连接、如何进行参数传递,那我们的需求就算基本满足了。

我们可以先进行假设,需要达成如下效果,以伪码的形式给出:

  1. 创建数据执行者:DataExecuter:execObj;    
  2. 创建数据映射对象:DataMapping map;    
  3. 由映射对象填充数据集:map.Fill(sqlText, "TEST", ds);    
  4. 设置映射对象更新命令:map.SetCommands(Insert | Update | Delete, ds);    
  5. DataTable进行实际增、删、改操作。    
  6. 数据执行者执行最后的变更操作:execObj.Update(ds);    

后面我将一步步看到上述假设是如何实现的。

 

当我们通过上面已了解了.NET对数据库操作的基本原理,并就Ado.net对象的使用提出了几点疑问:

1、如何由系统来判断数据库型。

2、如何消除这些重复代码。

而上篇中也提出了一种解决思路,对ADO.NET对象进行封装,具体应该如何实施?

1、需要一个对象,该对象用于建立内存表与物理表的之间映射关系,解决数据查询、更新操作,形成了数据映射对象,定义为DataMapping。

2、每一个映射对象只与一张物理建立映射关系,如果有多个这样的对象同时操作,如何解决?这时就需要另一个对象,用于添加映射对象集合,打包映射对象操作,形成了数据执行者,定义为DataExecutor。

想想看,只需要这两个基本对象,就可以形成简单的数据访问层了。

先实现DataMapping,它应具备如下功能。

1、需要知道物理表的信息,表名、主键集、字段集。

2、需要知道映射的是什么类型的数据库,MSSql数据库、Oracle数据库、MySql数据库或者其他类型的数据库。

3、可查询数据,即填充内存表。

4、可更新数据,并且可设置更新操作方式。

5、可加入到事务中去。

根据上述功能,可初步设计出的DataMapping类:

 

public class DataMapping
{
   
public DataMapping()
    { }

   
/// <summary>
   
/// 填充数据集
   
/// </summary>
    public void Fill()
    {

    }

   
/// <summary>
   
/// 设置更新命令
   
/// </summary>
    public void SetCommands()
    {

    }

   
/// <summary>
   
/// 设置数据提交事务
   
/// </summary>
    public void SetTransaction()
    {

    }

   
/// <summary>
   
/// 提交数据
   
/// </summary>
    public bool Update()
    {

    }

   
/// <summary>
   
/// 更新列名
   
/// </summary>
    public string Columns
    {
       
get
        {
           
return columns;
        }
       
set
        {
            columns
= value;
        }
    }
   
private string columns = "";

   
/// <summary>
   
/// 主键名
   
/// </summary>
    public string KeyColumns
    {
       
get
        {
           
return keyColumns;
        }
       
set
        {
            keyColumns
= value;
        }
    }
   
private string keyColumns = "";

   
/// <summary>
   
/// 表名
   
/// </summary>
    public string TableName
    {
       
get
        {
           
return tableName;
        }
       
set
        {
            tableName
= value;
        }
    }
   
private string tableName = "";
}
再来实现DataExecutor类,它应具备的功能:

1、应该知道执行什么类型的数据库操作。

2、可以添加映射对象。

3、可以进行数据提交。

如何来知道执行的数据库类型,我们可以定义具体的执行者,比如MSSql执行者、Oracle执行者、MySql执行者。

可以初步设计出DataExecutor类

public abstract class DataExecutor
{
   
private IList<DataMapping> lisDataMappings = new List<DataMapping>();

   
/// <summary>
   
/// 添加数据映射对象
   
/// </summary>
    public void AddDataMapping(DataMapping map)
    {

    }

   
/// <summary>
   
/// 更新数据
   
/// </summary>
    public bool Update()
    {

    }
}

public class MSSqlExecutor : DataExecutor
{
   
}

public class OracleExecutor : DataExecutor
{

}

public class MySqlExecutor : DataExecutor
{

}
准备就绪,开始行具体设计。

先从DataMapping的Fill方法入手,看看它是如何查询数据的。

 

public void Fill(string sqlText, string tableName, DataSet ds)
{
    IDbConnection conn
= 具体的数据连接对象;
    IDbDataAdapter dataAdapter
= 具体的数据适配对象;
    IDbCommand cmd
= 具体的命令对象;
    cmd.Connection
= conn;
    cmd.CommandText
= sqlText;
    dataAdapter.SelectCommand
= cmd;
    ((DbDataAdapter)dataAdapter).Fill(ds, tableName);
}

问题出来了,这里出现了具体的对象,如何得到这些对象?

前面我们设计了MSSqlExecutor类,它已经知道具体的数据库类型,所以它也应该知道进行数据操作的具体的对象,DataMapping类是否可以引用该它,从而通过它来获取数据操作对象,因此,可以MSSqlExecutor类及DataMapping类进行修改,使DataMapping对MSSqlExecutor类产生依赖关系;这只是对MSSql数据库进行操作,现要改变数据库对象为Oracle了,DataMapping类应该也需要对OracleExecutor类产生依赖关系。

因此,这里可以设计一个接口,用于获取具体对象:

 

/// <summary>
/// 映射执行接口
/// </summary>
public interface IMappingExecute
{
   
/// <summary>
   
/// 获取连接对象
   
/// </summary>
    IDbConnection GetConn();

   
/// <summary>
   
/// 获取数据适配器
   
/// </summary>
    IDbDataAdapter GetDataAdapter();

   
/// <summary>
   
/// 获取命令对象
   
/// </summary>
    IDbCommand GetCommand();

   
/// <summary>
   
/// 获取命令参数
   
/// </summary>
    IDbDataParameter GetDataParameter(string col);

   
/// <summary>
   
/// 获取命令参数
   
/// 数据库之间的命令参类是不一样的
   
/// MMSql是“@” + 列名,Oracle是 “:” + 列名,MySql是 “?” + 列名
   
/// </summary>
    string GetSourceColumn(string col);
}

改造后的MSSqlExecutor类为:

 

public class MSSqlExecutor : DataExecutor, IMappingExecute { }

改造后的DataMapping类为:

 

public class DataMapping
{
   
private IDbConnection conn = null;
   
private IDbDataAdapter dataAdapter = null;

   
/// <summary>
   
/// 映射执行对象
   
/// </summary>
    public IMappingExecute ExecuteObject
    {
       
set
        {
            executeObj
= value;
            conn
= executeObj.GetConn();
        }
    }
   
private IMappingExecute executeObj;

   
/// <summary>
   
/// 填充数据集
   
/// 参数:查询语句
   
/// 参数:内存表名
   
/// </summary>
    public void Fill(string sqlText, string tableName, DataSet ds)
    {
        dataAdapter
= executeObj.GetDataAdapter();
        IDbCommand cmd
= executeObj.GetCommand();
        cmd.Connection
= conn;
        cmd.CommandText
= sqlText;
        dataAdapter.SelectCommand
= cmd;
        ((DbDataAdapter)dataAdapter).Fill(ds, tableName);
    }
}
到此为止,查询功能算是完成了,接下来该实现更新功能了,从SetCommands入手,以新增操作为例:
/// <summary>
/// 设置更新命令
/// </summary>
public void SetCommands(DataCommandType commandType, DataSet ds)
{

   
if ((commandType & DataCommandType.Insert) == DataCommandType.Insert)
    {
        CreateInsertCommand(ds);
    }

   
if ((commandType & DataCommandType.Update) == DataCommandType.Update)
    {
        CreateUpdateCommand(ds);
    }

   
if ((commandType & DataCommandType.Delete) == DataCommandType.Delete)
    {
        CreateDeleteCommand(ds);
    }
}


/// <summary>
/// 生成新增命令及SQL语句
/// </summary>
private void CreateInsertCommand(DataSet ds)
{
    IList
<string> lisColumns = GetColumns(ds);
    StringBuilder sbCol
= new StringBuilder();
    StringBuilder sbVal
= new StringBuilder();
   
foreach (string col in lisColumns)
    {
        sbCol.AppendFormat(
", {0}", col);
        sbVal.AppendFormat(
", {0}", executeObj.GetSourceColumn(col));
    }

    sbCol.Remove(
0, 2);
    sbVal.Remove(
0, 2);
   
string sqlText = string.Format("INSERT INTO {0} ({1}) VALUES ({2})", tableName, sbCol.ToString(), sbVal.ToString());
    IDbCommand cmd
= executeObj.GetCommand();
    cmd.Connection
= conn;
    cmd.CommandText
= sqlText;
    SetCommandParams(cmd, lisColumns);
    dataAdapter.InsertCommand
= cmd;
}

/// <summary>
/// 获取列字段集
/// </summary>
private IList<string> GetColumns(DataSet ds)
{
    IList
<string> lisColumns = new List<string>();
   
if (columns != "*")
    {
       
string[] sltCol = columns.Split(',');
       
foreach (string col in sltCol)
        {
            lisColumns.Add(col.Trim());
        }
    }
   
else
    {
        DataTable dt
= ds.Tables[tableName];
       
foreach (DataColumn dc in dt.Columns)
        {
            lisColumns.Add(dc.ColumnName);
        }
    }

   
return lisColumns;
}
更新操作非常简单,就是在上一篇的数据操作原理的基础上动态生成了查询语句及参数绑定,不多做解释。 

其中DataCommandType为自定义枚举类型:

 

/// <summary>
/// 数据操作命令类型
/// </summary>
public enum DataCommandType
{
   
/// <summary>
   
/// 新增
   
/// </summary>
    Insert = 1,

   
/// <summary>
   
/// 修改
   
/// </summary>
    Update = 2,

   
/// <summary>
   
/// 删除
   
/// </summary>
    Delete = 4
}

更新完后进行数据提交:

 

/// <summary>
/// 提交数据
/// </summary>
public bool Update(DataSet ds)
{
   
return ((DbDataAdapter)dataAdapter).Update(ds, tableName) > 0;
}

至此,数据更新操作也已经完成,最后再看看数据执行者是如何进行批量提交。

这里产生的第一个问题是,什么时候数据执行者会人将映射对象加入到集合中来,其中一种方法是在DataMapping设置更新的时候自己加入到集合去。

因此, 映射执行接口得多添加一个方法,用于新增映射对象:

 

/// <summary>
/// 添加数据映射对象
/// </summary>
void AddDataMapping(DataMapping map);
修改SetCommand方法:
/// <summary>
/// 设置更新命令
/// </summary>
public void SetCommands(DataCommandType commandType, DataSet ds)
{
   
//设置更新事件时添加映射对象
    executeObj.AddDataMapping(this);
}
现在执行者中已经存在了,可以进行最后的数据提交:
/// <summary>
/// 更新数据
/// </summary>
public bool Update(DataSet ds)
{
   
using (conn)
    {
       
if (conn.State == ConnectionState.Closed)
        {
            conn.Open();
        }

        IDbTransaction transaction
= conn.BeginTransaction(IsolationLevel.ReadCommitted);
       
foreach (DataMapping map in lisDataMappings)
        {
            map.SetTransaction(transaction);
        }

       
try
        {
           
foreach (DataMapping map in lisDataMappings)
            {
                map.Update(ds);
            }

            transaction.Commit();
        }
       
catch (Exception ex)
        {
            transaction.Rollback();
           
throw new System.Exception(ex.Message);
        }
    }

   
return true;
}

//DataMapping类设置事务
/// <summary>
/// 设置数据提交事务
/// </summary>
public void SetTransaction(IDbTransaction transaction)
{
   
if (dataAdapter.InsertCommand != null)
    {
    dataAdapter.InsertCommand.Transaction
= transaction;
    }

   
if (dataAdapter.UpdateCommand != null)
    {
    dataAdapter.UpdateCommand.Transaction
= transaction;
    }

   
if (dataAdapter.DeleteCommand != null)
    {
    dataAdapter.DeleteCommand.Transaction
= transaction;
    }
}
到些为止,我们自己的数据访问层功能已基本完成,但是,我们要如何对其进行调用,现在的方式真能方便的让我们进行调用吗?答案是否定的。
 

暂且至此为止,下一篇我们再进行最后的收尾工作,并最终打造成符合自己需求的数据访问层

 

我们已具体实现了数据访问层对应的功能,该进行收尾工作了,先来看段代码,试试上一篇实现的功能:

 

  1. string sqlText = "SELECT ID, NAME, VAL FROM TEST";  
  2. string columns = "ID, NAME, VAL";  
  3. DataSet ds = new DataSet();  
  4. DataExecutor execObj = new MSSqlExecutor();  
  5. DataMapping map = new DataMapping();  
  6. map.ExecuteObject = execObj;  
  7. map.TableName = "TEST";  
  8. map.KeyColumns = "ID";  
  9. map.Columns = "ID, NAME, VAL";  
  10. DataMapping map = new DataMapping(execObj.GetInstant(), "TEST""ID", columns);  
  11. map.Fill(sqlText, "TEST");  
  12. map.SetCommands(DataCommandType.Insert | DataCommandType.Update | DataCommandType.Delete, ds);  
  13. //DataTable方式进行增、删、改  
  14. bool isSuccess = execObj.Update(); 

果然已经完成了对数据库的读写操作了,至少不用再写大段的参数传递代码,功能都已经实现了,是不是就完成了?

仔细看看上面的代码,实际上还有问题尚未解决,看看这句:

  1. DataExecutor execObj = new MSSqlExecutor(); 

竟然在代码里直接实例化一个MSSql的执行对象,这样一开始提出的数据库之间的切换问题根本就没有从本质上解决。

再回过头来看上一篇,有一个方法public IDbConnection GetConn(),用来获取数据连接对像,之前并没有说明其如何实现。

我们知道DBConnection有两个关键信息:

1、与哪种类型的数据库产生连接,这个前面已经解决了。

2、传递与数据库连接的帐号信息、访问库信息的ConnectionString,这个并没有提及。

看看第二点以前是怎么做的:

 

  1. public IDbConnection GetConn()  
  2. {  
  3.     if (conn != null)  
  4.     {  
  5.         return conn;  
  6.     }  
  7.     conn = new SqlConnection();  
  8.     conn.ConnectionString = 连接字串;  
  9.     return conn;  

上面出现了连接字串,这个字串从哪来?

总结下,要完成最终的数据访问输出,还需要解决两个问题:

1、动态进行不同数据库之间的切换。

2、解决数据连接字串的来源问题。

接着就来解决这两问题,先解决第二个问题,有个比较简单的方法,将连接字串写入配置文件中去,数据访问层只需知道它传递过来KEY值:

 

  1. <appSettings>  
  2.     <add key="ConnStr" value="server=.;uid=sa;password=123456;database=DATA_BASE;max pool size=300"/>  
  3. </appSettings> 

第一个问题解决了,只剩下最后一个问题了,如何动态切换不同的数据库,也就是说,在使用的时候不需要自己NEW一个对象,而是通过第三方来创建一个对象,实际上,设计模式里已提出了方案,创建型模式,有兴趣的朋友可以自行研究,我们这里只需要用到简单工厂模式:

 

  1. public sealed class ExecutorFactory  
  2. {  
  3.     public static DataExecutor Create()  
  4.     {  
  5.         return Create(DatabaseType.MSSql);  
  6.     }  
  7.     public static DataExecutor Create(DatabaseType dbType)  
  8.     {  
  9.         AbstractDataBase dataBase = null;  
  10.         Switch(dbType)  
  11.         {  
  12.             case DatabaseType.MSSql:  
  13.                 dataBase = new MSSqlDataBase();  
  14.                 break;  
  15.             case DatabaseType.Oracle:  
  16.                 dataBase = new OracleDataBase();  
  17.                 break;  
  18.         }  
  19.         return dataBase.Create();  
  20.     }  

现在可对这句代码进行替换了:DataExecutor execObj = new MSSqlExecutor();

替换为:DataExecutor execObj = ExecutorFactory.Create();

至此,问题都解决了,切换数据库是只需更改DatabaseType为相应的数库类型。

接下来再考虑下,如果改变数据库类型也不需要变动程序,能不能实现?

还是利用配置文件,只是此时提供的不是类型字串,而是实际的数据执行者程序集信息,再利用.NET的天然优势反射可以实现了。
最终配置文件为:

 

  1. <appSettings>  
  2.     <add key="ConnStr" value="server=.;uid=sa;password=123456;database=DATA_BASE;max pool size=300"/>  
  3.     <add key="DBExecutor" value="FM.DataAccess, FM.DataAccess.MappingExcuter.MSSqlExecutor"></add>  
  4.   </appSettings> 

改造后的工厂:

 

  1. public sealed class ExecutorFactory  
  2.     {  
  3.         public static DataExecutor Create()  
  4.         {  
  5.             return Create(null);  
  6.         }  
  7.         public static DataExecutor Create(string dataBaseTypeKey)  
  8.         {  
  9.             return Create(dataBaseTypeKey, null);  
  10.         }  
  11.         public static DataExecutor Create(string dataBaseTypeKey, string connStrKey)  
  12.         {  
  13.             if (string.IsNullOrEmpty(dataBaseTypeKey))  
  14.             {  
  15.                 dataBaseTypeKey = "DBExecutor";  
  16.             }  
  17.             string[] sltDataBaseType = ConfigReader.Read(dataBaseTypeKey).Split(',');  
  18.             string asselblyName = sltDataBaseType[0];  
  19.             string nameSpace = sltDataBaseType[1].Trim();  
  20.             Assembly assembly = Assembly.Load(asselblyName);  
  21.             DataExecutor execObj = assembly.CreateInstance(nameSpace) as DataExecutor;  
  22.             execObj.SetConnectionString(connStrKey);  
  23.             return execObj;  
  24.         }  
  25.     } 

 

到此为止,数据访问层最终完成,当然这里还有很多问题有待解决,但其基本框架已形成了,以此为依据,根据业务变化,实现自己的扩展,不断更新,最终才能真正形成完善的数据访问层。

分享到:
评论

相关推荐

    Kyligence Zen 供应链场景数据集和行业指标模板.zip

    Kyligence Zen 是基于 Kyligence 核心 OLAP 能力打造的智能指标驱动的管理和决策平台。...通过 AI 增强的高性能分析引擎、统一 SQL 服务接口、业务语义层等功能,Kyligence 提供成本最优的多维数据分析能力,支撑企

    Qcon全球软件开发大会[20160423]_新时代的数据存储与访问技术专题

    5-4-饿了么异构服务平台数据访问层的演进-徐东焱 QCon是由InfoQ主办的全球顶级技术盛会,每年在伦敦、北京、东京、纽约、圣保罗、杭州、旧金山召开。自2007年3月份首次举办以来,已经有包括传统制造、金融、电信、...

    学生信息管理源码

    dao:数据访问层(data access object),与数据库的增删改查等方法的相关代码写在这。一般定义为dao层包括dao,daoImpl,分别为数据层接口和数据层实现类 biz:业务层,处理业务操作,可以与外部系统交流,算法的...

    java打造电影网站源码(springboot).zip

    本系统采用企业级开发标准,使用SpringBoot架构,数据访问层采用Spring Data Jpa,业务控制层采用SpringMvc,安全框架采用Shiro,实现了完整权限系统,Controller方法采用shiro注解,来实现有效的权限控制;...

    ASP.NET WebAPI+mvc4.0+EasyUI快速开发框架+通用权限管理系统源码

    框架特色: 1、基于ASP.NET MVC4.0 + WebAPI...6、数据访问层采用强大的Fluentdata完美地支持多数据库操作 7、封装了一大部分比较实用的控件和组件,如自动完成控件、弹出控件、拼音模糊输入控件、日期控件、导出组件等

    Web mvc4.0 EasyUI 最新 权限管理系统源码.zip

    框架特色: 1、基于ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout的架构设计开发 ...6、数据访问层采用强大的Fluentdata完美地支持多数据库操作 7、封装了一大部分比较实用的控件和组件,如自动完成控件、弹出。

    基于 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发

    二、框架特色 1、基于 ASP.NET MVC4.0 + ...6、数据访问层采用强大的Fluentdata完美地支持多数据库操作 7、封装了一大部分比较实用的控件和组件,如自动完成控件、弹出控件、拼音模糊输入控件、日期控件、导出组件等

    建筑材料管理系统

    1、基于 ASP.NET MVC4.0 + WebAPI + EasyUI ...6、数据访问层采用强大的Fluentdata完美地支持多数据库操作 7、封装了一大部分比较实用的控件和组件,如自动完成控件、弹出控件、拼音模糊输入控件、日期控件、导出组件等

    商城系统致力于为中小企业打造一个完整、易于维护的开源的电商商城系统

    dts-dao 数据访问层核心模块 ,供两个api模块引用 dts-wx-api 小程序api模块 (微信后台启动本模块即可) wx-mini-program 小程序前端代码 dts-job 分布式定时器模块 (VIP2.0版本独有) dts-merchant-api 商户管理...

    MVC+WebAPI+EasyUI+Knockout后台管理系统.zip

    基于Asp.Net MVC4.0 + WebAPI + Knockout ...6、数据访问层采用强大的Fluentdata完美地支持多数据库操作 7、封装了一大部分比较实用的控件和组件,如自动完成控件、弹出控件、拼音模糊输入控件、日期控件、导出组件等

    asp.net+Web+mvc4.0 EasyUI 最新 权限管理系统源码教程

    一、企业版简介 Zephyr.Net 企业版是基于...6、数据访问层采用强大的Fluentdata完美地支持多数据库操作 7、封装了一大部分比较实用的控件和组件,如自动完成控件、弹出控件、拼音模糊输入控件、日期控件、导出组件等

    Java框架springBoot企业级进销存ERP系统源码

    本系统采用企业级开发标准,使用SpringBoot架构,数据访问层采用Spring Data Jpa,业务控制层采用SpringMvc,安全框架采用Shiro,实现了完整权限系统,Controller方法采用shiro注解,来实现有效的权限控制;...

    特色小镇云脑整体解决方案.docx

    特色小镇云脑的建设目标是打造一个集数据采集、处理、分析、应用于一体的智能化管理平台,实现特色小镇内各类资源的优化配置和高效利用,提升特色小镇的管理水平和服务质量,促进特色小镇的经济、社会、文化等多方面...

    GoodProject Maven Webapp.zip

    1:数据访问层:主要是对非原始数据(数据库或者文本文件等存放数据的形式)的操作层,而不是指原始数据,也就是说,是对数据库的操作,而不是数据,具体为业务逻辑层或表示层提供数据服务. (主要用来访问数据库表) 2:...

    mvc4.0 EasyUI 权限管理系统源码.7z

    6、数据访问层采用强大的Fluentdata完美地支持多数据库操作% P' n/ H) J/ S9 g. U- N" w 7、封装了一大部分比较实用的控件和组件,如自动完成控件、弹出控件、拼音模糊输入控件、日期控件、导出组件等.

    特色小镇大脑建设方案.docx

    特色小镇大脑建设方案旨在通过集成先进的信息技术和智能化应用,为特色小镇打造一个集数据管理、智能决策、服务创新于一体的智慧化平台。以下是特色小镇大脑建设方案的主要内容: 一、建设目标 特色小镇大脑的建设...

    物流小镇大脑建设方案.docx

    信息安全与隐私保护技术:采用加密、访问控制等技术手段,确保数据的安全性和隐私保护。 四、平台部署与运维 硬件环境:选择高性能的服务器、网络设备和存储设备等,确保平台的稳定运行和数据安全。 软件环境:部署...

    搜一次CMS电影程序 v4.0.0.rar

    06、成果保护系统:系统内置的图片水印添加功能以及数据地址两层嵌套加密的方式,让你达到真正的保护效果;从而保护您辛苦手动更新的成果不被其他站长轻易盗走,提高网站竞争优势 07、多组合网站运行模式:支持...

    搜一次CMS电影程序 v4.0.1.rar

    06、成果保护系统:系统内置的图片水印添加功能以及数据地址两层嵌套加密的方式,让你达到真正的保护效果;从而保护您辛苦手动更新的成果不被其他站长轻易盗走,提高网站竞争优势 07、多组合网站运行模式:支持...

    6、段子发布平台大学生系统(ssm-vue).zip

    MyBatis作为持久层框架,实现了数据库操作的自动化与定制化,提升了数据访问的效率。 前端部分,采用Vue.js框架构建单页面应用,通过组件化的开发方式,实现了页面的快速搭建与灵活调整。同时,Vue.js的响应式数据...

Global site tag (gtag.js) - Google Analytics