LLBL Gen + Entity Framework 程序設計入門


Entity Framework推出有好幾年,除了微軟的Visual Studio可以做實體框架開發外,第三方的開發工具如LLBL Gen,

Devart Entity Developer也可以用來做設計開發。

設計數據庫表Configuration,它的SQL定義如下

IF OBJECT_ID ('dbo.Configuration') IS NOT NULL
    DROP TABLE dbo.Configuration
GO

CREATE TABLE dbo.Configuration
    (
    Recnum      INT IDENTITY NOT NULL,
    MasterKey   NVARCHAR (50) NOT NULL,
    Description TEXT NULL,
    Remark      NVARCHAR (400) NULL,
    CONSTRAINT PK_X_Config PRIMARY KEY (MasterKey)
    )
GO

打開LLBL Gen,創建一個新項目,選擇Entity Framework v1

image

這里還有其它版本的Entity Framework。對應關系如下

Entity Framework v1 =>  Entity Framework 3.5 SP1

Entity Framework v4 => Entity Framework 4/4.5

再到Category Explorer窗口中,選擇添加數據庫映射,選擇數據庫類型,設置連接參數

image

生成實體模型,繼續在Category Explorer窗口中,把表添加到當前項目的實體中,如下圖所示

image

驗證實體類型,准備生成代碼,但是出現以下幾個錯誤:

The Entity "FileType" contains field "FileType" which has the same name as its containing element,something which isn't supported by the Entity Framework

映射的實體名字段中,不能包含與實體名稱一樣的字段。比如,我有一個FileType的表,映射到FileType實體,它包含一個FileType的主鍵字段,自動生成映射時,這是不允許的。

清除這個錯誤之后,按F7生成代碼,用Visual Studio 2012打開項目,如下圖所示

image

LLBL Gen代碼生成器幫忙我們生成Entity Framework所需要的edmx文件,類型定義和DataContext類型。

來看一下生成的類型定義代碼,Configuration表映射的實體類型Configuration實體,它的代碼如下

/// <summary>Class which represents the entity 'Configuration'.</summary>
    [Serializable]
    [DataContract(IsReference=true)]
    [EdmEntityType(NamespaceName="Entity35Model", Name="Configuration")]
    public partial class Configuration : CommonEntityBase
    {
        #region Class Member Declarations
        private System.String _description;
        private System.String _masterKey;
        private System.Int32 _recnum;
        private System.String _remark;
        #endregion
        
        #region Extensibility Method Definitions
        partial void OnDescriptionChanging(System.String value);
        partial void OnDescriptionChanged();
        partial void OnMasterKeyChanging(System.String value);
        partial void OnMasterKeyChanged();
        partial void OnRecnumChanging(System.Int32 value);
        partial void OnRecnumChanged();
        partial void OnRemarkChanging(System.String value);
        partial void OnRemarkChanged();
        #endregion
                
        /// <summary>Initializes a new instance of the <see cref="Configuration"/> class.</summary>
        public Configuration() : base()
        {
        }

        /// <summary>Factory method to create a new instance of the entity type 'Configuration'</summary>
        /// <param name="masterKeyValue">The initial value for the field 'MasterKey'</param>    
        /// <param name="recnumValue">The initial value for the field 'Recnum'</param>    
        public static Configuration CreateConfiguration(System.String masterKeyValue, System.Int32 recnumValue)
        {
            var toReturn = new Configuration();
            toReturn.MasterKey = masterKeyValue;
            toReturn.Recnum = recnumValue;
            return toReturn;
        }

        #region Class Property Declarations
        /// <summary>Gets or sets the Description field. </summary>
        [DataMember]
        [EdmScalarProperty()]
        public System.String Description
        {
            get    { return _description; }
            set
            {
                OnDescriptionChanging(value);
                this.ReportPropertyChanging("Description");
                _description = SetValidValue(value, true);
                this.ReportPropertyChanged("Description");
                OnDescriptionChanged();
            }
        }
        
        /// <summary>Gets or sets the MasterKey field. </summary>
        [DataMember]
        [EdmScalarProperty(EntityKeyProperty=true, IsNullable=false)]
        public System.String MasterKey
        {
            get    { return _masterKey; }
            set
            {
                if(_masterKey==value)
                {
                    return;
                }
                OnMasterKeyChanging(value);
                this.ReportPropertyChanging("MasterKey");
                _masterKey = SetValidValue(value, false);
                this.ReportPropertyChanged("MasterKey");
                OnMasterKeyChanged();
            }
        }
        
        /// <summary>Gets or sets the Recnum field. </summary>
        [DataMember]
        [EdmScalarProperty(IsNullable=false)]
        public System.Int32 Recnum
        {
            get    { return _recnum; }
            private set
            {
                OnRecnumChanging(value);
                this.ReportPropertyChanging("Recnum");
                _recnum = SetValidValue(value);
                this.ReportPropertyChanged("Recnum");
                OnRecnumChanged();
            }
        }
        
        /// <summary>Gets or sets the Remark field. </summary>
        [DataMember]
        [EdmScalarProperty()]
        public System.String Remark
        {
            get    { return _remark; }
            set
            {
                OnRemarkChanging(value);
                this.ReportPropertyChanging("Remark");
                _remark = SetValidValue(value, true);
                this.ReportPropertyChanged("Remark");
                OnRemarkChanged();
            }
        }
        
        #endregion
    }

