實體類的枚舉屬性--原來支持枚舉類型這么簡單,沒有EF5.0也可以


    通常,我們都是在業務層和界面層使用枚舉類型,這能夠為我們編程帶來便利,但在數據訪問層,不使用枚舉類型,因為很多數據庫都不支持,比如我們現在用的SqlServer2008就不支持枚舉類型的列,用的時候也是將枚舉類型轉換成int 類型,數據庫存儲的是int 類型的數據,在訪問數據的時候進行枚舉類型和int類型的轉換,例如下面的例子:

    public enum RoleNames
    { 
        User,
        Manager,
        Admin
    }

假設有一個實體類Users,如果實體類不支持枚舉類型,得這樣使用(下面的示例都以PDF.NET的ORM框架使用來說明):

//獲取一個實體類:
Users user=new Users();
user.ID=1;

if(EntityQuery<Users>.Fill(user))
{
 RoleNames rn=(RoleNames)user.RoleID;
 Console.Write("Role Name:"+rn);
}


//更新實體類:
Users user=new Users();
user.ID=1;
user.RoleID=(int)RoleNames.Admin;
EntityQuery<Users>.Instance.Update(user);

    查詢和更新操作都得對枚舉類型進行轉換,不方便,雖然如此,我們大部分情況下還是將就了,在訪問數據庫的時候這么轉換下。這種情況下EF 5.0 之前也不例外,都是社區用戶的強烈要求,在EF5.0版本之后才加入支持實體類枚舉屬性的。

    既然使用枚舉還要將實體類的屬性轉換下,為何不直接將實體類的屬性定義成枚舉類型?
    修改下Users類型的定義:

public partial class Users : EntityBase
{
        //其它部分定義略

        public RoleNames RoleID
        {
            get { return getProperty<RoleNames>("RoleID"); }
            set { setProperty("RoleID", value); }
        }

}

直接使用這個修改過的實體類來插入、修改數據,是沒有問題的:

//更新實體類:
Users user=new Users();
user.ID=1;
user.RoleID=RoleNames.Admin;
EntityQuery<Users>.Instance.Update(user);

但是查詢實體類的時候會有點小問題,雖然能夠正確的從數據庫查詢,但查看枚舉屬性的時候會報類型轉換錯誤:

//獲取一個實體類:
Users user=new Users();
user.ID=1;

if(EntityQuery<Users>.Fill(user))
{
 RoleNames rn=user.RoleID;
 Console.Write("Role Name:"+rn);
}

    跟蹤代碼發現,user.RoleID 對應的SqlReader 的結果類型是int ,因為數據庫的RoleID 列沒法定義成枚舉類型,如果要將實體類的屬性定義成枚舉類型,那么在SqlReader讀取的時候,必須進行類型轉換:

user.RoleID=(RoleNames)reader["RoleID"];

    幸好PDF.NET的實體類認為“實體類是數據的容器”,內部采用一個object[] 保存來自數據庫的原始數據,而在使用數據的時候,才來進行類型轉換,因此框架原來查詢數據、插入、更新數據的地方,都不用做任何修改,只需要修改下 getProperty<T>("fieldName") 涉及的部分:

       public static T ChangeType<T>(object Value)
       {
           if (Value is T)
               return (T)Value;
           else if (Value == DBNull.Value || Value == null)
           {
               if (typeof(T) == typeof(DateTime))
               {
                   //如果取日期類型的默認值 0001/01/01 ,在WCF JSON序列化的時候,會失敗。
                   object o = new DateTime(1900, 1, 1);
                   return (T)o;
               }
               else
                   return default(T);
           }
           else
           {
               //edit at 2011.5.16
               //如果 Value為 decimal類型,T 為double 類型, (T)Value 將發生錯誤
               //edit at 2013.8.9 支持枚舉類型
               if (typeof(T).IsEnum)
                   return (T)Value;
               else
                   return (T)Convert.ChangeType(Value, typeof(T));
           }
       }

使用PDF.NET框架的V4.X 版本(包括V4.6之前的版本)用戶,只需要打開 CommonUtil.cs 文件,找到該方法,將

return (T)Convert.ChangeType(Value, typeof(T));

修改為:

 if (typeof(T).IsEnum)
       return (T)Value;
 else
       return (T)Convert.ChangeType(Value, typeof(T));

