饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 90 页

作者:Nick Randolph/等 当前章节:15375 字 更新时间:2026-6-18 14:51

that is generated by LINQ to SQL for your LINQ statement. Figure 28-21 illustrates the default

data tip for the same LINQ to SQL statement in C# (VB is the same, except you don’t see the

generated SQL in the first line of the data tip).

fiGure 28-21

After adding the visualizer you will see the magnifying glass icon in the first line of the data tip.

Clicking this opens up the LINQ to SQL Debug Visualizer so that you can see the way your LINQ

to SQL statement is translated to SQL. Figure 28-22 illustrates this visualizer showing the way

that the query is parsed by the compiler in the top half of the screen, and the SQL statement that

is generated in the lower half of the screen. Clicking the Execute button displays the QueryResult

window (inset into Figure 28-22) with the output of the SQL statement. Note that you can modify

the SQL statement, allowing you to tweak it until you get the correct results set. This can quickly

help you correct any errors in your LINQ statement.

610 .

chaPter 28 lAnguAge inTegrATed QuerieS (linQ)

fiGure 28-22

inserts, Updates, and Deletes

You can see from the earlier code snippet that the DataContext acts as the conduit through which

LINQ to SQL queries are processed. To get a better appreciation of what the DataContext does

behind the scenes, let’s look at inserting a new product category into the AdventureWorksLT

database. Before you can do this you will need to add the ProductCategory table to your LINQ to

SQL design surface. In this case you don’t need to modify any of the properties, so just drag the

ProductCategory table onto the design surface. Then to add a new category to your database, all

you need is the following code:

c#

using(var aw = new AdventureLiteDataContext()){

var cat = new ProductCategory();

cat.Name = "Extreme Bike";

aw.ProductCategories.InsertOnSubmit(cat);

aw.SubmitChanges();

}

Code snippet MainForm.cs

Vb

Using aw As New AdventureLiteDataContext

Dim cat As New ProductCategory

cat.Name = "Extreme Bike"

aw.ProductCategories.InsertOnSubmit(cat)

aw.SubmitChanges()

End Using

Code snippet MainForm.vb

linQ to sQl .

611

This code inserts the new category into the collection of product categories held in memory by

the DataContext. When you then call SubmitChanges on the DataContext it is aware that you

have added a new product category so it will insert the appropriate records. A similar process is

used when making changes to existing items. In the following example you retrieve the product

category you just inserted using the Contains syntax. Because there is likely to be only one

match, you can use the FirstOrDefault extension method to give you just a single product

category to work with:

c#

using (var aw = new AdventureLiteDataContext()){

var cat = (from pc in aw.ProductCategories

where pc.Name.Contains("Extreme")

select pc).FirstOrDefault();

cat.Name = "Extreme Offroad Bike";

aw.SubmitChanges();

}

Code snippet MainForm.cs

Vb

Using aw As New AdventureLiteDataContext

Dim cat = (From pc In aw.ProductCategories

Where pc.Name.Contains("Extreme")).FirstOrDefault

cat.Name = "Extreme Offroad Bike"

aw.SubmitChanges()

End Using

Code snippet MainForm.cs

Once the change to the category name has been made, you just need to call SubmitChanges on the

DataContext in order for it to issue the update on the database. Without going into too much detail

the DataContext essentially tracks changes to each property on a LINQ to SQL object so that it

knows which objects need updating when SubmitChanges is called. If you want to delete an object,

you simply need to obtain an instance of the LINQ to SQL object, in the same way as for doing

an update, and then call DeleteOnSubmit on the appropriate collection. For example, to delete a

product category you would call aw.ProductCategories.DeleteOnSubmit(categoryToDelete),

followed by aw.SubmitChanges.

stored Procedures

One of the questions frequently asked about LINQ to SQL is whether you can use your own stored

procedures in place of the run time-generated SQL. The good news is that for inserts, updates,

and deletes you can easily specify the stored procedure that should be used. You can also use

existing stored procedures for creating instances of LINQ to SQL objects. Let’s start by adding

