AppFramework1.0数据库访问组件使用说明(五)IDBSession使用详解

 
IDBSession负责与数据库打交道,它通过ADO.NET实现几种常用数据库的连接。目前支持3种数据库:SQLServer(7.0、2000、2005三个版本,推荐2005)、ORACLE(8.1.7以上,推荐9i)、MSAccess(需要MDAC1.7以上支持)。与IDBSession有关的关系图如下:
 
 
 
 
 
 
 
 
 
 
IDBSession提供了跨平台、参数化的SQL执行,直接支持数据库内分页,提供强大的无SQL查询构造器。在提供简单、易用、跨平台功能的同时,并不以损失执行性能为代价,基于IDBSession编写数据库访问程序性能与直接基于ADO.NET的程序相当。
有三种方式获取IDBSession:直接构造、通过工厂类构造、通过会话管理器获取,推荐使用第三种方法,通过会话管理器获取IDBSession。
方法一:直接构造
public IDBSession CreateSession(string connectionString)
{
    return new AccessDBSession(connectionString);
}
 
方法二:用工厂类构造
IDBSessionFactory factory = new OracleDBSessionFactory(dbVersion, connectionString);
IDBSession session = factory.Create();
IDBSession session = factory.Create(newConnectionString);
相比方法一,方法二代码更容易在不同数据库上迁移。
 
方法三:用会话管理器
第一步:配置会话管理器
         配置会话管理器有两种方法,一种是配置 DBAccess.config ,会话管理器会自动加载 DBAccess.config 。通常 DBAccess.config 放在 Web 应用程序的虚拟目录的根目录下或 Config 子目录下,或者放在 Windows 应用程序的启动目录或 Config 子目录下。具体内容请参考前文“配置 DBAccess.config ”;另一种方法是用代码初始化会话管理器:
         IDBSessionManager defaultManager = new DBSessionManager();
         defaultManager.Add(“IMS”,DBType.Oracle,”9.2”, true,IMSConnectionString);
         defaultManager.Add(“ABC”,DBType.SQLServer,”8.0”, true, ABCConnectionString);
 
第二步:获取 IDBSession
IDBSession session = DBSessionManager.Default.GetSession()
IDBSession session = DBSessionManager.Default.GetSession(“IMS”)
 
方法三比方法二更具有灵活性,由于数据库连接都配置在配置文件里,在部署和切换数据库环境时,只需修改配置文件而不用重新编译程序。
属性名
类型
说明
DBType
DBType
获取数据库类型,例如DBType.Oracle、DBType.SQLServer等等
State
DBSessionState
数据库连接状态,Open或Close
IgnoreCase
bool
获取或设置此数据库在作字符串比较时是否忽略大小写, 默认为 true。对于Oracle这类区分大小写的数据库,IDBSession将自动用upper(字段名)的方式实现不区分大小写值比较,这在性能上有一定损耗。
IsCaseSensitiveDB
bool
表明此数据库是否为大小写区分
Columns
DBColumns
获取最后一次查询的结果集字段列表
AutoGenerateColumns
bool
获取或设置查询时是否自动生成 Columns 属性,默认为 true。如果不关注返回的字段列表,可以把此属性设置为false以提高批量处理性能。
DbConnection
DbConnection
获取或设置内部使用的 DbConnection,便于与其他数据库访问组件交互调用。
DbTransaction
DbTransaction
获取或设置内部使用的 DbTransaction,便于与其他数据库访问组件交互调用。
AllowSubqueryPaging
bool
获取或设置是否用子查询对翻页进行优化,默认为 true。例如对于Oracle,使用rownum作分页查询。
ReadStartIndex
int
分页查询参数,读取数据的开始行索引号,从0开始,默认为0。
ReadMaxCount
int
分页查询参数,读取的最大记录数,默认为0,表示读取所有。
RecordCount
int
获取查询命中的总记录数
ComputeRecordCount
bool
获取或设置是否计算记录总数,默认为 false。如果设置为true,IDBSession 将统计查询命中的记录数,会降低查询性能,合适的做法是仅在分页查询打开第一页时统计一次记录总数,而后续的页面浏览不再统计记录总数。
ComputeRecordCountOnly
bool
获取或设置是否只计算记录总数,默认为 false。此属性可以方便用于统计SQL返回记录数而不返回结果集。
SqlBuilder
ISqlBuilder
获取 ISqlBuilder接口。ISqlBuilder接口提供了跨数据库SQL语句统一构造接口,封装了常用的数据库函数,例如字符串连接、TRIM、取字符串子串等。
 
