using …

Pure C#

‘Ado.Net’ Kategorisi için Arşiv

Servers and Services tracks recorded at TechDays 2009 Belgium

Yazan: esersahin 10/08/2009

http://www.microsoft.com/belux/techdays/2009/track.aspx?tid=servers_services&engine=MSDN

In this track you will find sessions on SQL Server 2008, SharePoint Server (MOSS), Windows Workflow Foundation (WF) and Windows Communication Foundation (WCF) in .NET Framework 3.5. Claims and authentication is also addressed as well as the Azure Services Platform.

Building RESTful Applications with Microsoft Tools

Building RESTful Applications with Microsoft Tools Applications today are expected to expose their data and consume data-centric services via REST. In this session we discuss ADO .NET Data Services and see how we can REST enable your application. Then you will learn how to leverage existing skills related to LINQ and data access to customize the behavior, control-flow, security model and experience of your data service. Then switching gears we will focus on consuming of REST services from any platform (including Ruby on Rails) using Visual Studio and LINQ to REST. We will then see how to enable data-binding to traditional ASP.NET controls as well as Silverlight. We will conclude with developing offline applications with the ability to sync back to the online data service.

Session level: 300

Building Workflow Services in .NET Framework 3.5

Building Workflow Services in .NET Framework 3.5 About creating business processes in Workflow Foundation and integration with other applications using WCF. The Workflow first approach vs. the Contract first approach. The use of the wsHttpContextBinding. Big demo of a real life scenario based where a public webapplication start a process, internal applications are communicating with the process and at the end thirdparty services are called.

Session level: 300

Enhancing the SharePoint Developer Experience

Enhancing the SharePoint Developer Experience This session will focus on best practices for SharePoint development based on lessons learnt. You will learn how to approach SharePoint development to build solutions in an effective way. This is not only about knowing the right tools and techniques to speed up the SharePoint development process but also about how to avoid mistake and making the correct design decisions.

Session level: 300

Inside the Architecture of the Podcasting Kit for SharePoint

Inside the Architecture of the Podcasting Kit for SharePoint Join this session to know more about the design of the Podcasting Kit for SharePoint, how SharePoint Server 2007 is used out of the box, and which components have been developed and how: rating, commenting and rating, native Zune support, Silverlight 2.0 for playback and robust upload, streaming, grid view, mobile views etc… Scaling, performance and deployment will also be discussed. We’ll also share lessons learned from the current Academy Mobile implementation within Microsoft.

Session level: 300

Putting authentication in its place: claim-based identity, services and Geneva

Putting  authentication in its place: claim-based identity, services and Geneva The code that takes care of authentication is traditionally one of the nastiest spot of every distributed application. The current situation derives from multiple causes, from tightly coupling with specific technologies to trusting non-experts to write security code. Microsoft has been among the thought leaders who proposed a strategic solution to the problem, the Identity MetaSystem and its claim based identities, achieving vast consensus across the industry. Come to this session to learn how you can finally put that vision in practice thanks to the new “Geneva” products line.

Session level: 300

SQL Server 2008 for Developers

SQL Server 2008 for Developers Lynn’s demo-filled presentation will give .NET developers an overview of the numerous new capabilities in SQL Server 2008: from support for Spatial Data types to a mechanism to store SQL BLOB data using the NTFS file system, and several things in between. There are also improvements in the area of SQL CLR and XML, Reporting Services, etc. This presentation will take a technical dive into the new things you will find in SQL Server 2008. Lynn’s sessions are always highly interactive, educational and a lot of fun.

Session level: 300

WCF Tips & Tricks

WCF Tips & Tricks Applications communicating over the Internet or being provided in the cloud need certain infrastructure functionalities. Authentication, authorization, powerful communication options and support for workflows seem to be a common need. Microsoft’s .NET Services – as part of the overall Azure Services platform – offer exactly all this with their Access Control Service, Service Bus and Workflow Service. In this session Christian Weyer sheds a light on how these services fit into the Azure picture, how they work and fit together in a practical manner, based on first experiences in customer projects.

Session level: 300

Yazı kategorisi: ADO.NET Data Services, ADO.NET Entity Framework, Ado.Net, LinQ, Silverlight, Sql Server, WCF | » yorum bırak;

Managed Data Access Inside SQL Server with ADO.NET and SQLCLR

Yazan: esersahin 24/11/2008

http://msdn.microsoft.com/en-us/library/ms345135.aspx

Pablo Castro
Microsoft Corporation

April 2005

Applies to:
   Microsoft SQL Server 2005
   Microsoft .NET Framework 2.0
   ADO.NET

Summary: Using the new SQLCLR feature, managed code can use ADO.NET when running inside SQL Server 2005. Learn about SQLCLR via basic scenarios of in-process data access, SQLCLR constructs, and their interactions. (26 printed pages)

Contents

Introduction
Part I: The Basics
   Why Do Data Access Inside SQLCLR?
   Getting Started with ADO.NET Inside SQLCLR
   The Context Connection
   Using ADO.NET in Different SQLCLR Objects
   When Not to Use SQLCLR + ADO.NET
Part II: Advanced Topics
   More on Connections
   Transactions
Conclusion
   Acknowledgements

Introduction

This white paper discusses how managed code can use ADO.NET when running inside SQL Server 2005 using the new SQLCLR feature.

In Part I, I describe the basic scenarios in which in-process data access might be required, and the difference between local and remote connections. Most of the different SQLCLR constructs are covered, such as stored procedures and functions, as well as interesting aspects of the interaction between the data access infrastructure and those constructs.

Part II further details in-process connections and restrictions that apply to ADO.NET when running inside SQLCLR. Finally, there is a detailed discussion on the transactions semantics of data access code inside SQLCLR, and how can it interact implicitly and explicitly with the transactions API.

Part I: The Basics

Why Do Data Access Inside SQLCLR?

SQL Server 2005 is highly integrated with the .NET Framework, enabling the creation of stored procedures, functions, user-defined types, and user-defined aggregates using your favorite .NET programming language. All of these constructs can take advantage of large portions of the .NET Framework infrastructure, the base class library, and third-party managed libraries.

In many cases the functionality of these pieces of managed code will be very computation-oriented. Things such as string parsing or scientific math are quite common in the applications that our early adopters are creating using SQLCLR.

However, you can do only so much using only number crunching and string manipulation algorithms in isolation. At some point you’ll have to obtain your input or return results. If that information is relatively small and granular you can use input and output parameters or return values, but if you’re handling a large volume of information, then in-memory structures won’t be an appropriate representation/transfer mechanism; a database might be a better fit in those scenarios. If you choose to store the information in a database, then SQLCLR and a data-access infrastructure are the tools you’ll need.

There are a number of scenarios where you’ll need database access when running inside SQLCLR. One is the scenario I just mentioned, where you have to perform some computation over a potentially large set of data. The other is integration across systems, where you need to talk to different servers to obtain an intermediate answer in order to proceed with a database-related operation.

Note   For an introduction and more details about SQLCLR in general, see Using CLR Integration in SQL Server 2005.

Now, if you’re writing managed code and you want to do data access, what you need is ADO.NET.

Getting Started with ADO.NET Inside SQLCLR

The good news is that ADO.NET “just works” inside SQLCLR, so in order to get started you can leverage all your existing knowledge of ADO.NET.

To illustrate this take a look at the code snippet below. It would work fine in a client-side application, Web application, or a middle-tier component; it turns out that it will also work just fine inside SQLCLR.

C#
// Connection strings shouldn't be hardcoded for production code
using(SqlConnection conn = new SqlConnection(
  "server=MyServer; database=AdventureWorks; user id=MyUser; password=MyPassword")) {
  conn.Open();

  SqlCommand cmd = new SqlCommand(
                     "SELECT Name, GroupName FROM HumanResources.Department", conn);

  SqlDataReader r = cmd.ExecuteReader();
  while(r.Read()) {
    // Consume the data from the reader and perform some computation with it
  }
}

Visual Basic .NET
Dim cmd as SqlCommand
Dim r as SqlDataReader

' Connection strings shouldn't be hardcoded for production code
Using conn As New SqlConnection( _
     "server=MyServer; database=AdventureWorks; user id=MyUser; password=MyPassword")
  conn.Open()

  cmd = New SqlCommand("SELECT Name, GroupName FROM HumanResources.Department", conn)

  r = cmd.ExecuteReader()
  Do While r.Read()
    ' Consume the data from the reader and perform some computation with it
  Loop
End Using

This sample uses the System.Data.SqlClient provider to connect to SQL Server. Note that if this code runs inside SQLCLR, it would be connecting from the SQL Server that hosts it to another SQL Server. You can also connect to different data sources. For example, you can use the System.Data.OracleClient provider to connect to an Oracle server directly from inside SQL Server.

For the most part, there are no major differences using ADO.NET from within SQLCLR. However, there is one scenario that needs a little bit more attention: what if you want to connect to the same server your code is running in to retrieve/alter data? See The Context Connection section to see how ADO.NET addresses that.

Before delving into further detail, I’d like to go through the basic steps to run code inside SQLCLR. If you already have experience creating SQLCLR stored procedures, you’ll probably want to skip this section.

Creating a managed stored procedure that uses ADO.NET from Visual Studio

