entity framework扩展实战,小项目重构,不折腾

一个控制台程序,MSSQL 2008 数据库,其中一个大表数据超过6000千万,开发时间有限不可能花很多时间设计、架构。使用控制台一是为了实现高效运行,二是程序是在服务器上定时运行无人干预。要保证程序可维护性和快速开发和程序高效运行,没时间去分层开发,直接使用了entity framework并结合ado.net对EF进行了扩展。不折腾是因为怕EF有性能问题使用了sqlbuckcopy进行批量插入数据,使用DB FIRST。重构是因为原来是oracle数据库,数据库已经改为MSSQL 2008。

1、解决方案、架构

解决方案:

 

2、业务说明

程序主要业务是读取指定目录下面的XML文件,将里面的文件里的记录整理拼凑为数据库里对应表的datatable,然后使用SqlBulkCopy批量插入数据库。文件是远程计算机通过FTP上传的。XML里面的记录和需要存储的数据库里对应表的表结构不一致,需要转换和补全。程序是定时运行,使用操作系统的计划任务进行调度。日志组件使用了log4net,来实现控制台显示和数据库记录日志。

3、关键代码和编码思路

1、业务逻辑实现

2、EF扩展类

using System.Data;
using System.Data.EntityClient;
using System;
using System.Data.SqlClient;
using System.Configuration;
 
namespace XXX_App
{
    public partial class XXX_DBEntities : global::System.Data.Objects.ObjectContext
    {
        Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
        /// <summary>
        /// 使用ado.net执行sqlbulkcopy
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="efConnectStr">webconfig里的数据库连接字符串</param>
        /// <returns></returns>
        public bool ExecuteSqlBulkCopy(DataTable dt)
        {
            string dbConnStr = this.GetEF_ConnectStr2Ado_ConnectStr();
            bool result = false;
            #region ado.net execute sqlbulkcopy
            using (SqlConnection dbConn = new SqlConnection(dbConnStr))
            {
                try
                {
                    #region 执行sqlbulkcopy
                    dbConn.Open();
                    SqlCommand cmd = dbConn.CreateCommand();
                    cmd.CommandText = "delete sc_productsource_temp";                   
                    cmd.ExecuteNonQuery();
                    new SqlBulkCopy(dbConn)
                    {
                        DestinationTableName = "sc_productsource_temp",
                        BatchSize = dt.Rows.Count,
                        BulkCopyTimeout = 1800
                    }.WriteToServer(dt);
                    #endregion
                    result = true;
                }
                catch (Exception ex)
                {
                    result = false;
                    throw new Exception(ex.Message);
                }
                finally
                {
                    if (result)
                    {
                        #region 临时表流量明细记录转正式 SC_PRODUCTSOURCE
                        SqlCommand cmd = dbConn.CreateCommand();
                        cmd.CommandText = " INSERT INTO  SC_PRODUCTSOURCE (PRODUCTSOURCEID,FACTORYID,PRDLINEID "+
                                          " ,MACRANDOMCODE    ,PRODUCTBATCHIDX ,LASERDNA_CODE ,PRODUCTNO ,PRODUCTNAME,PRODUCTTYPENAME"+
                                          " ,PRODUCTDATE ,PRINTCODEDT ,FACTORYSHIFTNO ,OUTBOX_DNACODE ,VIRTUALBALECODE" +
                                          " ,SENDTONDC_DT,FAC_NO,PRODUCTVERSION) " +
                                          " SELECT  NEWID() PRODUCTSOURCEID,FACTORYID,PRDLINEID,MACRANDOMCODE,PRODUCTBATCHIDX " +
                                          "      ,LASERDNA_CODE,PRODUCTNO,PRODUCTNAME,PRODUCTTYPENAME,PRODUCTDATE,PRINTCODEDT " +
                                          "      ,FACTORYSHIFTNO,OUTBOX_DNACODE,VIRTUALBALECODE,SENDTONDC_DT,FAC_NO,PRODUCTVERSION " +
                                          " FROM sc_productsource_temp";        
                        cmd.ExecuteNonQuery();
                        #endregion                       
                    }
                    dbConn.Close();
                }
            }
            #endregion
            return result;
        }
 
        /// <summary>
        /// 准备临时表
        /// </summary>
        /// <param name="efConnectStr"></param>
        /// <returns></returns>
        public DataTable GetTmpNewDataTable()
        {
            return this.GetDbHelperSQL_Instance().Query("select * from sc_productsource_temp where 1=2").Tables[0];           
        }
 
        /// <summary>
        /// 将EF的连接字符串转为Ado.net的连接字符串
        /// </summary>
        /// <param name="efConnectStr"></param>
        /// <returns></returns>
        private string GetEF_ConnectStr2Ado_ConnectStr()
        {
            string[] tmpStr = config.ConnectionStrings.ConnectionStrings["XXX_DBEntities"].ConnectionString.Split(";".ToCharArray());
            string dbConnStr = string.Empty;
            if (tmpStr.Length == 8)
            {
                //拼接出新的可用的ado.net连接字符串
                dbConnStr = string.Join(";", new string[] { "Data Source =" + base.Connection.DataSource, tmpStr[3], tmpStr[4], tmpStr[5], tmpStr[6].TrimEnd(new char[] { '"' }) });
                return dbConnStr;
            }
            else
            {
                return string.Empty;
                throw new Exception("请配置数据库连接方式为:sql认证方式;不支持WinNT集成安全方式。");
            }
        }
 
        /// <summary>
        /// 获取第一行第一列数据
        /// </summary>
        /// <param name="efConnectStr"></param>
        /// <param name="sqlTxt"></param>
        /// <returns></returns>
        public string AdoExecuteScalar(string sqlTxt)
        {
            string dbConnStr = this.GetEF_ConnectStr2Ado_ConnectStr();
            using (DbHelperSQL db = new DbHelperSQL(dbConnStr))
            {
                return db.GetSingle(sqlTxt).ToString();
            }
        }
        
        public DbHelperSQL GetDbHelperSQL_Instance()
        {
            string dbConnStr = this.GetEF_ConnectStr2Ado_ConnectStr();
            return new DbHelperSQL(dbConnStr);
        }
    }
}

 3、修改过的动软DbHelper,Ado.net存储类

 4、EF的使用和扩展类的使用

4、程序运行效果及截图

1、日志

2、截图

暂无,因为程序效率太高,一时没有文件需要解析了。呵呵

结束语:做项目不需要定势的思维,比如一定要分层架构,一定要什么牛X的技术,一定要高可扩展性、高可重用性。小项目,快速、稳定、高效和可维护性才是需要考量的要点。天下武功,唯快不破。呵呵...

PS:CSS样式是扒园友的,原来不是在博客设置里写样式,是在页面的HTML模式下加入自定义样式。
posted @   数据酷软件  阅读(2926)  评论(10编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示