EntityFramework與Ado.net的對比——EF優勢何在?


更准確的說法是EF對比SqlHelper ado.net

public class SqlHelper
    {
        public static readonly string connstr =
            "Server=.;Database=PhoneBook;Uid=sa;Pwd=********;";
        //params 長度可變的參數.
        public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters)
        {
            //a寫法
            using (SqlConnection conn = new SqlConnection(connstr))
            {
                conn.Open();
                using (SqlCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = sql;
                    cmd.Parameters.AddRange(parameters);
                    return cmd.ExecuteNonQuery();
                }
            }

            //b寫法
            //SqlConnection conn = new SqlConnection(connstr);
            //conn.Open();
            //SqlCommand cmd = conn.CreateCommand();

            //cmd.CommandText = sql;
            //cmd.Parameters.AddRange(parameters);
            //return cmd.ExecuteNonQuery();

        }

        public static object ExecuteScalar(string sql, params SqlParameter[] parameters)
        {
            using (SqlConnection conn = new SqlConnection(connstr))
            {
                conn.Open();
                using (SqlCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = sql;
                    cmd.Parameters.AddRange(parameters);
                    return cmd.ExecuteScalar();
                }
            }
        }

        public static DataTable ExecuteDataTable(string sql, params SqlParameter[] parameters)
        {
            using (SqlConnection conn = new SqlConnection(connstr))
            {
                conn.Open();
                using (SqlCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = sql;
                    cmd.Parameters.AddRange(parameters);

                    DataSet dataset = new DataSet();
                    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                    adapter.Fill(dataset);
                    return dataset.Tables[0];
                }
            }
        }

        //可空數據的輸入:
        //SqlParameter中,如果是"",則數據庫中的數據為""或者0.
        //如何SqlParameter是Null,程序運行報錯"沒有提供參數."
        //如何表示數據庫中的Null?SqlParameter用DBNull.Value.

        //如果數據庫中的值是Null,AOD.net讀取為DBNull.Value.而該DBNull.Value不能轉換為string.
        //可空類型,int?   bool?
        public static object FromDBValue(object value)
        {
            if (value == DBNull.Value)
            {
                return null;
            }
            else
            {
                return value;
            }
        }

        public static object ToDBValue(object value)
        {
            if (value == null)
            {
                return DBNull.Value;
            }
            else
            {
                return value;
            }
        }
    }
SqlHelper

1. 新增操作.

使用EF:

 var db = new PhoneBookEntities();
 db.Database.Log = Console.Write;//打印sql語句
 List<GroupInfo> list = new List<GroupInfo>();
 list.Add(new GroupInfo() { GroupName = "li" });
 list.Add(new GroupInfo() { GroupName = "ge" });
 list.Add(new GroupInfo() { GroupName = "xiao" });
 db.GroupInfo.AddRange(list);
 db.SaveChanges();

使用sql server profiler的監控結果:

 

使用SqlHelper

 public class GroupInfoDAL
    {

        public GroupInfo ToGroupInfo(DataRow row)
        {
            GroupInfo model = new GroupInfo();
            model.GroupId = (System.Int32)row["GroupId"];
            model.GroupName = (System.String)row["GroupName"];
            return model;
        }
        public GroupInfo GetById(int id)
        {
            DataTable table = SqlHelper.ExecuteDataTable("select * from GroupInfo where GroupId=@GroupId", new SqlParameter("@GroupId", id));
            if (table.Rows.Count <= 0)
            {
                return null;
            }
            else if (table.Rows.Count > 1)
            {
                throw new Exception("Id 重復,屬於嚴重錯誤");
            }
            else
            {
                DataRow row = table.Rows[0];
                return ToGroupInfo(row);
            }
        }
        public void DeleteById(int id)
        {
            SqlHelper.ExecuteNonQuery("delete from GroupInfo where GroupId=@GroupId", new SqlParameter("@GroupId", id));
        }
        public GroupInfo[] GetAll()
        {
            DataTable dt = SqlHelper.ExecuteDataTable("select * from GroupInfo");
            GroupInfo[] models = new GroupInfo[dt.Rows.Count];
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                models[i] = ToGroupInfo(dt.Rows[i]);
            }
            return models;
        }
        public void Update(GroupInfo model)
        {
            SqlHelper.ExecuteNonQuery("update GroupInfo set GroupName=@GroupName where GroupId=@GroupId", new SqlParameter("@GroupId", model.GroupId),
        new SqlParameter("@GroupName", model.GroupName));
        }
        public void Insert(GroupInfo model)
        {
            SqlHelper.ExecuteNonQuery("insert into GroupInfo(GroupName) values(@GroupName)", new SqlParameter("@GroupName", model.GroupName));
        }
    }
GroupInfoDal
        static void InsertTest()
        {
            var giDal = new GroupInfoDAL();

            List<GroupInfo> list=new List<GroupInfo>();
            list.Add(new GroupInfo(){GroupName = "li"});
            list.Add(new GroupInfo(){GroupName = "ge"});
            list.Add(new GroupInfo(){GroupName = "xiao"});

            foreach (var item in list)
            {
                giDal.Insert(item);
            }
        }
InsertTest

使用sql server profiler的監控結果:

測試結果:

EF:一次連接,執行3條sql.

SqlHelper里使用a寫法用using,會造成多次連接重置;
b寫法不用using,連接又無法釋放.

同樣,更新和刪除多條數據,也是一個道理.

甚至查詢上,也可以使用EntityFramework.Extended中Future,把多次查詢放到一個連接里.見 EntityFramework和EntityFramework.Extended使用說明——性能,語法和產生的sql

2. update

EF自動優化,只update set 有變化的字段.

EF也可以很方便地只更新實體的指定屬性,產生的sql語句里的set后的字段會更少.

 public void Edit(TEntity model, string[] propertyNames)
        {
            //檢查model的合法性
            if (model == null)
            {
                throw new Exception("model實體不能為Null");
            }
            //屬性propertyNames至少有一個
            if (propertyNames == null || propertyNames.Any() == false)
            {
                throw new Exception("propertyNames數組至少要有一個值");
            }
            var entry = db.Entry(model);
            entry.State = EntityState.Unchanged;
            foreach (var item in propertyNames)
            {
                entry.Property(item).IsModified = true;
            }
            db.Configuration.ValidateOnSaveEnabled = false;
        }
Update指定屬性

3. 只查詢表的指定字段

SqlHelper把查到的數據表的每一行轉換為一個對象.那么sql語句:select * from ... 而這種sql寫法是不推薦的.
要解決這個問題,有點麻煩吧?(有好方法的可以留言.希望回答時考慮到DTO,domain model,復雜的業務肯定會用到.)
而使用EF里的select投影方法輕松搞定,只在sql語句里'select'需要的字段.

4.用linq, lamda表達式 有智能提示,寫錯了編譯不過.

寫sql語句字符串,調sqlhelper,sql語句寫錯一樣編譯通過.

5.安全上,省去了防止sql注入的麻煩.

6.使用EF,數據庫變更切換較方便

雖然使用的數據庫在項目開始就會確定,誰又能保證沒有奇葩的數據庫變更的需求呢?
如果你使用的是EF,你就呵呵一笑,這事兒小菜一碟.

7.開發效率上.使用EF要比使用Ado.net開發效率高.

目前我用的Database First,會直接產生實體類(代碼生成功能);
如果是Code First,也會創建對應的數據庫.還是很方便的.這只是一個小方面.
更主要的是使用EF會更方便地操作數據庫.

8.代碼的可讀性.

使用EF,代碼可讀性更高。

...

如果有錯誤,請大家指出。如果有遺漏,請幫助完善。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM