65.9K
CodeProject 正在变化。 阅读更多。
Home

PLINQO - 超强的 LINQ to SQL

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2009 年 7 月 2 日

CPOL

12分钟阅读

viewsIcon

48669

自从 LINQ to SQL 可用以来,我们一直在探索使其变得更好的方法。我们将所有这些酷炫的技巧和窍门,包括新功能,打包成一套 CodeSmith 模板。PLINQO 打开了 LINQ TO SQL 的黑匣子,使您能够控制您的源代码

plinqo-speed-simluator.jpg

自从 LINQ to SQL 可用以来,我们一直在探索使其变得更好的方法。我们将所有这些酷炫的技巧和窍门,包括新功能,打包成一套 CodeSmith 模板。PLINQO 打开了 LINQ TO SQL 的黑匣子,使您能够控制您的源代码,同时增加了许多新功能和增强功能。它仍然是 LINQ to SQL,但更好了!

有什么新内容

改进之处


PLINQO 生成的输出是高质量、易于维护的代码,它为任何项目奠定了坚实的基础,并助其走向成功。PLINQO 利用了许多 CodeSmith 的功能,例如合并策略、CodeSmith 项目和 Visual Studio 集成。

通过 下载最新版本的 CodeSmith,您就可以在 C# 和 VB 中使用 PLINQO。此外,PLINQO 也在不断发展,不断推出新功能和错误修复。要随时了解 PLINQO 的最新动态,请查看下载区域

快速入门

秒速完成一个可用的项目!想想通常启动一个项目需要多长时间(创建解决方案、添加项目、组织代码等)。PLINQO 使这个过程变得和选择数据库一样简单。下面是 CodeSmith 快速启动属性的截图。和往常一样,您拥有完全的控制权,可以更改任何快速启动属性来生成您想要的解决方案。点击生成后,您可以通过玩转动态数据界面、创建测试或完成项目来体验 PLINQO 的所有功能。

只需要 SourceDatabase 属性。

Image

点击生成即可生成下面的解决方案。PLINQO 甚至会自动为您打开它!

Image

可用的解决方案包括一个完全配置的 CodeSmith 项目 (.csp),这使得重新生成过程非常简单。

点击生成即可生成下面的解决方案。PLINQO 甚至会自动为您打开它!

轻松同步数据库更改

更改是任何项目不可避免的一部分。Visual Studio 中的 LINQ to SQL 设计器在操作实体方面提供了很多支持,但当需要重构时,它并不能让事情变得容易。LINQ to SQL 设计器需要删除并重新创建实体才能生成必要的更新。当实体被删除时,该实体所做的任何更新也会丢失,现在必须重新创建。这既耗时又繁琐,还会导致重复劳动。有了 PLINQO,只需进行更改、右键单击、生成,即可完成!PLINQO 使这一切变得如此简单。PLINQO 支持将数据库与 dbml 同步,同时保留任何手动 dbml 更新。

管理器和查询扩展类

PLINQO 为每个实体提供生成管理器或查询扩展类的选项,该类封装了对实体进行的所有操作。已知常见操作,如按主键、索引和外键检索实体,都会被生成。任何自定义操作都可以添加,并在重新生成时得到保留。虽然 LINQ 使在整个应用程序中轻松地散布您的数据访问逻辑,但我们仍然认为这样做设计不佳,因此我们提供了创建管理器类或查询扩展类的选项。

管理器

管理器类用于封装业务逻辑,并设计为包含整个查询,因此在传递参数时,可以立即返回结果。

 
        Task task = context.Manager.Task.GetByKey(1);
        IQueryable<Task> tasks = context.Manager.Task.GetByAssignedId(1);

查询扩展

生成的每个查询扩展方法都是可组合的,这意味着您可以将方法链接在一起,通过较小的部分构建所需的函数,并充分利用重用。

 
        task = context.Task.GetByKey(1);
        tasks = context.Task.GetByAssignedId(1).GetByStatusId(1);
        List<Task> taskList = tasks.ToList();

组织良好、结构化的代码