a simple stored procedure to the AdventureWorksLT database. To do this, right-click the Stored

Procedures node under the database connection in the Server Explorer tool window and select Add

612 .

chaPter 28 lAnguAge inTegrATed QuerieS (linQ)

New Stored Procedure. This opens a code window with a new stored procedure template. In the

following code you have selected to return the five fields that are relevant to your Customer object:

CREATE PROCEDURE dbo.GetCustomers

AS

BEGIN

SET NOCOUNT ON

SELECT c.CustomerID, c.FirstName, c.LastName, c.EmailAddress, c.Phone

FROM SalesLT.Customer AS c

END;

Once you have saved this stored procedure it will appear under the Stored Procedures node. If you

now open up the AdventureLite LINQ to SQL designer, you can drag this stored procedure across

into the right-hand pane of the design surface. In Figure 28-23 you can see that the return type of

the GetCustomers method is set to Auto-generated Type. This means that you will only be able

to query information in the returned object. Ideally, you would want to be able to make changes to

these objects and be able to use the DataContext to persist those changes back to the database.

fiGure 28-23

The second method, GetTypedCustomers, actually has the Return Type set as the Customer class.

To create this method you can either drag the GetCustomers stored procedure to the right pane,

and then set the Return Type to Customer, or you can drag the stored procedure onto the Customer

class in the left pane of the design surface. The latter will still create the method in the right pane,

but it will automatically specify the return type as the Customer type.

Note that you don’t need to align properties with the stored procedure columns,

because this mapping is automatically handled by the DataContext. This is a

double-edged sword: clearly it works when the column names map to the source

columns of the LINQ to SQL class but it may cause a run time exception if

there are missing columns or columns that don’t match.

Once you have defined these stored procedures as methods on the design surface, calling them is as

easy as calling the appropriate method on the DataContext:

linQ to sQl .

613

c#

using (var aw = new AdventureLiteDataContext()){

var customers = aw.GetCustomers();

foreach (var c in customers){

MessageBox.Show(c.FirstName);

}

}

Code snippet MainForm.cs

Vb

Using aw As New AdventureLiteDataContext

Dim customers = aw.GetCustomers

For Each c In customers

MsgBox(c.FirstName)

Next

End Using

Code snippet MainForm.vb

Here you have seen how you can use a stored procedure to create instances of the LINQ to SQL

classes. If you instead want to update, insert, or delete objects using stored procedures, you follow

a similar process except you need to define the appropriate behavior on the LINQ to SQL class. To

begin with, create an insert stored procedure for a new product category:

CREATE PROCEDURE dbo.InsertProductCategory

(

@categoryName nvarchar(50),

@categoryId int OUTPUT

)

AS

BEGIN

INSERT INTO SalesLT.ProductCategory (Name) VALUES (@categoryName)

SELECT @categoryId=@@identity

END;

Following the same process as before, you

need to drag this newly created stored

procedure from the Server Explorer across

into the right pane of the LINQ to SQL

design surface. Then in the Properties tool

window for the ProductCategory class,

modify the Insert property. This will open

the dialog shown in Figure 28-24. Here you

can select whether you want to use the

run time-generated code or customize

the method that is used. In Figure 28-24 the

InsertProductCategory method has been

fiGure 28-24

614 .

chaPter 28 lAnguAge inTegrATed QuerieS (linQ)

selected. Initially, the Class Properties will be unspecified, because Visual Studio 2010 wasn’t able

to guess at which properties mapped to the method arguments. It’s easy enough to align these to

the id and name properties. Now when the DataContext goes to insert a ProductCategory it will

use the stored procedure instead of the run time-generated SQL statement.

binding linq to sql objects

The important thing to remember when using DataBinding with LINQ to SQL objects is that they

are in fact normal .NET objects. This means that you can create a new object data source via the

Data Sources tool window. In the case of the examples you have seen so far, you would go through

the Add New Data Source Wizard, selecting just the Customer object. Because the Order and

OrderItem objects are accessible via the navigation properties Orders and then OrderItems, you

don’t need to explicitly add them to the Data Source window.