Visual Studio 2005 includes great integration with SQL Server 2005 and makes it really easy to create and deploy SQLCLR projects. Let’s create a new managed stored procedure that uses ADO.NET using Visual Studio 2005.

  1. Create a SQLCLR project. The starting point for SQLCLR in Visual Studio is a database project. You need to create a new project by selecting the database project category under your favorite language. Next, select the project type called SQL Server Project, give it a name, and let Visual Studio create the project.
  2. Set permissions to EXTERNAL_ACCESS. Go to the properties of the project (right-click on the project node, choose Properties), choose the Database tab, and then from the Permission Level combo-box, choose External.
  3. Add a stored-procedure to the project. Once the project is created you can right-click on the project node and select Add -> New Item. On the pop-up dialog you’ll see all the different SQLCLR objects that you can create. Select Stored Procedure, give it a name, and let Visual Studio create it. Visual Studio will create a template stored procedure for you.
  4. Customize the Visual Studio template. Visual Studio will generate a template for a managed stored procedure for you. Since you want to use SqlClient (the .NET data access provider for SQL Server) to connect to another SQL Server in this sample, you’ll need to add at least one more using (C#) or imports (Visual Basic) statement for System.Data.SqlClient.
  5. Code the stored procedure body. Now you need the code for the stored procedure. Let’s say you want to connect to another SQL Server (remember, your code will be running inside SQL Server), obtain some information based on input data, and process the results. Note that Visual Studio generated a SqlProcedure attribute for the stored procedure method; it is used by the Visual Studio deployment infrastructure, so leave it in place. If you take a look at the proceeding code you’ll notice that there is nothing different from old fashioned ADO.NET code that would run in the client or middle-tier. We love that part :)
    C#
    using System.Data;
    using System.Data.SqlClient;
    using Microsoft.SqlServer.Server;
    
    public partial class StoredProcedures {
      [Microsoft.SqlServer.Server.SqlProcedure()]
      public static void SampleSP() {
        // as usual, connection strings shouldn't be hardcoded for production code
        using(SqlConnection conn = new SqlConnection(
                                        "server=MyServer; database=AdventureWorks; " +
                                        "user id=MyUser; password=MyPassword")) {
          conn.Open();
    
          SqlCommand cmd = new SqlCommand(
                         "SELECT Name, GroupName FROM HumanResources.Department", conn);
    
          SqlDataReader r = cmd.ExecuteReader();
          while(r.Read()) {
            // consume the data from the reader and perform some processing
          }
        }
      }
    }
    
    Visual Basic .NET
    Imports System.Data
    Imports System.Data.SqlClient
    Imports Microsoft.SqlServer.Server
    
    Partial Public Class StoredProcedures
      <Microsoft.SqlServer.Server.SqlProcedure()> _
      Public Shared Sub SampleSP()
        Dim cmd As SqlCommand
        Dim r As SqlDataReader
    
        ' as usual, connection strings shouldn't be hardcoded for production code
        Using conn As New SqlConnection( _
         "server=MyServer; database=AdventureWorks; user id=MyUser; password=MyPassword")
          conn.Open()
    
          cmd = New SqlCommand( _
                       "SELECT Name, GroupName FROM HumanResources.Department", conn)
    
          r = cmd.ExecuteReader()
          Do While r.Read()
            ' consume the data from the reader and perform some processing
          Loop
        End Using
      End Sub
    End Class
  6. Deploy your assembly. Now you need to deploy your stored procedure in SQL Server. Visual Studio makes it trivial to deploy the assembly to SQL Server and take the appropriate steps to register each of the objects in the assembly with the server. After building the project, on the Build menu, choose Deploy Solution. Visual Studio will connect to SQL Server, drop previous versions of the assembly if needed, send the new assembly to the server and register it, and then register the stored procedure that you added to the assembly.
  7. Try it out. You can even customize the “test.sql” file that’s generated under the “Test Scripts” project folder to exercise the stored procedure you’re working on so Visual Studio will execute it when you press Ctrl+F5, or just press F5. (Yes, F5 will start the debugger, and you can debug code inside SQLCLR—both T-SQL and CLR code—isn’t that cool?)

Creating a managed stored procedure that uses ADO.NET using the SDK only

If you don’t have Visual Studio 2005 handy, or you’d like to see how things work the first time before letting Visual Studio do it for you, here is how to create a SQLCLR stored procedure by hand.

First, you need the code for the stored procedure. Let’s say you want to do the same as in the Visual Studio example: connect to another SQL Server, obtain some information based on input data, and process the results.

C#
using System.Data;
using System.Data.SqlClient;

public class SP {

  public static void SampleSP() {
    // as usual, connection strings shouldn't be hardcoded for production code
    using(SqlConnection conn = new SqlConnection(
                                      "server=MyServer; database=AdventureWorks; " +
                                      "user id=MyUser; password=MyPassword")) {
      conn.Open();

      SqlCommand cmd = new SqlCommand(
                     "SELECT Name, GroupName FROM HumanResources.Department", conn);

      SqlDataReader r = cmd.ExecuteReader();
      while(r.Read()) {
        // consume the data from the reader and perform some processing
      }
    }
  }
}

Visual Basic .NET
Imports System.Data
Imports System.Data.SqlClient

Public Class SP

  Public Shared Sub SampleSP()
    Dim cmd As SqlCommand
    Dim r As SqlDataReader

    ' as usual, connection strings shouldn't be hardcoded for production code
    Using conn As New SqlConnection( _
     "server=MyServer; database=AdventureWorks; user id=MyUser; password=MyPassword")
      conn.Open()

      cmd = New SqlCommand( _
                   "SELECT Name, GroupName FROM HumanResources.Department", conn)

      r = cmd.ExecuteReader()
      Do While r.Read()
        ' consume the data from the reader and perform some processing
      Loop
    End Using
  End Sub
End Class

Again, nothing different from old fashioned ADO.NET :)

Now you need to compile your code to produce a DLL assembly containing the stored procedure. The following command will do it (assuming that you called your file myprocs.cs/myprocs.vb and the .NET Framework 2.0 is in your path):

C#
csc /t:library myprocs.cs

VB
vbc /t:library myprocs.vb

This will compile your code and produce a new DLL called myprocs.dll. You need to register it with the server. Let’s say you put myprocs.dll in c:\temp, here are the SQL statements required to install the stored procedure in SQL Server from that path. You can run this either from SQL Server Management Studio or from the sqlcmd command-line utility:

-- Register the assembly
CREATE ASSEMBLY myprocs FROM 'c:\temp\myprocs.dll'
WITH PERMISSION_SET=EXTERNAL_ACCESS
GO
-- Register the stored-procedure
CREATE PROCEDURE SampleSP AS EXTERNAL NAME myprocs.SP.SampleSP

The EXTERNAL_ACCESS permission set is required because the code is accessing an external resource, in this case another SQL Server. The default permission set (SAFE) does not allow external access.

If you make changes to your stored procedure later on, you can refresh the assembly in SQL Server without dropping and recreating everything, assuming that you didn’t change the public interface (e.g., changed the type/number of parameters). In the scenario presented here, after recompiling the DLL, you can simply execute:

-- Refresh assembly from the file-system
ALTER ASSEMBLY myprocs FROM 'c:\temp\myprocs.dll'

The Context Connection

One data-access scenario that you can expect to be relatively common is that you’ll want to access the same server where your CLR stored procedure or function is executing.

One option for that is to create a regular connection using SqlClient, specify a connection string that points to the local server, and open it.

Now you have a connection. However, this is a separate connection; this implies that you’ll have to specify credentials for logging in—it will be a different database session, it may have different SET options, it will be in a separate transaction, it won’t see your temporary tables, etc.

In the end, if your stored procedure or function code is running inside SQLCLR, it is because someone connected to this SQL Server and executed some SQL statement to invoke it. You’ll probably want that connection, along with its transaction, SET options, and so on. It turns out that you can get to it; it is called the context connection.

The context connection lets you execute SQL statements in the same context that your code was invoked in the first place. In order to obtain the context connection you simply need to use the new context connection connection string keyword, as in the example below:

C#
using(SqlConnection c = new SqlConnection("context connection=true")) {
    c.Open();
    // do something with the connection
}

Visual Basic .NET
Using c as new SqlConnection("context connection=true")
    c.Open()
    ' do something with the connection
End Using

In order to see whether your code is actually running in the same connection as the caller, you can do the following experiment: use a SqlConnection object and compare the SPID (the SQL Server session identifier) as seen from the caller and from within the connection. The code for the procedure looks like this:

C#
using System.Data;
using System.Data.SqlClient;
using Microsoft.SqlServer.Server;

public partial class StoredProcedures {
    [Microsoft.SqlServer.Server.SqlProcedure()]
    public static void SampleSP(string connstring, out int spid) {
        using (SqlConnection conn = new SqlConnection(connstring)) {
            conn.Open();

            SqlCommand cmd = new SqlCommand("SELECT @@SPID", conn);
            spid = (int)cmd.ExecuteScalar();
        }
    }
}

Visual Basic .NET
Imports System.Data
Imports System.Data.SqlClient
Imports Microsoft.SqlServer.Server

Partial Public Class StoredProcedures
    <Microsoft.SqlServer.Server.SqlProcedure()> _
    Public Shared Sub SampleSP(ByVal connstring As String, ByRef spid As Integer)
        Using conn As New SqlConnection(connstring)
            conn.Open()

            Dim cmd As New SqlCommand("SELECT @@SPID", conn)
            spid = CType(cmd.ExecuteScalar(), Integer)
        End Using
    End Sub
End Class

After compiling and deploying this in SQL Server, you can try it out:

-- Print the SPID as seen by this connection
PRINT @@SPID

-- Now call the stored proc and see what SPID we get for a regular connection
DECLARE @id INT
EXEC SampleSP 'server=.;user id=MyUser; password=MyPassword', @id OUTPUT
PRINT @id

-- Call the stored proc again, but now use the context connection
EXEC SampleSP 'context connection=true', @id OUTPUT
PRINT @id

You’ll see that the first and last SPID will match, because they’re effectively the same connection. The second SPID is different because a second connection (which is a completely new connection) to the server was established.

Using ADO.NET in Different SQLCLR Objects

The “context” object

As you’ll see in the following sections that cover different SQLCLR objects, each one of them will execute in a given server “context.” The context represents the environment where the SQLCLR code was activated, and allows code running inside SQLCLR to access appropriate run-time information based on what kind of SQLCLR object it is.

The top-level object that surfaces the context is the SqlContext class that’s defined in the Microsoft.SqlServer.Server namespace.

Another object that’s available most of the time is the pipe object, which represents the connection to the client. For example, in T-SQL you can use the PRINT statement to send a message back to the client (if the client is SqlClient, it will show up as a SqlConnection.InfoMessage event). You can do the same in SQLCLR by using the SqlPipe object:

C#
SqlContext.Pipe.Send("Hello, World! (from SQLCLR)");

Visual Basic .NET
SqlContext.Pipe.Send("Hello, World! (from SQLCLR)")

Stored procedures

All of the samples I used above were based on stored procedures. Stored procedures can be used to obtain and change data both on the local server and in remote data sources.

Stored procedures can also send results to the client, just like T-SQL stored procedures do. For example, in T-SQL you can have a stored procedure that does this:

CREATE PROCEDURE GetVendorsMinRating(@rating INT)
AS
SELECT VendorID, AccountNumber, Name FROM Purchasing.Vendor
WHERE CreditRating <= @rating

A client running this stored procedure will see result sets coming back to the client (i.e., you would use ExecuteReader and get a SqlDataReader back if you were using ADO.NET in the client as well).

Managed stored procedures can return result sets, too. For stored procedures that are dominated by set-oriented statements such as the example above, using T-SQL is always a better choice. However, if you have a stored procedure that does a lot of computation-intensive work or uses a managed library and then returns some results, it may make sense to use SQLCLR. Here is the same procedure rewritten in SQLCLR:

C#
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
using Microsoft.SqlServer.Server;

public partial class StoredProcedures {
    [Microsoft.SqlServer.Server.SqlProcedure()]
    public static void SampleSP(int rating) {
        using (SqlConnection conn = new SqlConnection("context connection=true")) {
            conn.Open();

            SqlCommand cmd = new SqlCommand(
                "SELECT VendorID, AccountNumber, Name FROM Purchasing.Vendor " +
                "WHERE CreditRating <= @rating", conn);
            cmd.Parameters.AddWithValue("@rating", rating);

            // execute the command and send the results directly to the client
            SqlContext.Pipe.ExecuteAndSend(cmd);
        }
    }
}

Visual Basic .NET
Imports System.Data
Imports System.Data.SqlClient
Imports System.Transactions
Imports Microsoft.SqlServer.Server

Partial Public Class StoredProcedures
    <Microsoft.SqlServer.Server.SqlProcedure()> _
    Public Shared Sub SampleSP(ByVal rating As Integer)
        Dim cmd As SqlCommand

        ' connect to the context connection
        Using conn As New SqlConnection("context connection=true")
            conn.Open()

            cmd = New SqlCommand( _
                "SELECT VendorID, AccountNumber, Name FROM Purchasing.Vendor " & _
                "WHERE CreditRating <= @rating", conn)
            cmd.Parameters.AddWithValue("@rating", rating)

            ' execute the command and send the results directly to the client
            SqlContext.Pipe.ExecuteAndSend(cmd)
        End Using
    End Sub
End Class

The example above shows how to send the results from a SQL query back to the client. However, it’s very likely that you’ll also have stored procedures that produce their own data (e.g., by performing some computation locally or by invoking a Web service) and you’ll want to return that data to the client as a result set. That’s also possible using SQLCLR. Here is a trivial example:

C#
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
using Microsoft.SqlServer.Server;

public partial class StoredProcedures {
    [Microsoft.SqlServer.Server.SqlProcedure()]
    public static void SampleSP() {
        // simply produce a 10-row result-set with 2 columns, an int and a string

        // first, create the record and specify the metadata for the results
        SqlDataRecord rec = new SqlDataRecord(
            new SqlMetaData("col1", SqlDbType.NVarChar, 100),
            new SqlMetaData("col2", SqlDbType.Int));

        // start a new result-set
        SqlContext.Pipe.SendResultsStart(rec);

        // send rows
        for(int i = 0; i < 10; i++) {
            // set values for each column for this row
            // This data would presumably come from a more "interesting" computation
            rec.SetString(0, "row " + i.ToString());
            rec.SetInt32(1, i);
            SqlContext.Pipe.SendResultsRow(rec);
        }

        // complete the result-set
        SqlContext.Pipe.SendResultsEnd();
    }
}

Visual Basic .NET
Imports System.Data
Imports System.Data.SqlClient
Imports System.Transactions
Imports Microsoft.SqlServer.Server

Partial Public Class StoredProcedures
    <Microsoft.SqlServer.Server.SqlProcedure()> _
    Public Shared Sub SampleSP()
        ' simply produce a 10-row result-set with 2 columns, an int and a string

        ' first, create the record and specify the metadata for the results
        Dim rec As New SqlDataRecord( _
            New SqlMetaData("col1", SqlDbType.NVarChar, 100), _
            New SqlMetaData("col2", SqlDbType.Int))

        ' start a new result-set
        SqlContext.Pipe.SendResultsStart(rec)

        ' send rows
        Dim i As Integer
        For i = 0 To 9
            ' set values for each column for this row
            ' This data would presumably come from a more "interesting" computation
            rec.SetString(0, "row " & i.ToString())
            rec.SetInt32(1, i)
            SqlContext.Pipe.SendResultsRow(rec)
        Next

        ' complete the result-set
        SqlContext.Pipe.SendResultsEnd()
    End Sub
End Class

User-defined functions

User-defined scalar functions already existed in previous versions of SQL Server. In SQL Server 2005 scalar functions can also be created using managed code, in addition to the already existing option of using T-SQL. In both cases the function is expected to return a single scalar value.

SQL Server assumes that functions do not cause side effects. That is, functions should not change the state of the database (no data or metadata changes). For T-SQL functions, this is actually enforced by the server, and a run-time error would be generated if a side-effecting operation (e.g. executing an UPDATE statement) were attempted.

The same restrictions (no side effects) apply to managed functions. However, there is less enforcement of this restriction. If you use the context connection and try to execute a side-effecting T-SQL statement through it (e.g., an UPDATE statement) you’ll get a SqlException from ADO.NET. However, we cannot detect it when you perform side-effecting operations through regular (non-context) connections. In general it is better play safe and not do side-effecting operations from functions unless you have a very clear understanding of the implications.

Also, functions cannot return result sets to the client as stored procedures do.

Table-valued user-defined functions

T-SQL table-valued functions (or TVFs) existed in previous versions of SQL Server. In SQL Server 2005 we support creating TVFs using managed code. We call table-valued functions created using managed code “streaming table-valued functions,” or streaming TVFs for short.

  • They are “table-valued” because they return a relation (a result set) instead of a scalar. That means that they can, for example, be used in the FROM part of a SELECT statement.
  • They are “streaming” because after an initialization step, the server will call into your object to obtain rows, so you can produce them based on server demand, instead of having to create all the result in memory first and then return the whole thing to the database.

Here is a very simple example of a function that takes a single string with a comma-separated list of words and returns a single-column result-set with a row for each word.

C#
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
using Microsoft.SqlServer.Server;

public partial class Functions {
    [Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName="FillRow")]
    // if you're using VS then add the following property setter to
    // the attribute above: TableDefinition="s NVARCHAR(4000)"
    public static IEnumerable ParseString(string str) {
        // Split() returns an array, which in turn
        // implements IEnumerable, so we're done :)
        return str.Split(',');
    }

    public static void FillRow(object row, out string str) {
        // "crack" the row into its parts. this case is trivial
        // because the row is only made of a single string
        str = (string)row;
    }
}

Visual Basic .NET
Imports System.Collections
Imports System.Data
Imports System.Data.SqlClient
Imports System.Transactions
Imports System.Runtime.InteropServices
Imports Microsoft.SqlServer.Server

Partial Public Class Functions
    <Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName:="FillRow")> _
    ' if you're using VS then add the following property setter to
    ' the attribute above: TableDefinition:="s NVARCHAR(4000)"
    Public Shared Function ParseString(ByVal str As String) As IEnumerable
        ' Split() returns an array, which in turn
        ' implements IEnumerable, so we're done :)
        Return Split(str, ",")
    End Function

    Public Shared Sub FillRow(ByVal row As Object, <Out()> ByRef str As String)
        ' "crack" the row into its parts. this case is trivial
        ' because the row is only made of a single string
        str = CType(row, String)
    End Sub
End Class

If you’re using Visual Studio, simply deploy the assembly with the TVF. If you’re doing this by hand, execute the following to register the TVF (assuming you already registered the assembly):

-- register the managed TVF
CREATE FUNCTION ParseString(@str NVARCHAR(4000))
RETURNS TABLE (s NVARCHAR(4000))
AS EXTERNAL NAME myprocs.Functions.ParseString

Once registered, you can give it a try by executing this T-SQL statement:

-- Use the TVF in a SELECT statement, throwing-in an "order by" just because
SELECT s FROM dbo.ParseString('a,b,c') ORDER BY s DESC

Now, what does this have to do with data access? Well, it turns out there are a couple of restrictions to keep in mind when using ADO.NET from a TVF:

  • TVFs are still functions, so the side-effect restrictions also apply to them.
  • You can use the context connection in the initialization method (e.g., ParseString in the example above), but not in the method that fills rows (the method pointed to by the FillRowMethodName attribute property).
  • You can use ADO.NET with regular (non-context) connections in both initialization and fill-row methods. Note that performing queries or other long-running operations in the fill-row method can seriously impact the performance of the SELECT statement that uses the TVF.

Triggers

Creating triggers is in many aspects very similar to creating stored procedures. You can use ADO.NET to do data access from a trigger just like you would from a stored procedure.

For the triggers case, however, you’ll typically have a couple of extra requirements:

  • You’ll want to “see” the changes that caused the trigger to fire. In a T-SQL trigger you’d typically do this by using the INSERTED and DELETED tables. For a managed trigger the same still applies: as long as you use the context connection, you can reference the INSERTED and DELETED tables from your SQL statements that you execute in the trigger using a SqlCommand object.
  • You’ll want to be able to tell which columns changed. You can use the IsUpdatedColumn() method of the SqlTriggerContext class to check whether a given column has changed. An instance of SqlTriggerContext is available off of the SqlContext class when the code is running inside a trigger; you can access it using the SqlContext.TriggerContext property.

Another common practice is to use a trigger to validate the input data, and if it doesn’t pass the validation criteria, then abort the operation. You can also do this from managed code by simply using this statement:

C#
System.Transactions.Transaction.Current.Rollback();

Visual Basic .NET
System.Transactions.Transaction.Current.Rollback()

Wow, what happened there? It is simple thanks to the tight integration of SQLCLR with the .NET Framework. See the Part II: Advanced Topics section, Transactions, for more information.

When Not to Use SQLCLR + ADO.NET

Don’t just wrap SQL

If you have a stored procedure that only executes a query, then it’s always better to write it in T-SQL. Writing it in SQLCLR will take more development time (you have to write T-SQL code for the query and managed code for the procedure) and it will be slower at run-time.

Whenever you use SQLCLR to simply wrap a relatively straightforward piece of T-SQL code, you’ll get worse performance and extra maintenance cost. SQLCLR is better when there is actual work other than set-oriented operations to be done in the stored procedure or function.