打开和关闭数据库会话、启动、提交和回滚数据库事务的方法如下:
/// <summary>
/// 打开连接,重复执行此操作无效但不出错
/// </summary>
void Open();
 
/// <summary>
/// 关闭连接,重复执行此操作无效但不出错
/// </summary>
void Close();
 
/// <summary>
/// 开始新事务,重复执行此操作只会增加嵌套级别但不出错。
/// </summary>
void BeginTran();
 
/// <summary>
/// level 事务级别开始新事务,重复执行此操作只会增加嵌套级别但不出错。
/// </summary>
void BeginTran(IsolationLevel level);
 
/// <summary>
/// 提交事务,若有事务嵌套,则只在最外层才提交。如果事务尚未打开则抛出 TransactionNotBeginException
/// </summary>
void CommitTran();
 
/// <summary>
/// 如果已启动事务,无论嵌套多少级别都回滚整个事务,重复调用也不出错。
/// </summary>
void RollbackTran();
相比ADO.NET提供的对应功能,AppFramework实现的更加智能化,例如Open和Close允许重复执行,提高了容错性;允许事务嵌套,自动判断嵌套层数,仅在最外层启动和提交事务,这极大方便了业务类之间的事务组合,不会像ADO.NET多次启动事务导致异常。
/// <summary>
/// 执行命令,返回 Update/Delete/Insert 所影响的记录条数
/// </summary>
/// <param name="cmdText"> 命令 SQL</param>
/// <returns> 受影响的记录数 </returns>
int ExecCmd(string cmdText);
 
/// <summary>
/// 执行查询,返回结果集的第一行第一列
/// </summary>
/// <param name="cmdText"> 语句命令 </param>
/// <returns> 返回 Object 对象,调用者要自己转换类型 </returns>
object QueryScalar(string cmdText);
 
/// <summary>
/// 查询并只返回第一条记录
/// </summary>
/// <param name="cmdText"> 命令 SQL</param>
/// <returns> 字段值数组 </returns>
object[] Get(string cmdText);
 
/// <summary>
/// 查询并只返回第一条记录所构造出的对象
/// </summary>
/// <param name="cmdText"> 命令 SQL</param>
/// <param name="create"> 对象构造器 </param>
/// <returns> 返回构造的对象 </returns>
object Get(string cmdText, ObjectConstructionEventHandler create);
 
/// <summary>
/// 查询,返回数据集,不支持分页
/// </summary>
/// <param name="cmdText"> 查询语句 </param>
/// <returns> 数据集 </returns>
DataSet QueryDataSet(string cmdText);
说明: SQLServer 数据库支持一次执行多条查询语句,放回多个结果集 DataSet 。其他数据库例如 Oracle SQL 语法不支持此功能。
 
/// <summary>
/// 查询,返回数据表,支持分页
/// </summary>
/// <param name="cmdText"> 查询语句 </param>
/// <returns> 数据表 </returns>
DataTable QueryDataTable(string cmdText);
1.1.5  以SqlTemplate为参数的命令
SqlTemplate(SQL模板)实现SQL语句的可配置化,类似IBatis的SqlMapper,支持与IBatis相似的动态SqlMap语法。关于SqlTemplate及其使用,请参考本文后续章节。IDBSession支持通过SqlTemplate作增删改查,并支持数据库内翻页查询,这一功能比IBatis要实用和强大得多,性能也比IBatis略好。
/// <summary>
/// 执行命令,返回 Update/Delete/Insert 所影响的记录条数
/// </summary>
/// <param name="template">SQL 模板 </param>
/// <param name="parameters"> 参数 </param>
/// <returns> 受影响的记录数 </returns>
int ExecCmd(SqlTemplate template, IDictionary<string, object> parameters);
 