LINQ to SQL 在数据库更改或自定义的用戶體驗方面並沒有深入考慮。您需要創建自己的類來處理變更。PLINQO 足夠智能,能夠識別生成的代碼並非整個解決方案,而是堅實的基礎。在項目結構和文件組織方面付出了巨大的努力。項目越大,這一點就越重要。PLINQO 會創建部分類別,每個實體、管理器和查詢擴展都對應兩個文件。一個文件是主動生成的,另一個專門用於自定義和擴展 PLINQO 架構。

查询结果缓存

任何框架的關鍵方面都包括緩存數據的選項。每當重複檢索相同數據時,都會浪費寶貴的時間和 CPU 週期。PLINQO 旨在通過提供緩存任何 LINQ to SQL 查詢結果的選項來節省寶貴的時間和 CPU。PLINQO 利用 `System.Web.Caching.Cache` 類來存儲 LINQ to SQL 查詢的結果,並提供使用滑動或絕對過期選項以及設置緩存項優先級的功能。

要在 PLINQO 中緩存查詢結果,請使用位於 `CodeSmith.Data.Linq` 命名空間中的 `FromCache` 擴展方法。以下是使用 PLINQO 提供的所有不同選項緩存查詢結果的示例。只需像平常一樣執行 LINQ to SQL 查詢,然後附加 `FromCache` 擴展,並告訴 PLINQO 如何緩存結果。

    //By default, the cached results use a one minute sliding expiration with
    //no absolute expiration.
    var tasks = context.Task.ByAssignedId(UserId).FromCache();
    
    //query result is now cached 300 seconds
    var approvedUsers = context.User.ByIsApproved(true).FromCache(300);
    
    //A sliding expiration is used. Each time this line is executed, the time in
    //cache is reset to 5 minutes from the time of the call.
    var createdTasks = context.Task.ByCreatedId(UserId).FromCache(TimeSpan.FromMinutes(5));
    
    //adding a priority to the cached item
    var roles = context.Role.FromCache(TimeSpan.FromMinutes(5), CacheItemPriority.High);
    
    //Uses an absolute expiration.  The results of this query will not stay in cache
    //longer than 15 minutes
    var statuses = context.Status.FromCache(DateTime.UtcNow.AddMinutes(15));
    
    //The results of this query are cached with high priority and will not stay in
    //cache longer than 15 minutes
    var tasksDueToday = context.Task.ByDueDate(DateTime.Now.Date).FromCache(
        DateTime.UtcNow.AddMinutes(15), CacheItemPriority.High);

立即開始節省時間和金錢,通過利用 PLINQO 的查詢結果緩存來讓數據庫得到休息。

实体分离

無法分離是開發人員在處理 LINQ to SQL 時抱怨最多的問題。好了,抱怨將結束。PLINQO 讓在不接觸數據上下文的情況下輕鬆處理實體,並在準備保存更改時將其附加到另一個上下文。由於 PLINQO,以下代碼現在成為可能。

 
        Task task = null;
        using (var context = new TrackerDataContext())
        {
            task = context.Task.FirstOrDefault(t => t.Id == 1);
            task.Detach();
        }
        
        task.StatusId = 1;
        
        using (var context2 = new TrackerDataContext())
        {
            context2.Task.Attach(task, true);
            context2.SubmitChanges();
        }

如果您的數據庫支持行版本控制,則此處顯示的代碼無需更改即可工作。如果您的數據庫不支持行版本控制,則必須將 dbml 中每個屬性的 `Update Check` 策略設置為 `Never` 才能使分離正常工作。

实体克隆

PLINQO 利用 WCF 中的 `DataContractSerializer` 為所有實體對象提供高質量的克隆解決方案。只需調用 PLINQO 生成的任何實體上的 `Clone` 方法,您就會得到一個複製到其自身內存位置的對象。以下是克隆方法實際應用的快速示例。從數據庫檢索用戶對象,克隆它,更改一個屬性,然後將新用戶保存到數據庫。

 
        using (var context = new TrackerDataContext())
        {
            var u = context.Manager.User.GetByKey(1);
            User clonedUser = u.Clone();
            clonedUser.Id = 0;
            context.User.InsertOnSubmit(clonedUser);
            context.SubmitChanges();
        }

枚举生成