Note   The samples in this article are always parts of stored procedures or functions, and are never complete real-world components of production-level databases. I only include the minimum code necessary to exercise the ADO.NET API I am describing. That’s why many of the samples contain only data-access code. In practice, if your stored procedure or function only has data-access code, then you should double-check and see if you could write it in T-SQL.

Avoid procedural row processing if set-oriented operations can do it

Set-oriented operations can be very powerful. Sometimes it can be tricky to get them right, but once they are there, the database engine has a lot of opportunities to understand what you want to do based on the SQL statement that you provide, and it can perform deep, sophisticated optimizations on your behalf.

So in general it’s a good thing to process rows using set-oriented statements such as UPDATE, INSERT and DELETE.

Good examples of this are:

  • Avoid row-by-row scans and updates. If at all possible, it’s much better to try to write a more sophisticated UPDATE statement.
  • Avoid custom aggregation of values by explicitly opening a SqlDataReader and iterating over the values. Either use the built-in aggregation functions (SUM, AVG, MIN, MAX, etc.) or create user-defined aggregates.

There are of course some scenarios where row-by-row processing using procedural logic makes sense. It’s mostly a matter of making sure that you don’t end up doing row-by-row processing for something that could be expressed in a single SQL statement.

Part II: Advanced Topics

More on Connections

Choosing between regular and context connections

If you’re connecting to a remote server, you’ll always be using regular connections. On the other hand, if you need to connect to the same server you’re running a function or stored procedure on, in most cases you’ll want to use the context connection. As I mentioned above, there are several reasons for this, such as running in the same transaction space, and not having to reauthenticate.

Additionally, using the context connection will typically result in better performance and less resource utilization. The context connection is an in-process–only connection, so it can talk to the server “directly”, meaning that it doesn’t need to go through the network protocol and transport layer to send SQL statements and receive results. It doesn’t need to go through the authentication process either.

There are some cases where you may need to open a separate regular connection to the same server. For example, there are certain restrictions in using the context connection described in the Restrictions for the context connection section.

What do you mean by connect “directly” to the server?

I mentioned before that the context connection could connect “directly” to the server and bypass the network protocol and transport layers. Figure 1 represents the primary components of the SqlClient managed provider, as well as how the different components interact with each other when using a regular connection, and when using the context connection.

ms345135.mandataaccess_01(en-US,SQL.90).gif

Figure 1. Connection processes

As you can see, the context connection follows a shorter code path and involves fewer components. Because of that, you can expect the context connection to get to the server and back faster than a regular connection. Query execution time will be the same, of course, because that work needs to be done regardless of how the SQL statement reaches the server.

Restrictions for the context connection

Here are the restrictions that apply to the context connection that you’ll need to take into account when using it in your application:

  • You can have only one context connection opened at a given time for a given connection.
    • Of course, if you have multiple statements running concurrently in separate connections, each one of them can get their own context connection. The restriction doesn’t affect concurrent requests from different connections; it only affects a given request on a given connection.
  • MARS (Multiple Active Result Sets) is not supported in the context connection.
  • The SqlBulkCopy class will not operate on a context connection.
  • We do not support update batching in the context connection.
  • SqlNotificationRequest cannot be used with commands that will execute against the context connection.
  • We don’t support canceling commands that are running against the context connection. SqlCommand.Cancel() will silently ignore the request.
  • No other connection string keywords can be used when you use context connection=true.

Some of these restrictions are by design and are the result of the semantics of the context connection. Others are actually implementation decisions that we made for this release and we may decide to relax those restrictions in a future release based on customer feedback.

Restrictions on regular connections inside SQLCLR

For those cases where you decide to use regular connections instead of the context connection, there are a few limitations to keep in mind.

Pretty much all the functionality of ADO.NET is available inside SQLCLR; however, there are a few specific features that either do not apply, or we decided not to support, in this release. Specifically, asynchronous command execution and the SqlDependecy object and related infrastructure are not supported.

Credentials for connections

You probably noticed that all the samples I’ve used so far use SQL authentication (user id and password) instead of integrated authentication. You may be wondering why I do that if we always strongly suggest using integrated authentication.

It turns out that it’s not that straightforward to use inside SQLCLR. There are a couple of considerations that need to be kept in mind before using integrated authentication.

First of all, no client impersonation happens by default. This means that when SQL Server invokes your CLR code, it will be running under the account of the SQL Server service. If you use integrated authentication, the “identity” that your connections will have will be that of the service, not the one from the connecting client. In some scenarios this is actually intended and it will work fine. In many other scenarios this won’t work. For example, if your SQL Server runs as “local system”, then you won’t be able to login to remote servers using integrated authentication.

Note   Skip these next two paragraphs if you want to avoid a headache :)

In some cases you may want to impersonate the caller by using the SqlContext.WindowsIdentity property instead of running as the service account. For those cases we expose a WindowsIdentity instance that represents the identity of the client that invoked the calling code. This is only available when the client used integrated authentication in the first place (otherwise we don’t know the Windows identity of the client). Once you obtained the WindowsIdentity instance you can call Impersonate to change the security token of the thread, and then open ADO.NET connections on behalf of the client.

It gets more complicated. Even if you obtained the instance, by default you cannot propagate that instance to another computer; Windows security infrastructure restricts that by default. There is a mechanism called “delegation” that enables propagation of Windows identities across multiple trusted computers. You can learn more about delegation in the TechNet article, Kerberos Protocol Transition and Constrained Delegation.

Transactions

Let’s say you have a managed stored procedure called SampleSP that has the following code:

C#
// as usual, connection strings shouldn't be hardcoded for production code
using(SqlConnection conn = new SqlConnection(
  "server=MyServer; database=AdventureWorks; user id=MyUser; password=MyPassword")) {
  conn.Open();

  // insert a hardcoded row for this sample
  SqlCommand cmd = new SqlCommand("INSERT INTO HumanResources.Department " +
     "(Name, GroupName) VALUES ('Databases', 'IT'); SELECT SCOPE_IDENTITY()", conn);
  outputId = (int)cmd.ExecuteScalar();
}

Visual Basic .NET
Dim cmd as SqlCommand

' as usual, connection strings shouldn't be hardcoded for production code
Using conn As New SqlConnection( _
     "server=MyServer; database=AdventureWorks; user id=MyUser; password=MyPassword")
  conn.Open()

  ' insert a hardcoded row for this sample
  cmd = New SqlCommand("INSERT INTO HumanResources.Department " _ &
      "(Name, GroupName) VALUES ('Databases', 'IT'); SELECT SCOPE_IDENTITY()", conn)
  outputId = CType(cmd.ExecuteScalar(), Integer)
End Using

What happens if you do this in T-SQL?

BEGIN TRAN
DECLARE @id INT
-- create a new department and get its ID
EXEC SampleSP @id OUTPUT
-- move employees from department 1 to the new department
UPDATE Employees SET DepartmentID = @id WHERE DepartmentID = @id
-- now undo the entire operation
ROLLBACK

Since you did a BEGIN TRAN first, it’s clear that the ROLLBACK statement will undo the work done by the UPDATE from T-SQL. But the stored procedure created a new ADO.NET connection to another server and made a change there, what about that change? Nothing to worry about—we’ll detect that the code established ADO.NET connections to remote servers, and by default we’ll transparently take any existing transaction with the connection and have all servers your code connects to participate in a distributed transaction. This even works for non-SQL Server connections!

How do we do this? We have GREAT integration with System.Transactions.

System.Transactions + ADO.NET + SQLCLR

System.Transactions is a new namespace that’s part of the 2.0 release of the .NET Framework. It contains a new transactions framework that will greatly extend and simplify the use of local and distributed transactions in managed applications.

For an introduction to System.Transactions and ADO.NET, see the MSDN Magazine article, Data Points: ADO.NET and System.Transactions, and the MSDN TV episode, Introducing System.Transactions in .NET Framework 2.0.

ADO.NET and SQLCLR are tightly integrated with System.Transactions to provide a unified transactions API across the .NET Framework.

Transaction promotion

After reading about all the magic around distributed transactions for procedures, you may be thinking about the huge overhead this implies. It turns out that it’s not bad at all.

When you invoke managed stored procedures within a database transaction, we flow the transaction context down into the CLR code.

As I mentioned before, the context connection is literally the same connection, so the same transaction applies and no extra overhead is involved.

On the other hand, if you’re opening a connection to a remote server, that’s clearly not the same connection. When you open an ADO.NET connection, we automatically detect that there is a database transaction that came with the context and “promote” the database transaction into a distributed transaction; then we enlist the connection to the remote server into that distributed transaction so everything is now coordinated. And this extra cost is only paid if you use it; otherwise it’s only the cost of a regular database transaction. Cool stuff, huh?

Note   A similar transaction promotion feature is also available with ADO.NET and System.Transactions when used from the client and middle-tier scenarios. Consult the documentation on MSDN for further details.

Accessing the current transaction

At this point you may be wondering, “How do they know that there is a transaction active in the SQLCLR code to automatically enlist ADO.NET connections?” It turns out that integration goes deeper.

Outside of SQL Server, the System.Transactions framework exposes the concept of a “current transaction,” which is available through System.Transaction.Current. We basically did the same thing inside the server.

If a transaction was active at the point where SQLCLR code is entered, then the transaction will be surfaced to the SQLCLR API through the System.Transactions.Transaction class. Specifically, Transaction.Current will be non-null.

In most cases you don’t need to access the transaction explicitly. For database connections, ADO.NET will check Transaction.Current automatically during connection Open() and it will enlist the connection in that transaction transparently (unless you add enlist=false to the connection string).

There are a few scenarios where you might want to use the transaction object directly:

  • If you want to abort the external transaction from within your stored procedure or function. In this case, you can simply call Transaction.Current.Rollback().
  • If you want to enlist a resource that doesn’t do automatic enlistment, or for some reason wasn’t enlisted during initialization.
  • You may want to enlist yourself in the transaction, perhaps to be involved in the voting process or just to be notified when voting happens.

Note that although I used a very explicit example where I do a BEGIN TRAN, there other scenarios where your SQLCLR code can be invoked inside a transaction and Transaction.Current will be non-null. For example, if you invoke a managed user-defined function within an UPDATE statement, it will happen within a transaction even if one wasn’t explicitly started.