/// <summary>
/// 执行命令,返回 Update/Delete/Insert 所影响的记录条数
/// </summary>
/// <param name="template">SQL 模板 </param>
/// <param name="parameters"> 参数 </param>
/// <returns> 受影响的记录数 </returns>
object QueryScalar(SqlTemplate template, IDictionary<string, object> parameters);
 
/// <summary>
/// 查询,返回数据表,支持分页
/// </summary>
/// <param name="template">SQL 模板 </param>
/// <param name="parameters"> 参数 </param>
/// <returns> 数据表 </returns>
DataTable QueryDataTable(SqlTemplate template, IDictionary<string, object> parameters);
SqlTemplate适合于实现复杂的统计查询,当查询条件较多、统计逻辑较复杂时,为了提高代码的可读性,可以牺牲一些数据库移植性或者少量的执行性能,把SQL语句写在配置文件里,方便分析和阅读。
 
关于SqlTempate,这里提供几个使用例子:
SqlTemplate updateUserSqlTemplate = new SqlTemplate(@"<statement id=""UpdateUser"">
    update BAS_USER set
    Name = #Name#,
    En_Name=#En_Name#,
    Password=#Password#,
    Dept_id=#Dept_id#,
    Org_id=#Org_id#,
    Employee_NO=#Employee_NO#,
    Email=#Email#,
    State=#State#,
    Creator_ID=#Creator_ID#,
    Created_Time=#Created_Time#,
    Updated_By=#Updated_By#,
    Updated_Time=#Updated_Time#,
    Age=#Age#
    WHERE id=#ID#
 </statement> ");
 
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters[“Name”] =”user_name”;
parameters[“En_Name”] =”user_ en_name”;
……
 
using (IDBSession session = DBSessionManager.Default.GetSession())
{
         int rowCount = session.ExecCmd(updateUserSqlTemplate, parameters);
}
       
通常SqlTemplate的SQL模板都配置在配置文件里,通过管理器统一加载。AppFramework的DaoGen文件支持编写SqlTemplate,代码生成器将把SqlTemplate生成SqlMap类的派生类,并把相应的参数生成为类属性,方便了SQL模板的使用,避免了因文字错误或大小写错误导致调用失效。SqlMap使用例子如下:
UpdateUserSqlMap user = new UpdateUserSqlMap();
 
user.ID = 100;
user.Name = "BatisName";
user.En_Name = "EnBatisName";
user.Created_Time = DateTime.Now;
user.Creator_ID = 0;
user.Dept_id = 100;
user.Email = "Email";
user.Employee_NO = "EmployeeNO";
user.Org_id = 0;
user.Password = "Password";
user.State = 0;
user.Updated_By = 0;
user.Updated_Time = DateTime.Now;
user.Age = 25;
 
using (IDBSession session = DBSessionManager.Default.GetSession())
{
return session.ExecCmd(user.Template, user.Parameters);
}
以下命令提供一种途径实现高性能的增删改查,特别适合代码生成器使用,但不适合手工编码人员使用。其中用到了QueryFilter查询条件构造器,详细使用方法请参考本文后续章节内容。
/// <summary>
/// 插入一条记录到指定表中,返回受影响的记录数
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 字段参数数组 </param>
/// <returns> 受影响的记录数 </returns>
int Insert(string tableName, params DBField[] fields);
 
/// <summary>
/// 查询并只返回第一条记录 [ 高性能的命令,为代码生成器优化 ]
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 字段名或表达式 , * ”表示所有字段 </param>
/// <param name="filter"> 条件 </param>
/// <returns> 字段值数组 </returns>
object[] Get(string tableName, string fields, string filter);
 
/// <summary>
/// 更新表,返回受影响的记录数 [ 高性能的命令,为代码生成器优化 ]
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="filter"> 更新条件 </param>
/// <param name="fields"> 字段参数数组 </param>
/// <returns> 受影响的记录数 </returns>
int Update(string tableName, string filter, params DBField[] fields);
 
/// <summary>
/// 删除表记录,返回受影响的记录数 [ 高性能的命令,为代码生成器优化 ]
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="filter"> 更新条件 </param>
/// <returns> 返回受影响的记录数 </returns>
int Delete(string tableName, string filter);
 
/// <summary>
/// 查询,支持分页,如果 IDBSesssion ComputeRecordCountOnly 属性为 true ,则返回 null [ 高性能的命令,为代码生成器优化 ]
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 字段名或表达式 , * ”表示所有字段 </param>
/// <param name="filter"> 条件 </param>
/// <param name="orderBy"> 排序表达式 </param>
/// <returns> 数组,每个元素是一个字段值数组 object[]</returns>
IList<object[]> Select(string tableName, string fields, string filter, string orderBy);
 
/// <summary>
/// 查询 [ 高性能的命令,为代码生成器优化 ]
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 字段名或表达式 </param>
/// <param name="filter"> 条件 </param>
/// <param name="orderBy"> 排序表达式 </param>
/// <param name="resultList"> 用来存放对象的链表 </param>
/// <param name="create"> 对象构造器 </param>
void Select(string tableName, string fields, string filter, string orderBy, IList resultList, BatchObjectConstructionEventHandler create);
QueryFilter功能强大用途广泛,本后后续章节有详细说明。SelectStatement类也是基于QueryFilter实现的,因此基于SelectStatement的方法归根结底也是基于QueryFilter的。与QueryFilter相关的IDBSession方法数量较多,大致罗列如下:
/// <summary>
/// 用查询结果插入一批记录到指定表中,返回受影响的记录数
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 插入表的字段列表,用 "," 间隔 </param>
/// <param name="query"> 对查询的描述 </param>
/// <returns> 受影响的记录数 </returns>
int Insert(string tableName, string fields, SelectStatement query);
说明:此 Insert 方法实现 insert…select… 子查询插入语法。 SelectStatement 代表子查询,其查询结果将插入到名为 tableName 的表的 fields 字段里。
 
/// <summary>
/// 更新表,返回受影响的记录数
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="filter"> 更新条件 </param>
/// <param name="fields"> 字段参数数组 </param>
/// <returns> 受影响的记录数 </returns>
int Update(string tableName, QueryFilter filter, params DBField[] fields);
说明:此 Update 方法实现对名为 tableName 的表数据的更新, fields 表示字段名和字段值, filter 表示更新条件。
 
/// <summary>
/// 删除表记录,返回受影响的记录数
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="filter"> 更新条件 </param>
/// <returns> 返回受影响的记录数 </returns>
int Delete(string tableName, QueryFilter filter);
 
 
/// <summary>
/// 执行查询,返回结果集的第一行第一列
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="field"> 字段名或表达式 , * ”表示所有字段 </param>
/// <param name="filter"> 条件 </param>
/// <returns> 返回 Object 对象,调用者要自己转换类型 </returns>
object QueryScalar(string tableName, string field, QueryFilter filter);
 
/// <summary>
/// 执行查询,返回结果集的第一行第一列
/// </summary>
/// <param name="query"> 查询对象 </param>
/// <returns> 返回 Object 对象,调用者要自己转换类型 </returns>
object QueryScalar(SelectStatement query);
 
 
/// <summary>
/// 查询并只返回第一条记录
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 字段名或表达式 , * ”表示所有字段 </param>
/// <param name="filter"> 条件 </param>
/// <returns> 字段值数组 </returns>
object[] Get(string tableName, string fields, QueryFilter filter);
说明:此 Get 方法对名为 tableName 的表进行查询,但只返回第一条数据, fields 表示要求返回的字段, filter 表示查询条件,返回的 object[] 数组存放着查询到的记录的字段值,字段顺序与 fields 的字段书写顺序一致,如果 fields * ,则表示返回所有字段,字段顺序由表字段顺序和数据库决定。
因为涉及到字段顺序,此方法适合代码生成器使用。
 
/// <summary>
/// 查询并只返回第一条记录
/// </summary>
/// <param name="query"> 查询对象 </param>
/// <returns> 字段值数组 </returns>
object[] Get(SelectStatement query);
说明:因为涉及到字段顺序,此方法适合代码生成器使用。
 
 
/// <summary>
/// 查询,返回字段数组链表,支持分页,如果 IDBSesssion ComputeRecordCountOnly 属性为 true ,则返回 null
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 字段名或表达式 , * ”表示所有字段 </param>
/// <param name="filter"> 条件 </param>
/// <param name="orderBy"> 排序表达式 </param>
/// <returns> 数组,每个元素是一个字段值数组 object[]</returns>
IList<object[]> Select(string tableName, string fields, QueryFilter filter, string orderBy);
说明:因为涉及到字段顺序,此方法适合代码生成器使用。
 
/// <summary>
/// 查询,支持分页,返回的对象放入 resultList 链表
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 字段名或表达式 </param>
/// <param name="filter"> 条件 </param>
/// <param name="orderBy"> 排序表达式 </param>
/// <param name="resultList"> 用来存放对象的链表 </param>
/// <param name="create"> 对象构造器 </param>
void Select(string tableName, string fields, QueryFilter filter, string orderBy, IList resultList, BatchObjectConstructionEventHandler create);
说明: Select 方法实现对表的查询,同时通过 create 委托为每条记录生成对象,并把对象放入 resultList 链表中。此方法性能比基于 DataTable 的查询好得多,测试数据表明,前者比后者性能高 30% 以上。相比 ObjectConstructionEventHandler BatchObjectConstructionEventHandler 是专为批量创建对象定制的委托,它允许把一些对象创建所需的中间结果保存到委托事件参数里,再让后续的对象创建过程使用,直接提高了批量创建对象的性能。
 
/// <summary>
/// 查询,支持分页,如果 IDBSesssion ComputeRecordCountOnly 属性为 true ,则返回 null
/// </summary>
/// <param name="query"> 查询对象 </param>
/// <returns> 数组,每个元素是一个字段值数组 object[]</returns>
IList<object[]> Select(SelectStatement query);
说明:因为涉及到字段顺序,此方法适合代码生成器使用。
 
/// <summary>
/// 查询,支持分页,返回的对象放入 resultList 链表
/// </summary>
/// <param name="query"> 查询对象 </param>
/// <param name="resultList"> 用来存放对象的链表 </param>
/// <param name="create"> 对象构造器 </param>
void Select(SelectStatement query, IList resultList, BatchObjectConstructionEventHandler create);
 
 
/// <summary>
/// 查询并只返回第一条记录
/// </summary>
/// <param name="tableName"> 表名 </param>
/// <param name="fields"> 字段名或表达式 </param>
/// <param name="filter"> 条件 </param>
/// <param name="create"> 对象构造器 </param>
/// <returns> 返回构造的对象 </returns>
object Get(string tableName, string fields, QueryFilter filter, ObjectConstructionEventHandler create);
 
/// <summary>
/// 查询并只返回第一条记录
/// </summary>
/// <param name="query"> 查询对象 </param>
/// <param name="create"> 对象构造器 </param>
/// <returns> 返回构造的对象 </returns>
object Get(SelectStatement query, ObjectConstructionEventHandler create);
 
 
/// <summary>
/// 查询,返回数据表,支持分页,如果 IDBSesssion ComputeRecordCountOnly 属性为 true ,则返回 null
/// </summary>
/// <param name="tableName"> 指定要填充的数据表名 </param>
/// <param name="fields"> 要查询的字段名 , * ”表示所有字段 </param>
/// <param name="filter"> 查询条件 </param>
/// <param name="orderBy"> 排序表达式,如: "xxxx asc, xxxx1 desc"</param>
/// <returns> 数据表 </returns>
DataTable QueryDataTable(string tableName, string fields, QueryFilter filter, string orderBy);
 
/// <summary>
/// 查询,返回数据表,支持分页,如果 IDBSesssion ComputeRecordCountOnly 属性为 true ,则返回 null
/// </summary>
/// <param name="query"> 查询对象 </param>
/// <returns> 数据表 </returns>
DataTable QueryDataTable(SelectStatement query);
此代理的目的是为了提供一种优化途径,便于开发者最大程度地提升IDBSession构造实体对象的速度。事件包含两个参数:
1、DBColumns columns:从数据库里读取到的列的信息;
2、object[] values:从数据库里读取到的数据行信息;
此代理的目的与ObjectConstructionEventHandler相似,后者仅用于返回单行数据的查询,而BatchObjectConstructionEventHandler主要用于返回多行数据的查询,便于开发者最大程度地提升在一个查询构造多个实体对象的速度。
事件参数BatchObjectConstructionEventArgs包含如下信息:
1、DBColumns columns:从数据库里读取到的列的信息;
2、object[] values:从数据库里读取到的数据行信息;
3、object Context:供事件处理器存放上下文信息,这一信息会被保留下来,在下一次调用时传给事件处理器。开发者可以充分利用Context属性,保存一些可以多次利用的信息,减少重复计算进而提高执行速度。
 
大部分IDBSession的查询方法都支持分页查询。分页查询有几个要点,第一、设置是否统计查询结果记录总数;第二、设置查询返回记录开始索引;第三、设置查询返回记录数。由于统计查询结果记录总数非常耗时,应该只在查询时才统计,翻页时不应统计。推荐的代码模板如下:
bool query =false;
private void btnQuery_Click(object sender, EventArgs e)
{
    query = true;// 只有点击“查询”按钮时才统计记录数
dataGrid.CurrentPageIndex = 0;
Query();
}
 
private void dataGrid_PageIndexChanged(object sender, DataGridPageChangedEventArgs e)
{
query = false;
    dataGrid.CurrentPageIndex = e.NewPageIndex;
Query();
}

private void Query()
{
using (IDBSession session = DBSessionManager.Default.GetSession())
{
    session.ComputeRecordCount = query; // 控制只在第一次查询或刷新时才统计记录数
    session.ReadStartIndex = dataGrid.CurrentPageIndex *pageSize; // 从当前页第一条记录读起
    session.ReadMaxCount = pageSize;// 只读取一页数据
    DataTable dt = session.QueryDataTable(“select * from BAS_USER”);
    dataGrid.DataSource = dt;
    dataGrid.DataBind();
 
    if (query) // 如果统计了记录总数,则显示记录总数
    {
        t xtRecordCount.Text = session.RecordCount;
    }
    }
}
有一种更加优化的分页策略是“分块查询”,例如每页20条,每10页为1块,一次性读取1块记录(合200条)记录存到内存中,在翻页时检查页码是否在块内,如果在块内则直接从内存中取出数据绑定到DataGrid;如果不在块内,则从数据库里读取下一块数据并显示指定的页码。
AppFramework.UI.WebDataGrid的组件提供了非常方便的分块查询翻页功能,欢迎了解使用。
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程通过实际项目融入常用开发技术架构,讲授风格独特,提供详细上课日志及答疑,赠送配套的项目架构源码注释详细清晰且表达通俗,均能直接在实际项目中应用,正真的物超所值,价格实惠任务作业:综合运用《C#/.Net企业级系统架构设计实战精讲教程》课程所学知识技能设计一个学生成绩管理系统的架构。要求:1.系统基于MVC的三层架构,各层单独建不同的解决方案文件夹。2.采用Model First开发方式,设计架构时只需要设计学生表(TbStudent)和课程表(TbCourse)。学生表必须有的字段是ID、stuName、age;课程表必须有的字段是ID、courseName、content。3.数据访问层采用Entity Framework或NHibernate来实现,必须封装对上述表的增删改查方法。4.必须依赖接口编程,也就是必须要有数据访问层的接口层、业务逻辑层的接口层等接口层。层层之间必须减少依赖,可以通过简单工厂或抽象工厂。5.至少采用简单工厂、抽象工厂、Spring.Net等技术中的2种来减少层与层之间的依赖等。6.封装出DbSession类,让它拥有所有Dal层实例和SaveChanges方法。7.设计出数据访问层及业务逻辑层主要类的T4模板,以便实体增加时自动生成相应的类。8.表现层要设计相关的控制器和视图来验证设计的系统架构代码的正确性,必须含有验证增删改查的方法。9.开发平台一定要是Visual Studio平台,采用C#开发语言,数据库为SQL Server。10.提交整个系统架构的源文件及生成的数据库文件。(注意: 作业需写在CSDN博客中,请把作业链接贴在评论区,老师会定期逐个批改~~)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值