PLINQO 的枚舉生成可以輕鬆地將一個包含數據的表轉換為一個枚舉。許多時候,枚舉值存儲在數據庫和代碼中,導致在需要更改時必須更新兩個位置。重複進行相同的更改以保持同步絕對是一個令人沮喪的過程。PLINQO 讓您可以輕鬆定義要生成的枚舉表列表,以及哪些字段包含枚舉常量文本和描述。結果是枚舉僅需維護一個位置,一切都變得輕鬆。

PLINQO 枚舉生成輕鬆地將優先級表轉換為枚舉。

Image
 
                        [DataContract]
                        public enum Priority : int
                        {
                            [EnumMember]
                            High = 1,
                            [EnumMember]
                            Normal = 2,
                            [EnumMember]
                            Low = 3,
                        }

元數據自定義/同步

.NET 3.5 SP1 中引入的 `System.ComponentModel.DataAnnotations` 程序集為 PLINQO 提供了另一個讓生活更輕鬆的機會。PLINQO 在每個實體內生成並維護一個元數據類。這個元數據類允許您輕鬆地為您的域對象及其屬性添加額外的知識。每次 PLINQO 重新生成時,DBML 和數據庫的更改都會被同步,同時保留使用 CodeSmith 的一項新功能(插入類合併策略)的任何自定義更改。維護系統中每個實體的元數據的過程現在可以像重新生成元數據類一樣簡單。

這是顯示坐在 User 類內部的一個 MetaData 類的圖片。

 
        [CodeSmith.Data.Audit.Audit]
        private class Metadata
        {
            // Only Attributes in the class will be preserved.

            public int Id { get; set; }

            [Required]
            public string UserName { get; set; }
            
            [Required]
            [DataType(System.ComponentModel.DataAnnotations.DataType.Password)]
            public string Password { get; set; }

            [DataType(System.ComponentModel.DataAnnotations.DataType.EmailAddress)]
            public string EmailAddress { get; set; }

            public string FirstName { get; set; }

            public string LastName { get; set; }

            public System.Data.Linq.Binary Avatar { get; set; }

            [Now(EntityState.New)]
            [CodeSmith.Data.Audit.NotAudited]
            public System.DateTime CreatedDate { get; set; }

            [Now(EntityState.Dirty)]
            [CodeSmith.Data.Audit.NotAudited]
            public System.DateTime ModifiedDate { get; set; }

            public System.Data.Linq.Binary RowVersion { get; set; }

            public EntitySet<Task> AssignedTaskList { get; set; }

            public EntitySet<Task> CreatedTaskList { get; set; }

            public EntitySet<UserRole> UserRoleList { get; set; }

        }

預先配置好這些,可以清楚地知道在需要模型額外知識時應該去哪裡。ASP.NET 動態數據屬性,例如顯示數據的控件、數據類型、如何驗證字段以及對屬性執行的操作,只是元數據類中可用屬性中的一小部分。

规则

PLINQO 規則!是的,PLINQO 提供了幾種不同的方式來制定規則。規則可以通過屬性以編程方式或聲明方式添加。可以強制執行屬性長度、必需字段等約束。使用 PLINQO 可以實現正則表達式數據驗證以及幾種內置規則,包括授權規則。在保存任何數據之前,規則會自動對更改集中的任何實體進行執行。如果任何規則被違反,將拋出 `BrokenRulesException`,其中包含被違反規則的列表,並且實體不會被更新。

PLINQO 規則管理器基於架構生成規則,並且可以添加自定義規則。規則在嘗試保存更改時強制執行。添加自定義規則非常簡單,每個實體上的 `AddSharedRules` 部分方法是添加它們的地方。只需幾行代碼即可添加自定義規則。這裡有一個例子。

為 `UserName` 的最小長度添加了一個規則。

 
        static partial void AddSharedRules()
        {
            RuleManager.AddShared<User>(new CustomRule<string>("UserName",
                "UserName must be 5 characters.", MinLengthUserName));
        }

        private static bool MinLengthUserName(string username)
        {
            if (String.IsNullOrEmpty(username) || username.Length < 5)
                return false;
            else
                return true;
        }