即可。


    經過測試,通過這樣的修改,框架就可以支持實體類使用枚舉類型了。


    為什么修改如此簡單?前面已經說過,PDF.NET的實體類是數據的容器,也就是說,我們在內存中將某個屬性的值直接設置為枚舉類型的值,也可以將內存中的Int 類型的來自數據庫的值,在運行時轉換成枚舉類型。這樣,使得PDF.NET的實體類的屬性類型可以不必跟數據庫的字段類型嚴格對應,只要類型相容即可。這個特點為系統移植數據庫平台提供了很大的便利,比如Oracle 沒有Decimal類型,沒有real 類型,要使用非整形的數字類型,只有使用Number類型,那么為SqlServer設計使用的實體類,一般情況下也可以直接在Oracle下使用。

    下面的代碼是一個完整的使用實體類的枚舉屬性的例子:

using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using PWMIS.DataMap.Entity;
using PWMIS.Common;

namespace OQLTest
{
    public enum RoleNames
    { 
        User,
        Manager,
        Admin
    }
    public partial class Users : EntityBase
    {
        public Users()
        {
            TableName = "LT_Users";
            EntityMap = EntityMapType.Table;
            //IdentityName = "標識字段名";
            IdentityName = "ID";

            //PrimaryKeys.Add("主鍵字段名");
            PrimaryKeys.Add("ID");


        }


        protected override void SetFieldNames()
        {
            PropertyNames = new string[] { "ID", "UserName", "Password", "NickName", "RoleID", "Authority", "IsEnable", "LastLoginTime", "LastLoginIP", "Remarks", "AddTime" };
        }



        /// <summary>
        /// 
        /// </summary>
        public System.Int32 ID
        {
            get { return getProperty<System.Int32>("ID"); }
            set { setProperty("ID", value); }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.String UserName
        {
            get { return getProperty<System.String>("UserName"); }
            set { setProperty("UserName", value, 50); }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.String Password
        {
            get { return getProperty<System.String>("Password"); }
            set { setProperty("Password", value, 50); }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.String NickName
        {
            get { return getProperty<System.String>("NickName"); }
            set { setProperty("NickName", value, 50); }
        }

        /// <summary>
        /// 
        /// </summary>
        public RoleNames RoleID
        {
            get { return getProperty<RoleNames>("RoleID"); }
            set { setProperty("RoleID", value); }
        }

        //用下面的方式處理實體類的子實體類問題
        UserRoles _roles;
        public UserRoles Roles
        {
            get
            {
                if (_roles == null)
                {
                    _roles = new UserRoles() { ID = this.RoleID };
                    EntityQuery<UserRoles>.Fill(_roles);
                }
                return _roles;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.String Authority
        {
            get { return getProperty<System.String>("Authority"); }
            set { setProperty("Authority", value, 250); }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.Boolean IsEnable
        {
            get { return getProperty<System.Boolean>("IsEnable"); }
            set { setProperty("IsEnable", value); }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.DateTime LastLoginTime
        {
            get { return getProperty<System.DateTime>("LastLoginTime"); }
            set { setProperty("LastLoginTime", value); }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.String LastLoginIP
        {
            get { return getProperty<System.String>("LastLoginIP"); }
            set { setProperty("LastLoginIP", value, 20); }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.String Remarks
        {
            get { return getProperty<System.String>("Remarks"); }
            set { setProperty("Remarks", value, 150); }
        }

        /// <summary>
        /// 
        /// </summary>
        public System.DateTime AddTime
        {
            get { return getProperty<System.DateTime>("AddTime"); }
            set { setProperty("AddTime", value); }
        }

    }

}
用戶實體類定義

    測試程序:

            Users user = new Users() { NickName = "pdf.net", RoleID= RoleNames.Admin };
         
            OQL q0 = OQL.From(user)
               .Select()
               .Where(user.NickName, user.RoleID) 
               .OrderBy(user.ID)
               .END;
            q0.SelectStar = true;
            Console.WriteLine("q0:one table and select all fields \r\n{0}", q0);
            Console.WriteLine(q0.PrintParameterInfo());

            var userList= EntityQuery<Users>.QueryList(q0);
            if (userList.Count > 0)
            {
                Users u = userList[0];
                Console.WriteLine("User Type is:"+u.RoleID.ToString());
                u.RoleID = RoleNames.User;
                EntityQuery<Users>.Instance.Update(u);
            }

    程序輸出:

 

 

    數據庫結果界面:

 

--------------分界線----------------------

PDF.NET 開發框架是國產的開發框架,支持SQL-MAP、ORM和數據控件 三種編程模型,可以一種或者三種混合使用,是開源的開發框架,供廣大.net開發朋友在EF,NH之外,提供第三中選擇。歡迎加入PDF.NET開源技術團隊

相關鏈接:

 

 


免責聲明!

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



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