Using System.Transactions explicitly

If you have a block of code that needs to execute within a transaction even if the caller didn’t start one, you can use the System.Transactions API. This is, again, the same code you’d use in the client or middle-tier to manage a transaction. For example:

C#
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
using Microsoft.SqlServer.Server;

public partial class StoredProcedures {
  [Microsoft.SqlServer.Server.SqlProcedure()]
  public static void SampleSP() {

    // start a transaction block
    using(TransactionScope tx = new TransactionScope()) {

      // connect to the context connection
      using(SqlConnection conn = new SqlConnection("context connection=true")) {
        conn.Open();

        // do some changes to the local database
      }

      // connect to the remote database
      using(SqlConnection conn = new SqlConnection(
                                  "server=MyServer; database=AdventureWorks;" +
                                  "user id=MyUser; password=MyPassword")) {
        conn.Open();

        // do some changes to the remote database
      }

      // mark the transaction as complete
      tx.Complete();
    }
  }
}

Visual Basic .NET
Imports System.Data
Imports System.Data.SqlClient
Imports System.Transactions
Imports Microsoft.SqlServer.Server

Partial Public Class StoredProcedures
  <Microsoft.SqlServer.Server.SqlProcedure()> _
  Public Shared Sub SampleSP()

    ' start a transaction block
    Using tx As New TransactionScope()

      ' connect to the context connection
      Using conn As New SqlConnection("context connection=true")
        conn.Open()

        ' do some changes to the local database
      End Using

      ' connect to a remote server (don't hardcode the conn string in real code)
      Using conn As New SqlConnection("server=MyServer; database=AdventureWorks;" & _
                                      "user id=MyUser; password=MyPassword")
        conn.Open()

        ' do some changes to the remote database
      End Using

      ' mark the transaction as completed
      tx.Complete()
    End Using
  End Sub
End Class

The sample above shows the simplest way of using System.Transactions. Simply put a transaction scope around the code that needs to be transacted. Note that towards the end of the block there is a call to the Complete method on the scope indicating that this piece of code executed its part successfully and it’s OK with committing this transaction. If you want to abort the transaction, simply don’t call Complete.

The TransactionScope object will do the “right thing” by default. That is, if there was already a transaction active, then the scope will happen within that transaction; otherwise, it will start a new transaction. There are other overloads that let you customize this behavior.

The pattern is fairly simple: the transaction scope will either pick up an already active transaction or will start a new one. In either case, since it’s in a “using” block, the compiler will introduce a call to Dispose at the end of the block. If the scope saw a call to Complete before reaching the end of the block, then it will vote commit for the transaction; on the other hand, if it didn’t see a call to Complete (e.g., an exception was thrown somewhere in the middle of the block), then it will rollback the transaction automatically.

Note   For the SQL Server 2005 release, the TransactionScope object will always use distributed transactions when running inside SQLCLR. This means that if there wasn’t a distributed transaction already, the scope will cause the transaction to promote. This will cause overhead if you only connect to the local server; in that case, SQL transactions will be lighter weight. On the other hand, in scenarios where you use several resources (e.g., connections to remote databases), the transaction will have to be promoted anyway, so there is no additional overhead.
I recommend not using TransactionScope if you’re going to connect only using the context connection.

Using SQL transactions in your SQLCLR code

Alternatively, you can still use regular SQL transactions, although those will handle local transactions only.

Using the existing SQL transactions API is identical to how SQL transactions work in the client/middle-tier. You can either using SQL statements (e.g., BEGIN TRAN) or call the BeginTransaction method on the connection object. That returns a transaction object (e.g., SqlTransaction) that then you can use to commit/rollback the transaction.

These transactions can be nested, in the sense that your stored procedure or function might be called within a transaction, and it would still be perfectly legal for you to call BeginTransaction. (Note that this does not mean you get “true” nested transactions; you’ll get the exact same behavior that you’d get when nesting BEGIN TRAN statements in T-SQL.)

Transaction lifetime

There is a difference between transactions started in T-SQL stored procedures and the ones started in SQLCLR code (using any of the methods discussed above): SQLCLR code cannot unbalance the transaction state on entry/exit of a SQLCLR invocation. This has a couple of implications:

  • You cannot start a transaction inside a SQLCLR frame and not commit it or roll it back; SQL Server will generate an error during frame exit.
  • Similarly, you cannot commit or rollback an outer transaction inside SQLCLR code.
    • Any attempt to commit a transaction that you didn’t start in the same procedure will cause a run-time error.
    • Any attempt to rollback a transaction that you didn’t start in the same procedure will doom the transaction (preventing any other side-effecting operation from happening), but the transaction won’t disappear until the SQLCLR code unwinds. Note that this case is actually legal, and it’s useful when you detect an error inside your procedure and want to make sure the whole transaction is aborted.

Conclusion

SQLCLR is a great technology and it will enable lots of new scenarios. Using ADO.NET inside SQLCLR is a powerful mix that will allow you to combine heavy processing with data access to both local and remote servers, all while maintaining transactional correctness.

As with any other technology, this one has a specific application domain. Not every procedure needs to be rewritten in SQLCLR and use ADO.NET to access the database; quite the contrary, in most cases T-SQL will do a great job. However, for those cases where sophisticated logic or rich libraries are required inside SQL Server, SQLCLR and ADO.NET are there to do the job.

Acknowledgements

Thanks to Acey Bunch, Alazel Acheson, Alyssa Henry, Angel Saenz-Badillos, Chris Lee, Jian Zeng, Mary Chipman and Steve Starck for taking the time to review this document and provide helpful feedback.

Yazı kategorisi: Ado.Net, SQLCLR, Sql Server | » yorum bırak;

XML Features in ADO.NET

Yazan: esersahin 07/11/2008

http://msdn.microsoft.com/en-us/library/ms810298.aspx

Dino Esposito
Wintellect

December 13, 2001

XML and some of its related technologies, including XPath, XSL Transformation, and XML Schema, are unquestionably at the foundation of ADO.NET. As a matter of fact, XML constitutes the key element for the greatly improved interoperability of the ADO.NET object model when compared to ADO. In ADO, XML was merely an (non-default) I/O format used to persist the content of a disconnected recordset. The participation of XML in the building and in the inter-workings of ADO.NET is much deeper. The aspects of ADO.NET where the interaction and the integration with XML is stronger can be summarized in the following points:

  • Objects serialization and remoting
  • A dual programming interface
  • XML-driven batch update (for SQL Server 2000 only)

In ADO.NET, you have several options to save objects to, and restore objects from, XML documents. To say it all, this ability belongs to one object only—the DataSet—but can be extended to other container objects with minimal coding. Saving objects like DataTable and DataView to XML is substantially seen as a special case of the DataSet serialization.

Furthermore, ADO.NET and XML classes provide for a sort of unified intermediate API that is made available to programmers through a dual and synchronized programming interface. You can access and update data using either the hierarchical and node-based approach of XML ,or the relational approach of column-based tabular data sets. At any time, you can switch from a DataSet representation of the data to XMLDOM, and vice versa. Data is synchronized and any change you enter in either model is immediately reflected and visible in the other. In this article, I’ll cover ADO.NET-to-XML serialization and XML data access—that is, the first two points in the list above. Next month, I’ll attack XML-driven batch update—one of the coolest features you get from SQL Server 2000 XML Extensions (SQLXML 2.0).

DataSet and XML

Just like any other .NET object, the DataSet object is stored in memory in a binary format. Unlike other objects, though, the DataSet is always remoted and serialized in a special XML format called the DiffGram. When the DataSet trespasses the boundaries of the app-domains, or the physical borders of the machine, it is automatically rendered as a DiffGram. At destination, the DataSet is silently rebuilt as a binary and promptly usable object. The same serialization facilities are available to applications through a bunch of methods, a pair of which clearly stands out. They are ReadXml and WriteXml. The table below presents the DataSet’s methods you can use to work with XML, both in reading and in writing.

Methods Description
GetXml
  • Returns a string that is the XML representation of the data stored in the DataSet
  • No schema information is included
GetXmlSchema
  • Returns a string that is the XML schema information for the DataSet
ReadXml
  • Populates a DataSet object with the specified XML data read from a stream or a file
ReadXmlSchema
  • Loads the specified XML schema information into the current DataSet object
WriteXml
  • Writes the XML data, and optionally the schema, that represents the DataSet
  • Can write to a stream or a file
WriteXmlSchema
  • Writes the string being the XML schema information for the DataSet
  • Can write to a stream or a file

As the table shows, when working with DataSet and XML you can manage data and schema information as distinct entities. You can take the XML schema out of a DataSet and use it as a string. Alternately, you could write it to a disk file or load it into an empty DataSet object. Side by side with the methods listed in the table above, the DataSet object also features two XML-related properties—Namespace and Prefix. Namespace determines the XML namespace used to scope XML attributes and elements when you read them into a DataSet. The prefix to alias the namespace is stored in the Prefix property.

Building a DataSet from XML

The ReadXml method fills out a DataSet object reading from a variety of sources, including disk files, .NET streams, or instances of XmlReader objects. The method can process any type of XML file, but, of course, XML files having a non-tabular and rather irregularly shaped structure may create some problems when rendered in terms of rows and columns.

The ReadXml method has several overloads, all of which are rather similar. They take the XML source plus an optional XmlReadMode value as arguments. For example:

public XmlReadMode ReadXml(String, XmlReadMode);

The method creates the relational schema for the DataSet depending on the read mode specified, and whether or not a schema already exists in the DataSet. The following code snippet illustrates the typical code you would use to load a DataSet from XML.

StreamReader sr = new StreamReader(fileName);
DataSet ds = new DataSet();
ds.ReadXml(sr);   // defaults to XmlReadMode.Auto
sr.Close();

When loading the contents of XML sources into a DataSet, ReadXml does not merge rows whose primary key information match. To merge an existing DataSet with one loaded from XML, you first have to create a new DataSet, and then merge the two using the Merge method. During the merging, the rows that get overwritten are those with matching primary keys. An alternate way to merge existing DataSet objects with contents read from XML is through the DiffGram format (more on this later).

The table below illustrates the various read modes that ReadXml supports. You can set them using the XmlReadMode enumeration.