當任何規則被違反時,不會更新任何數據,並會返回一個包含被違反規則的列表。

 
        using (var context = new TrackerDataContext())
        {
            User user = new User();
            context.User.InsertOnSubmit(user);
            context.SubmitChanges();
        }

可以通過利用前面提到的元數據類以聲明方式添加規則。PLINQO 支持 `System.ComponentModel.DataAnnotations` 程序集中的標準規則以及 PLINQO 定義的規則。

如您所見,有許多方法可以確保保存的數據符合規則。

多對多關係

幾乎所有項目都需要使用多對多關係,而 LINQ to SQL 並不支持。您可能已經猜到了,PLINQO 支持!讓我們通過一個 PLINQO 中的多對多場景的快速示例。下面是 User 和 Role 實體之間的多對多關係圖。

Image

在執行任何多對多代碼之前的 UserRole 表。

Image

此代碼將用戶添加到角色中。

 
        using (var context = new TrackerDataContext())
        {
            User u = context.User.GetByKey(1);
            Role r = context.Role.GetByKey(1);
            u.RoleList.Add(r);
            context.SubmitChanges();
        }

代碼執行後數據庫中的結果。

Image

审计

什麼數據發生了變化,是什麼,現在是什麼!這些是經常被問到的問題。當這些問題被問到時,PLINQO 已準備好提供答案。當數據上下文中的 `AuditingEnabled` 設置為 `true` 時,PLINQO 將捕獲任何提交到數據庫的更改。PLINQO 只捕獲已更改的對象,並且每次提交到數據庫的更改中只捕獲這些對象中的已更改屬性。前後值都會被記錄。`Context.LastAudit` 是存儲此信息的地方,並且有一個 `ToXml()` 方法,可以輕鬆地將 AuditLog 轉換為 XML 以便於存儲。在此,我們更改 User 和 Task 對象,提交更改,然後顯示審核的 XML。PLINQO 審核將記錄插入、刪除和更新,並消除了在決定需要對數據更改進行審核時通常所需的工作。

 
        using (var context = new TrackerDataContext())
        {
            Priority p = new Priority();
            p.Name = "High!";
            context.Priority.InsertOnSubmit(p);

            Task t = context.Task.GetByKey(1);
            t.Details = "Startup Counterstrike.  Used PLINQO.  Project is done";

            context.SubmitChanges();
            AuditLog audit = context.LastAudit;
        }
 
        <audit xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance 
           xmlns:xsd=http://www.w3.org/2001/XMLSchema 
           xmlns="http://schemas.codesmithtools.com/datacontext/audit/1.0">
          <entity action="Insert" type="Tracker.Data.Priority">
            <key name="Id" type="System.Int32">
              <value xsi:type="xsd:int">0</value>
            </key>
            <property name="Id" type="System.Int32">
              <current xsi:type="xsd:int">0</current>
            </property>
            <property name="Name" type="System.String">
              <current xsi:type="xsd:string">High!</current>
            </property>
            <property name="Order" type="System.Int32">
              <current xsi:type="xsd:int">0</current>
            </property>
          </entity>
          <entity action="Update" type="Tracker.Data.Task">
            <key name="Id" type="System.Int32">
              <value xsi:type="xsd:int">1</value>
            </key>
            <property name="Details" type="System.String">
              <current xsi:type="xsd:string">
                  Startup CounterStrike.  Used PLINQO.  Project is done</current>
              <original xsi:type="xsd:string">
                  Work overtime to get project started</original>
            </property>
          </entity>
        </audit>

数据服务和 WCF

数据服务

LINQ to SQL 默認不支持數據服務。但是,使用 PLINQO 的數據服務所需做的就是將 Entities 模板上的 `IncludeDataServices` 屬性設置為 `true`,讓 PLINQO 負責設置您的項目以支持數據服務。

WCF

PLINQO 負責設置 Windows Communication Foundation (WCF) 的 `DataContract` 和 `DataMember` 屬性的所有繁瑣工作。Entities 模板上的 `IncludeDataContract` 選項告訴 PLINQO 生成 `Data Contract` 和 `Data Member` 屬性,通過處理所有繁重的工作,使將 Windows Communication Foundation (WCF) 與 PLINQO 的使用變得輕鬆無憂。