LLBL Gen讓生成的實體類型派生於CommonEntityBase,這個類型派生於EntityObject,定義如下

/// <summary>Class which is the common base class for all generated entity classes.</summary>
/// <remarks>As all non-subtype entity classes derive from this class, use a partial class of this class to implement code which is shared among all generated entity classes</remarks>
    [DataContract(IsReference = true)]
    [Serializable]
    public abstract partial class CommonEntityBase : EntityObject
    {
        #region Class Extensibility Methods
        /// <summary>Method called from the constructor</summary>
        partial void OnCreated();
        #endregion
        
        /// <summary>Initializes a new instance of the <see cref="CommonEntityBase"/> class.</summary>
        protected CommonEntityBase() : base()
        {
            OnCreated();
        }

    }

可以在這個類型中,創建一些公共的方法以方便在生成的實體類型中使用。

LLBL Gen為實體框架的實體的每個屬性添加了二個跟蹤機制方法:Changing和Changed方法。這里可以寫我們實體的業務邏輯。比如在采購單中,用戶改變單價時,自動重新計算金額(金額=數量*單價)。

以備注屬性為例子,請看下面的代碼

/// <summary>Gets or sets the Remark field. </summary>
[DataMember]
[EdmScalarProperty()]
public System.String Remark
{
            get    { return _remark; }
            set
            {
                OnRemarkChanging(value);
                this.ReportPropertyChanging("Remark");
                _remark = SetValidValue(value, true);
                this.ReportPropertyChanged("Remark");
                OnRemarkChanged();
            }
}
partial void OnRemarkChanging(System.String value);
partial void OnRemarkChanged();
 

這二個方法都是partial方法,如果我們沒有定義方法體,則編譯時,它會被忽略。partial方法是C# 3.0才引入的特性,為方便代碼生成器與開發人員之間的合作更緊密。試想一下,怎么在不修改代碼生成器生成的方法的情況下,添加自定義的業務代碼到類型的方法,屬性中去呢?答案是partial方法。

同時,因為生成的實體類型已經加了partial關鍵字,所以我們可以再加入一個同名的實體類型,用來寫業務邏輯,而不更改代碼生成器自動生成的代碼。

最后,寫一個測試方法,讓它讀取系統的配置表Configuration中的數據:

public static void Main(string[] args)
 {
            Entity35DataContext entity35DataContext = new Entity35DataContext();
            var configurations = from item in entity35DataContext.Configurations
                           select item;

            foreach (var dbDataRecord in configurations)
            {
                string companyCode = dbDataRecord.MasterKey;

            }
}
 

一行代碼即可完成數據庫的讀取,而且讀取的數據是強類型,非常方便。

一般在入門例子中,容易出錯的地方是配置文件的內容,來看一下App.config文件的內容:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
        <!-- please adjust the connection string embedded in the element below to target the proper catalog / server using the proper user / password combination -->
        <add name="ConnectionString.SQL Server (SqlClient)" connectionString="metadata=res://*/Entity35.csdl|res://*/Entity35.ssdl|res://*/Entity35.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\sqlexpress;initial catalog=Framework;integrated security=SSPI;persist security info=False;packet size=4096&quot;" providerName="System.Data.EntityClient" />
    </connectionStrings>
</configuration> 

這里是設置連接字符串的地方,從生成的ObjectContext類型中,可以看到不帶參數的構造方法為從這里讀取連接字符串,它的其它的幾個方法,如下代碼所示

/// <summary>Initializes a new instance of the <see cref="Entity35DataContext"/> class using the connection string found in the 'Entity35' section of the application configuration file.</summary>
public Entity35DataContext() : base("name=ConnectionString.SQL Server (SqlClient)", "Entity35Entities")
{
            Initialize();
}
        
/// <summary>Initializes a new instance of the <see cref="Entity35DataContext"/> class</summary>
public Entity35DataContext(string connectionString) : base(connectionString, "Entity35Entities")
{
            Initialize();
}
        
/// <summary>Initializes a new instance of the <see cref="Entity35DataContext"/> class</summary>
/// <param name="connection">Ready to use EntityConnection object to be used with this context</param>
public Entity35DataContext(System.Data.EntityClient.EntityConnection connection) : base(connection, "Entity35Entities")
{
            Initialize();
}
 
 

Entity Framework的連接字符串與經常寫的SQL Server的SqlConnection的字符串有所區別,要指定依據edmx生成的三個文件的位置,因為edmx文件的Build Action為EntityDeploy,所以它會被嵌入到生成的程序集中。

image

用.NET Reflector載入生成的實體程序集,查看它的資源文件,如上圖所示,三個資源文件被嵌入在程序集中。

 


免責聲明!

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



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