Read Mode Description
IgnoreSchema Ignores any inline schema and relies on the DataSet’s existing schema
ReadSchema Reads any inline schema and loads the data and schema
InferSchema Ignores any inline schema and infers the schema from the XML data
DiffGram Reads a DiffGram and adds the data to the current schema
Fragment Reads and adds XML fragments until the end of the stream is reached

The default read mode is not listed in the table and is XmlReadMode.Auto. When this mode is set, or when no read mode has been explicitly set, the ReadXml method examines the XML source and chooses the most appropriate option.

If the XML source turns out to be a DiffGram, then it is loaded as such. If the source happens to contain an inline schema, or a reference to an external schema, it is loaded using ReadXmlSchema. Finally, if no schema information is available in the XML source, then the ReadXml method infers the schema using the DataSet’s InferXmlSchema method. The relational structure, or schema, of a DataSet is made up of tables, columns, constraints, and relations. Let’s review what exactly happens when each of the modes is set.

The XmlReadMode.IgnoreSchema option causes the method to ignore any inline or referenced schema. So, the data is loaded into the existing DataSet schema and any data that does not fit in it is discarded. If no schema exists in the DataSet, no data is loaded. Notice that an empty DataSet has no schema information. Bear in mind that if the XML source is in a DiffGram format, then the IgnoreSchema option has the same effect as XmlReadMode.DiffGram.

// no schema in the DataSet, no data will be loaded
DataSet ds = new DataSet();
StreamReader sr = new StreamReader(fileName);
ds.ReadXml(sr, XmlReadMode.IgnoreSchema);

The XmlReadMode.ReadSchema option works only with inline schema and does not recognize external references. It can add new tables to the DataSet, but if any tables defined in the inline schema already exist in the DataSet, an exception is thrown. You cannot use the ReadSchema option to change the schema of an existing table. If the DataSet does not contain a schema (that is, it’s empty), and there is no inline schema, no data is read and loaded. ReadXml can only read inline schemas defined using the XML Schema definition language (XSD) or XML-Data Reduced (XDR). No document type definition (DTD) is supported.

When the XmlReadMode.InferSchema option is set, ReadXml infers the schema directly from the structure of the XML data and ignores any inline schema that may be present. The data is loaded only when the schema has been inferred. Existing schemas are extended by adding new tables, or by adding new columns to existing tables, as appropriate. You can use the DataSet’s InferXmlSchema method to load the schema from the specified XML file into the DataSet. You can control, to some extent, the XML elements processed during the schema inference operation. The signature of the method InferXmlSchema allows you to specify an array of namespaces whose elements will be excluded from inference.

void InferXmlSchema(String fileName, String[] rgNamespace);

A DiffGram is an XML format that ADO.NET utilizes to persist the state of a DataSet. Similar to the SQLXML’s updategram format, the DiffGram contains both current and original versions of data rows. Loading a DiffGram using ReadXml will merge rows that have the matching primary keys. You explicitly instruct ReadXml to work on a DiffGram using the XmlReadMode.DiffGram flag. When using the DiffGram format, the target DataSet must have the same schema as the DiffGram, otherwise the merge operation fails and an exception is thrown.

When the XmlReadMode.Fragment option is set, the DataSet is loaded from an XML fragment. An XML fragment is a valid piece of XML that identifies elements, attributes, and documents. The XML fragment for an element is the markup text that fully qualifies the XML element (node, CDATA, processing instruction, comment). The fragment for an attribute is the attribute value, and for a document is the entire content set. When the XML data is a fragment, the root level rules for well-formed XML documents are not applied. Fragments that match the existing schema are appended to the appropriate tables and fragments that do not match the schema are discarded. ReadXml reads from the current position to the end of the stream. The XmlReadMode.Fragment option should not be used to populate an empty, and subsequently schema-less, DataSet.

Serializing DataSet Objects to XML

The XML representation of the DataSet can be written to a file, a stream, an XmlWriter object, or a string, using the WriteXml method. The XML representation can include, or not include, schema information. The actual behavior of the WriteXml method can be controlled through the optional XmlWriteMode parameter you can pass. The values in the XmlWriteMode enum determine the output’s layout. The DataSet representation includes tables, relations, and constraints definitions. The rows in the DataSet’s tables are written in their current versions unless you choose to employ the DiffGram format. The table below summarizes the writing options available with XmlWriteMode.

Write Mode Description
IgnoreSchema Writes the contents of the DataSet as XML data without schema
WriteSchema Writes the contents of the DataSet with an inline XSD schema
DiffGram Writes the contents of the DataSet as a DiffGram, including original and current values

XmlWriteMode.IgnoreSchema is the default option. The following code shows the typical way to serialize a DataSet to XML.

// ds is the DataSet
StreamWriter sw = new StreamWriter(fileName);
ds.WriteXml(sw);   // defaults to XmlWriteMode.IgnoreSchema
sw.Close();

A few factors influence the final structure of the XML document created from the contents of a DataSet object. They are;

  • The overall XML format used—DiffGram or plain hierarchical representation of the current contents
  • The presence of schema information
  • Nested relations
  • How table columns are mapped to XML elements

The DiffGram format is a special XML format that I’ll describe more in depth in a moment. It does not include schema information, but preserves row state and row errors. As such, it seems able to constitute a closer representation of the living instance of the DataSet.

Schema information, if present in the DataSet being created, is always written as inline XSD. There’s no way for you to write it as XDR, DTD, or add a reference to an external file. The root node of the generated XML file takes the name of the DataSet, or NewDataSet, if no name has been specified. The following code snippet is an example of the XML representation of a DataSet object made of two tables, Customers and Orders, put into relationship on the CustomerID field.

<MyDataSet>
<xs:schema ... />
<Customers>
   <CustomerID>1</CustomerID>
   <FName>John</FName>
   <LName>Smith</LName>
</Customers>
<Customers>
   <CustomerID>2</CustomerID>
   <FName>Joe</FName>
   <LName>Users</LName>
</Customers>
<Orders>
   <CustomerID>1</CustomerID>
   <OrderID>000A01</OrderID>
</Orders>
<Orders>
   <CustomerID>1</CustomerID>
   <OrderID>000B01</OrderID>
</Orders>
</MyDataSet>

From the listing above, you can hardly say that the two tables are in relation. Some information about this is set in the <xs:schema> tree, but aside from this, nothing else would hint toward that conclusion. A relation set on the CustomerID field put down in words sounds like this—all the orders issued by a given customer. The XML tree above does not provide an immediate representation for this information. To change the order of the nodes when a data relation is present in the DataSet, you can set the Nested attribute of the DataRelation object to true. As a result of this change, the XML code from above changes as follows:

<MyDataSet>
<xs:schema ... />
<Customers>
   <CustomerID>1</CustomerID>
   <FName>John</FName>
   <LName>Smith</LName>
<Orders>
   <CustomerID>1</CustomerID>
   <OrderID>000A01</OrderID>
</Orders>
<Orders>
   <CustomerID>1</CustomerID>
   <OrderID>000B01</OrderID>
</Orders>
</Customers>
<Customers>
   <CustomerID>2</CustomerID>
   <FName>Joe</FName>
   <LName>Users</LName>
</Customers>
</MyDataSet>

As you can see, all the orders are now grouped under the corresponding customer subtree.

By default, in XML table columns are rendered as node elements. However, this is only a setting that can be adjusted on a per column basis. The DataColumn object has a property called ColumnMapping that determines how that column will be rendered in XML. The ColumnMapping property takes values from the MappingType enum listed below.

Mapping Description
Element Mapped to an XML node element:<CustomerID>value</CustomerID>
Attribute Mapped to an XML node attribute:<Customers CustomerID=value>
Hidden Not displayed in the XML data unless the DiffGram format is used
SimpleContent Mapped to simple text:<Customers>value</Customers>

If the XML output format is the DiffGram, then the Hidden mapping type is ignored. In this case, though, the DiffGram representation of the column features a special attribute that marks the column as originally hidden from XML serialization. The SimpleContent mapping type is not always available and can be used only if the table has one column.

The DiffGram Format

A DiffGram is simply an XML string written according to a particular schema that represents the contents of a DataSet. It is in no way a .NET type. The following code snippet shows how to serialize a DataSet object to a DiffGram.

StreamWriter sw = new StreamWriter(fileName);
ds.WriteXml(sw, XmlWriteMode.DiffGram);
sw.Close();

The resulting XML code is rooted in the <diffgr:diffgram> node, and contains up to three distinct sections of data, as shown below:

<diffgr:diffgram>
   <MyDataSet>
   :
   </MyDataSet>

   <diffgr:before>
   :
   </diffgr:before>

   <diffgr:errors>
   :
   </diffgr:errors>
</diffgr:diffgram>

The first section of the DiffGram is mandatory and represents the current instance of the data. It is nearly identical to the XML output you can get from ordinary serialization. The major difference between the two is that the DiffGram format never includes schema information.

The data section includes the current values of the rows in the DataSet. The original rows, including deleted rows, are stored in the <diffgr:before> section. Only modified or deleted records are listed here. Newly added records are only listed in the data instance as they have no preceding reference to which to link. The rows in the two sections are tracked using a unique ID. These rows represent the delta between the original and the current version of the DataSet.

Finally, in the <diffgr:errors> section, any message that relates to pending errors on rows is listed . Also in this case, rows are tracked using the same unique ID discussed for changes. DiffGram nodes can be flagged with special attributes to relate elements across different sections—data instance, changes, and errors.

Attribute Description
diffgr:hasChanges The row has been modified (see related row in <diffgr:before>) or inserted.
diffgr:hasErrors The row has an error (see related row in <diffgr:errors>).
diffgr:id Identifies the ID used to couple rows across sections: TableName+RowIdentifier.
diffgr:parentId Identifies the ID used to identify the parent of the current row.
diffgr:error Contains the error text for the row in <diffgr:errors>.
msdata:rowOrder Tracks the ordinal position of the row in the DataSet.
msdata:hidden Identifies columns marked as hidden msdata:hiddenColumn=…

The ADO.NET Framework provides explicit XML support only for the DataSet object. However, converting a DataView or a DataTable to XML is not particularly hard. In both cases, you have to use a temporary DataSet as the container for the set of rows you want to save as XML. The code necessary to save a DataTable to XML is simple.