性能改进

使用 PLINQO,將大大減少對數據庫的調用。以下是幾種方法

批量更新和刪除

刪除和更新是任何應用程序的重要組成部分。PLINQO 現在提供了一種最佳解決方案,無論是處理單個實體(LINQ to SQL 需要大量工作來刪除或更新實體)還是同時刪除或更新多個實體(沒有支持)。對於單個刪除,必須檢索並填充對象才能刪除或更新。在您已經擁有所需信息的情況下,刪除或更新實體需要兩次數據庫調用!PLINQO 通過直接發送刪除和更新來消除第一次調用,從而無需進行額外工作。因此,性能得以輕鬆提高,並且由於代碼行數減少,還可以節省時間。

多個實體的更新和刪除也是大多數 ORM 的一個缺點,LINQ to SQL 也不例外。在沒有 PLINQO 的情況下刪除或更新多個實體時,會發出多個語句,而單個 SQL 語句可以更高效地完成工作。PLINQO 能夠基於過濾器創建多個更新和刪除。以下是可用於刪除和更新的不同功能的概覽。

删除

 
        //Manager classes delete method
        context.Manager.User.Delete(1);
        //Query extension delete method
        context.User.Delete(1);

        //works for managers and queries
        context.User.Delete(u => u.FirstName == "firstname");

        IQueryable<Task> tasks = context.Task.Where(t => t.StatusId == 2);
        context.Task.Delete<Task>(tasks);

更新

 
        context.Task.Update(t => t.StatusId == 1, t2 => new Task {StatusId = 2});

        IQueryable<User> users = context.User.Where(u => u.FirstName == "firstname");
        context.User.Update(users, u => new User {FirstName = "newfirstname"});

正如您所見,無需 `SubmitChanges()`。操作會立即執行,並且由於 PLINQO 的批量刪除和更新功能,性能將會大大提高。

具有多個結果集的存儲過程

有時,將查詢批處理到一個存儲過程中以優化與數據庫的往返次數會更有效。在生成過程中,PLINQO 識別所有返回多個結果的存儲過程,並提供一種不錯的方法來處理結果。

以下是實現這一目標的方法。創建以下存儲過程。

 
        Create Procedure [dbo].[ReturnMultiplResultSets]
        As
        Select * From [User]
        Select * From [Task]

現在我們有一個返回多個結果集的存儲過程,以及 PLINQO 如何處理它的方法。

 
        IMultipleResults results = context.ReturnMultiplResultSets();
        List<User> users = results.GetResult<User>().ToList();
        List<Task> tasks = results.GetResult<Task>().ToList();

沒有比這更簡單的了。

批處理查詢

當您帶著錢去電子遊戲商店,準備購買《使命召喚》、《瘋狂橄欖球 09》和《老虎伍茲 09》時,我相信您不會去三次商店買遊戲,而是會一次性完成。進行三次旅行效率極低。那麼,為什麼 LINQ to SQL 在從數據庫檢索數據時可以接受這種做法呢?PLINQO 認為這是不可接受的!PLINQO 支持批處理查詢,從而可以大大優化完成操作所需的時間。數據上下文上的 `ExecuteQuery` 使之成為可能。這是一個將 `Select * From User` 和 `Select * From Task` 批處理到一次數據庫行程的示例。

 
        var q1 = from u in context.User select u;
        var q2 = from t in context.Task select t;
        IMultipleResults results = context.ExecuteQuery(q1, q2);
        List<User> users = results.GetResult<User>().ToList();
        List<Task> tasks = results.GetResult<Task>().ToList();

更輕鬆的序列化

從 LINQ to SQL 早期到現在,實體的序列化讓開發人員們團團轉。PLINQO 通過消除循環引用的可能性並利用 WCF 數據合同序列化消除了這種挫敗感。這是一個使用 PLINQO 序列化對象的示例。

 
        Task task = context.Task.GetByKey(1);
        string xml = task.ToXml();

结论

PLINQO 就是 LINQ to SQL,只是更好!立即查看 PLINQO,讓我們知道您的想法。

© . All rights reserved.