Once you have created the object data source (see the left side of Figure 28-25), you can then

proceed to drag the nodes onto your form to create the appropriate data components. Starting with

the Customer node, use the drop-down to specify that you want a DataGridView, then drag it onto

your form. Next, you need to specify that you want the Orders (a child node under Customer) to

appear as details and then drag this to the form as well. You will notice that you don’t get a binding

navigator for this binding source, so from the Toolbox add a BindingNavigator to your form and

set its BindingSource property to be the OrdersBindingSource that was created when you dragged

over the Orders node. Lastly, you want to display all the OrderItems in a DataGridView, so use the

drop-down to set this and then drag the node onto the form. After doing all this you should end up

with something similar to Figure 28-25. Note that we have also included a button that you will use

to load the data and we have laid the Order information out in a panel to improve the layout.

fiGure 28-25

linQ to sQl .

615

One of the things you will have noticed is that the columns on your OrderItems data grid don’t

match those in Figure 28-25. By default, you will get Quantity, Order, and Product columns. Clearly,

the last two columns are not going to display anything of interest, but you don’t really have an

easy way to display the Name of the product in the order with the current LINQ to SQL objects.

Luckily, there is an easy way to effectively hide the navigation from OrderItem to Product so that

the name of the product will appear as a property of OrderItem.

You do this by adding your own property to the OrderItem class. Each LINQ to SQL class is

generated as a partial class, which means that extending the class is as easy as right-clicking the

class in the LINQ to SQL designer and selecting View Code. This generates a custom code file,

in this case AdventureLite.vb (or AdventureLite.cs), and includes the partial class definition.

You can then proceed to add your own code. In the following snippet we have added the Product

property that will simplify access to the name of the product being ordered:

c#

partial class OrderItem{

public string ProductName{

get{

return this.Product.Name;

}

}

}

Code snippet AdventureLite.cs

Vb

Partial Class OrderItem

Public ReadOnly Property ProductName() As String

Get

Return Me.Product.Name

End Get

End Property

End Class

Code snippet AdventureLite.vb

For some reason this property, perhaps because it is added to a second code file, will not be detected

by the Data Sources tool window. However, you can still bind the Product column to this property

by manually setting the DataPropertyName field in the Edit Columns dialog for the data grid.

The last thing to do is to actually load the data when the user clicks the button. To do this you can

use the following code:

c#

private void btnLoadData_Click(object sender, EventArgs e){

using (var aw = new AdventureLiteDataContext()){

616 .

chaPter 28 lAnguAge inTegrATed QuerieS (linQ)

var cust = aw.Customers;

this.customerBindingSource.DataSource = cust;

}

}

Vb

Private Sub btnLoad_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles btnLoad.Click

Using aw As New AdventureLiteDataContext

Dim custs = From c In aw.Customers

Me.CustomerBindingSource.DataSource = custs

End Using

End Sub

You will notice that your application will now run, and when the user clicks the button the customer

information will be populated in the top data grid. However, no matter which customer you select,

no information will appear in the Order information area. The reason for this is that LINQ to

SQL uses lazy loading to retrieve information as it is required. Using the data visualizer you were

introduced to earlier, if you inspect the query in this code you will see that it contains only the

customer information:

SELECT [t0].[CustomerID], [t0].[FirstName], [t0].[LastName], [t0].[EmailAddress],

[t0].[Phone]

FROM [SalesLT].[Customer] AS [t0]

You have two ways to resolve this issue. The first is to force LINQ to SQL to bring back all the

Order, OrderItem, and Product data as part of the initial query. To do this, modify the button click

code to the following:

c#

private void btnLoadData_Click(object sender, EventArgs e){

using (var aw = new AdventureLiteDataContext()){

var loadOptions =new System.Data.Linq.DataLoadOptions();

loadOptions.LoadWith<Customer>(c=>c.Orders);

loadOptions.LoadWith<Order>(o=>o.OrderItems);

loadOptions.LoadWith<OrderItem>(o=>o.Product);

aw.LoadOptions = loadOptions;

var cust = aw.Customers;

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页