void WriteDataTableToXml(String fileName, DataTable dt)
{
   // Duplicate the table and add it to a temporary DataSet
   DataSet dsTmp = new DataSet();
   DataTable dtTmp = dt.Copy();
   dsTmp.Tables.Add(dtTmp);

   // Save the temporary DataSet to XML
   StreamWriter sr = new StreamWriter(fileName);
   dsTmp.WriteXml(sr);
   sr.Close();
}

It’s important that you duplicate the DataTable object for the simple reason that each ADO.NET object can be referenced only by one container object. You cannot have the same instance of, say, a DataTable object belonging to two distinct DataSet objects.

Unlike the DataTable object, the DataView is not a standard part of a DataSet, so in order to save it to XML you should convert the DataView to a table object. This is demonstrated by the following code:

void DataViewToDataTable(DataView dv)
{
// Clone the structure of the table behind the view
DataTable dtTemp = dv.Table.Clone();
   dtTemp.TableName = "Row";   // this is arbitrary!

   // Populate the table with rows in the view
   foreach(DataRowView drv in dv)
      dtTemp.ImportRow(drv.Row);

   // giving a custom name to the DataSet can help to
   // come up with a clearer layout but is not mandatory
   DataSet dsTemp = new DataSet(dv.Table.TableName);   

   // Add the new table to a temporary DataSet
   dsTemp.Tables.Add(dtTemp);
}

As a first step, you clone the structure of the table lying behind the DataView object that is being processed. Next, you walk through all the records in this view and add the corresponding rows to a temporary DataTable. Then this DataTable is added to a temporary DataSet and serialized. You can also manage to give the DataSet the table name and a customized format to the whole XML output. For example:

<TableName>
   <Row>
      <Column1>…</Column1>
      :
   </Row>
   <Row>
   :
   </Row>
   <Row>
   :
</Row>
</TableName>

The XmlDataDocument Class

XML and ADO.NET Frameworks offer a unified model to access data represented as both XML and relational data. The key XML class for this is XmlDataDocument, whereas the DataSet is the key ADO.NET class. XmlDataDocument, in particular, inherits from the base class XmlDocument and differs from it only in the ability to synchronize with DataSet objects. When synchronized, DataSet and XmlDataDocument classes work on the same collection of rows, and you can apply changes through both interfaces (nodes and relational tables) and make them immediately visible to both classes. Basically, DataSet and XmlDataDocument provide two sets of tools for the same data. As a result, you can apply XSLT transformations to relational data, query relational data through XPath expressions, and use SQL to select XML nodes.

There are a few ways to bind a DataSet object and XmlDataDocument object together. The first option is that you pass a non-empty DataSet object to the constructor of the XmlDataDocument class.

XmlDataDocument doc = new XmlDataDocument(dataset);

Like its base class, XmlDataDocument provides a XML DOM approach to work with XML data and, as such, turns out to be quite different from XML readers and writers. An alternate way of synchronizing the two objects is the following example that creates a valid and non-empty DataSet object from a non-empty instance of the XML DOM.

XmlDataDocument doc = new XmlDataDocument();
doc.Load(fileName);
DataSet dataset = doc.DataSet;

You turn an XML document into a DataSet object using the XmlDataDocument’s DataSet property. The property instantiates, populates, and returns a DataSet object. The data set is associated with the XmlDataDocument the first time you access the DataSet property. The methods GetElementFromRow and GetRowFromElement switch between the XML and relational view of the data. In order to view the XML data relationally, you must first specify a schema to use for data mapping. This can be done by calling the ReadXmlSchema method on the same XML file. As an alternate approach, you can manually create the necessary tables and columns in the DataSet.

Yet another way to synchronize XmlDataDocument and DataSet objects is when they are empty and you fill both separately. For example,

DataSet dataset = new DataSet();
XmlDataDocument xmldoc = new XmlDataDocument(dataset);
xmldoc.Load("file.xml");

Keeping the two objects synchronized provides an unprecedented level of flexibility since, as mentioned earlier, you can use two radically different types of navigation to move through records. In fact, you can use SQL-like queries on XML nodes, as well as XPath queries on relational rows.

Not all XML files can be successfully synchronized with a DataSet. For this to happen, XML documents must have a regular, tabular structure that can be mapped to a relational architecture where each row has the same number of columns. When rendered as DataSet objects, XML documents lose any XML-specific information they may have and for which there isn’t a relational counterpart. This information includes comments, declarations. and processing instructions.

Summary

In ADO.NET, XML is more than a simple output format for serializing content. You can use XML to streamline the entire contents of a DataSet object, but you can also choose the actual XML schema and control the structure of the resulting XML document. You can mirror the contents of the DataSet, including tables and relations, you can take the schema information out of the final document, and you can even resort to the DiffGram format.

ADO.NET has a lot more to offer when it comes to interacting and integrating with XML. In particular, in .NET you can simultaneously provide and exploit two equivalent but independent views of the same data that obey to different logical data representations.

Dialog Box: Using GetChanges with Batch Update

I’ve seen that the DataSet programming interface provides for a method called GetChanges, which returns a smaller DataSet filled out only with the updated rows in all included tables. So, I’m led to think that using this smaller DataSet, instead of the original one, results in improved performance. However, there was something in your last articleI can hardly say what and wherethat has thrown some doubtful exceptions in my mind. So the question is, can you shed some more light on the use of the DataSet’s GetChanges method in batch update?

The ADO.NET batch update is based on a loop that walks its way through the rows on the specified table. The code checks the state of the row and decides which action to take. The loop works on the DataSet and the DataTable you provide as an argument to the adapter’s method Fill. If you call Fill on the original DataSet, or on the smaller DataSet returned by GetChanges, the results are roughly the same. The optimization is minimal and serves only to reduce the length of the loop.

During the batch update process, rows are processed sequentially from the middle-tier to data server. There is no snapshot of data that is sent down to the database in a single shot or as a single block of data. In this case, in fact, using GetChanges would result in much more optimized code.

The key parameter that determines how many significant operations are performed during the batch update is the number of modified rows. This parameter does not change regardless of whether you use the original DataSet or the one returned by GetChanges.

By contrast, if you batch update from the DataSet returned by GetChanges, you may run into serious troubles when a conflict is detected. In this case, the rows processed prior to the one that failed are regularly committed, but not on the original DataSet! To guarantee the consistency of your application, you must accept changes on the committed rows, as well as changes on the original DataSet. This code is entirely on its own. All in all, the batch update code is much easier if you use the original DataSet.

Dino Esposito is Wintellect’s ADO.NET expert and a trainer and consultant based in Rome, Italy. Dino is a contributing editor to MSDN Magazine and writes the Cutting Edge column. He also regularly contributes to Developer Network Journal and MSDN News. Dino is the author of the upcoming Building Web Solutions with ASP.NET and ADO.NET from Microsoft Press, and the cofounder of http://www.vb2themax.com/. You can reach Dino at dinoe@wintellect.com.

Yazı kategorisi: Ado.Net, XML | » yorum bırak;

ADO.NET Entity Framework

Yazan: esersahin 26/10/2008

http://msdn.microsoft.com/en-us/data/aa937723.aspx

A

primary goal of the ADO.NET Entity Framework is to raise the level of abstraction available for data programming, thus simplifying the development of data aware applications and enabling developers to write less code. The Entity Framework is the evolution of ADO.NET that allows developers to program in terms of the standard ADO.NET abstraction or in terms of persistent objects (ORM) and is built upon the standard ADO.NET Provider model which allows access to third party databases. The Entity Framework introduces a new set of services around the Entity Data Model (EDM) (a medium for defining domain models for an application).

Technical Articles

Introducing LINQ to Relational Data
Learn more about using LINQ against a Relational database with LINQ to SQL and LINQ to Entities. What are the key scenarios for which each of these technologies was designed?
Next-Generation Data Access: Making the Conceptual Level Real
Eliminate the impedance mismatch for both applications and data services like reporting, analysis, and replication offered as part of the SQL Server product by raising the level of abstraction from the logical (relational) level to the conceptual (entity) level.

Channel 9


Webcasts

Programming LINQ and the ADO.NET Entity Framework (Level 200)
Language Integrated Query (LINQ) introduces an exciting new way for applications to build strongly typed queries that are deeply integrated into the programming language. The ADO.NET Entity Framework allows applications and services to work in terms of an application-oriented Entity Data Model, decoupling the application’s data model from the storage considerations of the relational schema. Join this webcast to see how these two technologies work together to change the way applications work with data.
24 Hours of SQL Server 2008: Using the Microsoft Data Platform for Easy Data Access with SQL Server 2008 (Level 100)
Join this series as we look at Microsoft SQL Server 2008 as a productive data platform. Throughout this series, we use Contoso (Container Overseas Shipping Operation) LTD as our scenario customer while we explore the features that make SQL Server 2008 this platform.
MSDN geekSpeak: Julie Lerman on ADO.NET (Level 200)
MSDN geekSpeak is a new kind of webcast series, hosted by Glen Gordon and Susan Wisowaty from the MSDN Events team, that provides a “talk-radio” format where industry experts share their knowledge of and experience with a particular developer technology. In this installment of geekSpeak, Julia Lerman, a Microsoft Most Valuable Professional (MVP), discusses the next version of ADO.NET, which presents a host of new ways to interact with data in your Microsoft .NET applications. Learn how the ADO.NET Entity Framework provides for abstracted access to your data, client views and schemas, and mapping of data to objects. See how you can build queries on the client against your own views and schemas using Entity SQL and Language-Integrated Query (LINQ).
Framework Masterclass: LINQ to Entities (Level 200)
In other sessions, we explored how Microsoft .NET Language Integrated Query (LINQ) is used for Structured Query Language (SQL) databases and working with XML. In this webcast, we connect to the data access layer, the business objects that provide the functionality of working with enterprise data. Join us to learn how you can make your LINQ applications really sing when working with entities.
Entity Framework for Database Administrators (Level 200)
The Entity Framework is a new data technology from Microsoft that may particularly interest database administrators (DBAs). Join this webcast to see how this technology can radically change the development of applications from a DBA perspective, and also change access patterns on servers. We discuss these changes and their impact on DBAs and data developers.

Yazı kategorisi: Ado.Net, Entity, Framework | » yorum bırak;

