顯示具有 LINQ 標籤的文章。 顯示所有文章
顯示具有 LINQ 標籤的文章。 顯示所有文章

Left Join in LINQ

在SQL使用Join可大致分為Inner Join、Outer Join,其中Outer包含Left、Right、Full有的沒的。
今天記錄一下在LINQ(搭配C#)中如何做到Left Join的效果~

假設有2個table"Customer"&"Product"分別記錄顧客與產品資訊,假設這2個table可透過Name、Address欄位串接,最常用的Inner Join寫法如下:
//JOIN 1(Inner):如果customer沒有joinproduct就不保留
var result = customer.Join(product, c => new { c.Name, c.Address }, p => new { p.Name, p.Address }, (c, p) => new { c, p }).ToList();
產出的結果是擁有Product的Customer才會被保留,比如說王小明留下了客戶資料卻沒有訂購任何產品,那麼Join出來的new table是不會有王小明的資訊。

如果要以Customer為基準,無論有無訂購產品皆保留顧客資訊,那麼就要以Customer為Left Table作Left Join,寫法如下:
//JOIN 2(Outer-Left Join):即使customer沒有對應的product,也保留
var result = (from c in customer
join p in product
on new { c.Name, c.Address } equals new { p.Name, p.Address } into newProduct
from newP in newProduct.DefaultIfEmpty()
select new { c, newP }).Distinct();

如何在ADO.NET Entity Data Model建立後加入新mapping

最近在撰寫Web Service,其中單純運算處理之WebMethod不多,主要是連接後端DB將資料透過Web Service回傳,因此需要使用O/R Mapping技術將後端資料預處理,方可為後續Web Service採用。

以VS為開發工具而論,有兩種mapping方式—LINQ to SQL Classes以及ADO .NET Entity Data Model ,前者透過拖曳方式將SQL Server table置放於*.dbml設計介面,後者則以VS提供之精靈設定,使用上極為方便~皆為所視即所得(WYSIWYG)!
但開發階段存在許多不確定因素,今日需要對5個table操作,明日可能因客戶需求變更為7個table,此時便需更新mapping方可進一步使用新增的2個table。LINQ to SQL Classes更新方式一如其建立方式,直接從Server Explorer拖曳想新增的SQL Server table即可,但ADO .NET Entity Data Model 不提供拖曳的方式,必須想辦法將精靈叫出方可更新table。
請注意mouse圖案!LINQ to SQL Classes讓您存檔後,
依舊可從Server Explorer拖曳其他table更新mapping 

 請注意mouse圖案!經精靈設定完成的ADO .NET Entity Data Model,
無法由Server Explorer拖曳其他table更新mapping

 
瞭解上述情境後,以下說明使用ADO .NET Entity Data Model更新mapping時的小技巧。
SETP 1:於*.edmx空白處按右鍵,並選擇「Update Model from Database...」


SETP 2:透過Update Wizard完成table mapping的更新(以新增table  mapping為例)
Update Wizard初始畫面

選取要新增(Add)mapping的表格並按下Finish 

 更新成功!現在有2個table的mapping...

本文主要是提供ADO.NET Entity Data Model使用者一點小撇步,piggy開發時也是苦於mapping更新花了點時間研究,希望這個tip能幫到其他也在學習中的朋友。最後附上開發環境資訊。

[環境說明]
開發工具:VS2010
資料庫:SQL Server Express 2005
.NET Framework版本:4.0

在Silverlight中透過WCF&LINQ使用SQL

針對Silverlight開發者常遇到binding SQL應用,提出循序漸進的範例,其中包含WCF與LING這兩種技巧,原文請參考Displaying SQL Database Data in a DataGrid using LINQ and WCF,本文步驟title依照原文,除了不同處會額外說明,步驟內容只提供操作方式的中文,需瞭解更詳細說明與操作意義者請參考原出處。
  1. Getting Started
    新增一Silverlight專案,命名為SqlData,為了後續使用WCF,我們需要Silverlight Project和Server Project,專案類型請選ASP.NET Web應用程式專案(ASP.NET Web Application Project)



  2. Examining the Two Projects
    VS2008會在名為SqlData的方案下為您新增2個project


    您的SQLDataTestPage.aspx將會自動以ScriptManager裝載未來的xaml以進行測試,如下圖。如果像piggy一樣已安裝Silverlight 3 Tool for VS2008的朋友,你的*.aspx會長的和*.html一樣,這邊不用擔心~只是描述的方式不同罷了,您還是可以改成以前Silverlight 2預設的裝載模式(使用ScriptManager)。可參考本狀況的詳細描述


  3. Linq To Sql
    對Server Project(SqlData.Web)按右鍵加入新項目,選擇「LINQ to SQL類別」


  4. 打開伺服器總管(Server Explorer)找到資料庫AdventureWorks    

    將Customers資料表直接拖曳到DataClasses1.dbml頁面




  5. Make the resulting LINQ class Serializable
    滑鼠左鍵在DataClasses1.dbml空白處按一下,接著至右側屬性視窗更改序列化模式(Serialization Mode),將無(None)改為單向(Unidirectional)


  6. Create the Web Service
    對SqlData.Web按右鍵加入新項目,選擇「有Silverlight功能的WCF服務」,此時專案終獲多2個新檔案Service1.svc以及Service1.svc.vb


    下預設的DoWork方法改成我們設計的新方法,新方法將利用TerritoryID取回該客戶的所有資料,新方法的完整代碼如下
        Function GetCustomersByTerritoryID(ByVal territoryId As Integer) As List(Of Customer)
            Dim db As New DataClasses1DataContext
            Dim matchingCustomers = From cust In db.Customer _
                                    Where cust.TerritoryID.Equals(territoryId) _
                                    Select cust
            Return matchingCustomers.ToList()
        End Function

  7. LINQ Syntax
    不瞭解何謂LINQ者請參照原文p11或其他更深入的書籍

  8. Watch Out for the Binding!(超重要)
    WCF在web.config預設binding是使用wsHttpBinding
    < services >
    < service behaviorConfiguration="SqlData.Web.Service1Behavior"
                    name="SqlData.Web.Service1" >
          < endpoint address="" binding="customBinding" bindingConfiguration="customBinding0" contract="SqlData.Web.Service1" />
          < endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    < /service >
    < /services >

    但是Silverlight只支援basic binding (例如SOAP 1.1),,需要手動更改binging!
    < services >
    < service behaviorConfiguration="SqlData.Web.Service1Behavior"
                    name="SqlData.Web.Service1">
          < endpoint address="" binding="basicHttpBinding" contract="SqlData.Web.Service1" />
          < endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    < /service >
    < /services >

    OK!我們的服務已經架設好勒!

  9. Creating the Silverlight Application
    對Silverlight Application(SqlData)的參考按右鍵,選擇「加入服務參考」


    加入服務參考視窗出現後,按下搜尋(Discover)並選擇「方案中的服務」,我們新建的服務將會被找到,服務中的GetCustomersByTerritoryID也可以一併察看。


    選擇Service1按下確定,之後就可以透過這個參考去存取服務。


  10. Creating the XAML
    接下來設計一個簡單的UI,包含2個row,第1個用來放使用者輸入的TerritoryID,第2個放查詢結果。首先配置容器Grid的layout,xaml碼如下

        < Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
            < Grid.RowDefinitions>
                < RowDefinition Height="10" />
                < RowDefinition Height="50" />
                < RowDefinition Height="*" />
                < RowDefinition Height="10" />
            < /Grid.RowDefinitions>
            < Grid.ColumnDefinitions>
                < ColumnDefinition Width="10" />
                < ColumnDefinition Width="*" />
                < ColumnDefinition Width="10" />
            < /Grid.ColumnDefinitions>
        < /Grid>

    使用Expression Blend 3開啟xaml將會看到下圖成果,總共有3個row、2個column,邊邊都是為了版面故意規劃的row&column,主要是下圖2個大塊的row,如果用VS2008設計檢視看不到或看到的layout很怪的話,請用Blend 3來make sure



  11. Placing controls in the top row
    在第1個row準備放入3個控制項—Textblock、TextBox、Button,為了快速配置3個控制項於row1,我們採用stack panel,然後用border來框住這個範圍

    < Border BorderBrush="Black" BorderThickness="2" Grid.Row="1" Grid.Column="1"/>
    < StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
    < TextBlock Text="Last name to search for: " VerticalAlignment="Bottom" FontSize="18" Margin="15,0,0,0" />
        < TextBox x:Name="LastName" Width="250" Height="30" Margin="2,0,0,4" VerticalAlignment="Bottom"/>
        < Button x:Name="Search" Width="75" Height="30" Margin="20,0,0,4" Content="Search" VerticalAlignment="Bottom" Background="Blue" FontWeight="Bold" FontSize="14" />
    < /StackPanel>


    在第2個大塊的row放一個DataGrid

    < data:DataGrid x:Name="theDataGrid_" Margin="40,15" Grid.Column="1" Grid.Row="2" Width="700" Height="500" d:LayoutOverrides="GridBox"/>

    介面設計完成!

  12. Write the Event Handler for the Search Button
    我們希望UI中的Button被按下去之後會執行查詢的動作(搜尋和Text Box具有相同TerritoryID的顧客),所以要開始在*.xaml.vb撰寫程式碼

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
            AddHandler Search.Click, AddressOf Search_Click
    End Sub

    'Write the Event Handler for the Search Button
    Private Sub Search_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    Dim webService As ServiceReference1.Service1Client = New ServiceReference1.Service1Client()
       AddHandler webService.GetCustomersByTerritoryIDCompleted, AddressOf webService_GetCustomersByTerritoryIDCompleted
       '注意:從Silverlight呼叫服務只能用非同步(Asynchronously)的方式
        webService.GetCustomersByTerritoryIDAsync(TerritoryID.Text)
    End Sub

    Private Sub webService_GetCustomersByTerritoryIDCompleted(ByVal sender As Object, ByVal e As SqlData.ServiceReference1.GetCustomersByTerritoryIDCompletedEventArgs)
    theDataGrid.ItemsSource = e.Result
    End Sub

    當然是件處理常式撰寫完畢後,要記得指派給Button,所以請在其屬性加上Click="Search_Click"

  13. 測試
    build成功後,輸入3搜尋(TerritoryID是Integer型別),可即刻取得ID為3的顧客資料。


    ★參考網址
    原出處
    下載AdventureWork資料庫
    本文使用的AdventureWork資料庫(搭配SQL Server Express 2005)

LINQ無法辨認WKT

LINQ第1步驟通常是從伺服器總管拖曳資料表,沒想到今天光是拖曳資料表就發生dbml無法辨認資料格式的問題,後來測試其他資料表,發現是SDE中以Geometry型別存在的資料表作怪,如果要用LINQ可能要暫時避開這種特殊型別!

無法檢視DBML

昨天想說試試LINQ,想當然就是開個網站再加入新項目「LINQ to SQL 類別」,可是光是新增此類別就有error,造成dbml無法以檢視模式觀看,當然我們也不可能硬來...直接編輯XML,後來Google了一下找到解決的方法,參考網址如下
http://social.msdn.microsoft.com/Forums/en-US/linqprojectgeneral/thread/af45e2b7-98c5-4e12-9bc9-890ae4d03542

在這邊註明一下我的錯誤訊息,因為piggy在尋求解答時發現用英文比較好找=..=,可能使用中文版的朋友們比較少在用LINQ吧~撲
中文版錯誤訊息:自訂工具 'MSLinqToSQLGenerator' 失敗。無法擷取目前的專案
英文版錯誤訊息:The custom tool 'MSLinqToSQLGenerator' failed. Could not retrieve the current project.

以下簡單說明一下solution
1.使用Visual Studio Tools裡面的「Visual Studio 2008 Itanium Cross Tools 命令提示字元」
2.輸入devenv /ResetSkipPkgs後按下enter
3.收工

此時VSTS已經被修復並且會重新開啟,這時候再去新增一次LINQ類別就會是下面漂亮的畫面勒