Getting Started with ADO.NET Data Services

Yazan: esersahin 26/10/2008

http://codebetter.com/blogs/david.hayden/archive/2008/01/08/getting-started-with-ado-net-data-services.aspx

At the Sarasota Visual Studio 2008 InstallFest I showed off a number of ASP.NET 3.5 Extensions CTP Features. One was ASP.NET Dynamic Data, which I have talked about in several posts:

Another was ADO.NET Data Services.

For those of you who haven’t played with ADO.NET Data Services, you owe yourself a quick 5 minute look to think about the possibilities. Here is the quick introduction I provided at the Visual Studio 2008 InstallFest.

Install the ASP.NET 3.5 Extensions CTP

First things first, swing over to the ASP.NET Website to download and install the ASP.NET 3.5 Extesions CTP, which includes ADO.NET Data Services.

You can find it here: http://www.asp.net/downloads/3.5-extensions/

Note this is a CTP, so common sense applies to what machines you install it on.

Create a New ASP.NET Website

Run Visual Studio 2008 and Create a New ASP.NET Website

Create ASP.NET Website

Add LINQ To SQL Classes and ADO.NET Data Services Items

We need some data, and one of the easiest ways to get data is to add a LINQ TO SQL Classes File to the solution and drag and drop Northwind Tables on it. We also need to add the ADO.NET Data Services Item to the solution as that is what we are trying to test. I called my items, Northwind and NorthwindDataService, respectively.

Hopefully LINQ To SQL is fairly easy to add. ADO.NET Data Services is even easier to add:

Add ADO.NET Data Services

When all is said and done, the solution looks like this:

ADO.NET Data Services Solution

Configure NorthwindDataService to use NorthwindDataContext

Open up the NorthwindDataService.cs in the App_Code Folder and change the code to look like below:

public class NorthwindDataService :
            WebDataService<NorthwindDataContext> {

    public static void InitializeService(IWebDataServiceConfiguration config)
    {
        config.SetResourceContainerAccessRule
            ("*", ResourceContainerRights.AllRead);
    }
    
}

Note that I added the NorthwindDataContext and set the access rules to allow access to all the data provided by the NorthwindDataContext in a read-only fashion.

Run the Website and Begin Querying

Now you can just run the website and start querying products or anything else in the Northwind Database using REST type URL’s.

Fetch ProductID = 1 : http://localhost:1453/WebSite5/NorthwindDataService.svc/Products(1)

Northwind ADO.NET Data Service

Fetch the Supplier for the Product : http://localhost:1453/WebSite5/NorthwindDataService.svc/Products(1)/Supplier

ADO.NET Data Services - Supplier

Fetch Products 11 – 20 : http://localhost:1453/WebSite5/NorthwindDataService.svc/Products?$skip=10&$top=10

Fetch Name of Product : http://localhost:1453/WebSite5/NorthwindDataService.svc/Products(1)/ProductName/$value

I think I change Chai to Chai2 playing with the database, so your version will probably say Chai :)

Read the Documentation

Check out the documentation on ADO.NET Data Services for the ASP.NET 3.5 Extensions CTP at:

http://quickstarts.asp.net/3-5-extensions/adonetdataservice/default.aspx

Pretty cool stuff…

}

Note that I added the NorthwindDataContext and set the access rules to allow access to all the data provided by the NorthwindDataContext in a read-only fashion.

Run the Website and Begin Querying

Now you can just run the website and start querying products or anything else in the Northwind Database using REST type URL’s.

Fetch ProductID = 1 : http://localhost:1453/WebSite5/NorthwindDataService.svc/Products(1)

Northwind ADO.NET Data Service

Fetch the Supplier for the Product : http://localhost:1453/WebSite5/NorthwindDataService.svc/Products(1)/Supplier

ADO.NET Data Services - Supplier

Fetch Products 11 – 20 : http://localhost:1453/WebSite5/NorthwindDataService.svc/Products?$skip=10&$top=10

Fetch Name of Product : http://localhost:1453/WebSite5/NorthwindDataService.svc/Products(1)/ProductName/$value

I think I change Chai to Chai2 playing with the database, so your version will probably say Chai :)

Read the Documentation

Check out the documentation on ADO.NET Data Services for the ASP.NET 3.5 Extensions CTP at:

http://quickstarts.asp.net/3-5-extensions/adonetdataservice/default.aspx

Pretty cool stuff…

Yazı kategorisi: Ado.Net, Data, Service | » yorum bırak;

ADO.NET Data Services (formerly known as Project “Astoria”)

Yazan: esersahin 26/10/2008

http://msdn.microsoft.com/en-us/data/bb931106.aspx

The ADO.NET Data Services framework consists of a combination of patterns and libraries that enable the creation and consumption of data services for the web. The goal of the ADO.Net Data Services framework is to facilitate the creation of flexible data services that are naturally integrated with the web, using URIs to point to pieces of data and simple, well-known formats to represent that data, such as JSON and plain XML. This results in the data service being surfaced to the web as a REST-style resource collection that is addressable with URIs and that agents can interact with using the usual HTTP verbs such as GET, POST or DELETE.

Yazı kategorisi: Ado.Net, Data, Service | » yorum bırak;

SQL Server and ADO.NET

Yazan: esersahin 26/10/2008

http://msdn.microsoft.com/en-us/library/kb9s9ks0.aspx

This section describes features and behaviors that are specific to the .NET Framework Data Provider for SQL Server (System.Data.SqlClient).

System.Data.SqlClient provides access to versions of SQL Server starting with SQL Server 7.0, which encapsulates database-specific protocols. The functionality of the data provider is designed to be similar to that of the .NET Framework data providers for OLE DB, ODBC, and Oracle. System.Data.SqlClient includes a tabular data stream (TDS) parser to communicate directly with SQL Server.

Note:
To use the .NET Framework Data Provider for SQL Server, an application must reference the System.Data.SqlClient namespace.
New Features in SQL Server 2008 (ADO.NET)
Describes SqlClient support for functionality introduced in SQL Server SQL Server 2008.

SQL Server Security (ADO.NET)
Provides an overview of SQL Server security features, and application scenarios for creating secure ADO.NET applications that target SQL Server.

SQL Server Data Types and ADO.NET
Describes how to work with SQL Server data types and how they interact with .NET Framework data types.

SQL Server Data Operations in ADO.NET
Describes how to work with data in SQL Server. Contains sections about working with binary and large value (max) data, table-valued parameters, bulk copy, MARS, and asynchronous operations.

SQL Server Features and ADO.NET
Describes SQL Server features that are useful for ADO.NET application developers.

LINQ to SQL
Describes the basic building blocks, processes, and techniques required for creating LINQ to SQL applications.

For complete documentation of the SQL Server Database Engine, see SQL Server Books Online for the version of SQL Server you are using.

Yazı kategorisi: Ado.Net, Sql Server | » yorum bırak;

Retrieving and Modifying Data in ADO.NET

Yazan: esersahin 26/10/2008

http://msdn.microsoft.com/en-us/library/ms254937.aspx

A primary function of any database application is connecting to a data source and retrieving the data that it contains. The .NET Framework data providers of ADO.NET serve as a bridge between an application and a data source, allowing you to execute commands as well as to retrieve data by using a DataReader or a DataAdapter. A key function of any database application is the ability to update the data that is stored in the database. In ADO.NET, updating data involves using the DataAdapter and DataSet, and Command objects; and it may also involve using transactions.

Connecting to a Data Source (ADO.NET)
Describes how to establish a connection to a data source and how to work with connection events.

Connection Strings (ADO.NET)
Contains topics describing various aspects of using connection strings, including connection string keywords, security info, and storing and retrieving them.

Connection Pooling (ADO.NET)
Describes connection pooling for the .NET Framework data providers.

Commands and Parameters (ADO.NET)
Contains topics describing how to create commands and command builders, configure parameters, and how to execute commands to retrieve and modify data.

DataAdapters and DataReaders (ADO.NET)
Contains topics describing DataReaders, DataAdapters, parameters, handling DataAdapter events and performing batch operations.

Transactions and Concurrency (ADO.NET)
Contains topics describing how to perform local transactions, distributed transactions, and work with optimistic concurrency.

Retrieving Identity or Autonumber Values (ADO.NET)
Provides an example of mapping the values generated for an identity column in a Microsoft SQL Server table or for an Autonumber field in a Microsoft Access table, to a column of an inserted row in a table. Discusses merging identity values in a DataTable.

Retrieving Large Data (ADO.NET)
Describes how to retrieve binary data or large data structures using CommandBehavior.SequentialAccess to modify the default behavior of a DataReader.

Modifying Data with Stored Procedures (ADO.NET)
Describes how to use stored procedure input parameters and output parameters to insert a row in a database, returning a new identity value.

Retrieving Database Schema Information (ADO.NET)
Describes how to obtain available databases or catalogs, tables and views in a database, constraints that exist for tables, and other schema information from a data source.

DbProviderFactories (ADO.NET)
Describes the provider factory model and demonstrates how to use the base classes in the System.Data.Common namespace.

Data Tracing in ADO.NET
Describes how ADO.NET provides built-in data tracing functionality.

Performance Counters (ADO.NET)
Describes performance counters available for SqlClient and OracleClient.

Yazı kategorisi: Ado.Net | » yorum bırak;

ADO.NET Entity Framework

Yazan: esersahin 26/10/2008

http://msdn.microsoft.com/en-us/library/bb399572.aspx

The ADO.NET Entity Framework is designed to enable developers to create data access applications by programming against a conceptual application model instead of programming directly against a relational storage schema. The goal is to decrease the amount of code and maintenance required for data-oriented applications. Entity Framework applications provide the following benefits:

  • Applications can work in terms of a more application-centric conceptual model, including types with inheritance, complex members, and relationships.
  • Applications are freed from hard-coded dependencies on a particular data engine or storage schema.
  • Mappings between the conceptual model and the storage-specific schema can change without changing the application code.
  • Developers can work with a consistent application object model that can be mapped to various storage schemas, possibly implemented in different database management systems.
  • Multiple conceptual models can be mapped to a single storage schema.
  • Language-integrated query support provides compile-time syntax validation for queries against a conceptual model.

Yazı kategorisi: Ado.Net, Entity, Framework | » yorum bırak;