Rants Tagged with “ADO.NET”

<<  <  1  2  3  4  5  6  7  8    (Total Pages: 8/Total Results: 78)

ADO.NET Powertoys and GotDotNet Workspace

I have finally gotten sick of GotDotNet's flakyness and moved the source and installer to my website.  I am looking for a new home and may end up at SourceForge.  If you have had any problems with the installer or finding the source, please visit http://wildermuth.com/powertoys.

Data Part 2: n-Tier...Gone Tomorrow

Recently I was talking with Rocky Lhotka and he said something interesting:

Just when we got good at Client-Server, they switched things and had us doing n-Tier applications.  Just when we got good at n-Tier development, internet applications took off.

In my opinion he is right. It is interesting because client-server and n-Tier applications still exist, especially in enterprise development.  I think we're good at client-server and n-Tier.  The problem is that I think that much of browser based development attempts to apply n-Tier development. 

What do I mean?  In simple words, the web server is the middle tier.   The browser is the client tier. 

The idea behind n-Tier development is being able to separate the data work into a tier that can be scaled out.  Luckily we know how to scale out webservers (into farms).  Since we are securing webservers, we can isolate security issues from the client...just like we've done in n-Tier development.

 

Data Part 1: Business Objects, Messages and DataSets...

I've had time lately to think about the nature of data in development lately.  I've been talking with Rocky Lhotka and Michael Earls about it (as well as number of others) about the issues with dealing with data in applications. 

The first camp is all about writing Business Objects.  In this camp, you write classes that encapsulate the data, the data access and business rules about that data.  This camp was the way to do it for years now.  It proliferated in the Client-Server and n-Tier architecture camps. 

Rocky Lhotka espouses his excellent CSLA.NET framework.  If you are going the business object road, I wholeheartedly recommend it.  It is designed around allowing object to exist locally or on separate servers through remoting.

The second camp is that data is all about data, so data is just a message to some system.  With the excitement around Service Oriented Architectures (SOA), this view is starting to prevail.

Somewhere in the middle is where I sit.  I think that data and business rules belong together, but the data access can be disconnected from it.  So this is the interesting fact in my opinion...there are reasons to have the data access separated from the end users' machines (so perhaps remote data access), but once in the client, you want to have the business logic (and schema) as close to the client as possible.  The closer it is to the client, the better it should scale.  I don't like to see finely grained data access happening.  Even in client-server apps, the more coarsely grained the data access, the better it should scale IMHO.

There is more I want to say on this, so stay tuned.  I will be posting every day about this.

Tomorrow:  “n-Tier, gone tomorrow”

Connections, Command and Transactions...oh my!

I was taking a refresher MCSD test today to get ready to take one of the tests and came upon a question that is wrong.  But it does infer that there is some confusion about how transactions are propogated to commands...or may be evidence that it is a bug.  For example:

SqlConnection conn = null;
SqlTransaction tx = null;
try
{
  // Create a new Connection
  conn = new SqlConnection("Server=.;Database=Northwind;Integrated Security=true;");

  // Open the Connection
  conn.Open();

  // Start a Transaction and create a new Command
  tx = conn.BeginTransaction();
  using (SqlCommand cmd = new SqlCommand())
  {
    // Set the Connection to the command
    cmd.Connection = conn;

    // NOTE: I do not explicitly set the TX to the Command
    //cmd.Transaction = tx;

    // Insert new values and execute it 
    // (within the transaction)
    cmd.CommandText = @"INSERT INTO Customers (CustomerID, CompanyName) 
                        VALUES ('ZZZZY', 'My New Company');";
    cmd.ExecuteNonQuery();

    // Insert new values, but the table name is wrong
    cmd.CommandText = @"INSERT INTO Companies (CompanyID) VALUES('ANother Company')";
    cmd.ExecuteNonQuery();

    // We should never get here since the query is wrong
    tx.Commit();
  }
}
catch (Exception ex)
{
  // Rollback the tx if error'd
  if (tx != null) tx.Rollback();
}
finally
{
  tx.Dispose();
  // Close the connection just in case
  if (conn != null)
  {
    conn.Close();
    conn.Dispose();
  }
}

This code fails because I do not explicitly set the transaction to the command.  Unfortuately, you must set the connection and the transaction.  This seems like a bug because you cannot execute a command on the connection (that has an pending transaction) without throwing an error. 

The practice test asked me to specify a single missing line of code, so I could either set the command's connection property or it's transaction property, but not both.  I suspect that there is confusion inside of MS about what is the expected behavior.  But for now, I will just continue to set both and know that the test is wrong....

CSV and ADO.NET

Chris Sells has just built a good ADO.NET test application to access text files (comma delimited).  I only wish I had done it first.  It looks great!

Things About Typed DataSet Generation I Never Noticed...

I have been thinking a lot about how Typed DataSets are generated and was spelunking through the code again when it got me thinking. The Typed DataSet generator doesn't really generate the code based on the .xsd, but on the DataSet. It simply loads the .xsd into a DataSet then interrogates the DataSet directly for everything (tables, columns, relationships, constraints). So if the Typed DataSet Designer cannot handle something (like relationships *without* constraints, see below), but the DataSet schema allows it...simply create the DataSet and save the .xsd file to see what it produces! This gets around some fundamental problems with the designer. It does require you start looking and understanding .xsd, but it is a useful skill to have anyway...right?

So my first relevation was how to add unconstrained relationships (no foreign key constraint, simply a way to navigate the data). Since the designer does not allow this, I looked at the .xsd and found that the DataSet handles this with a schema annotation:


<xs:schema>
  <xs:annotation>
    <xs:appinfo>
      <msdata:Relationship name="ta2t" 
        msdata:parent="titleauthor" 
        msdata:child="titles" 
        msdata:parentkey="title_id"
        msdata:childkey="title_id" />
    </xs:appinfo>
  </xs:annotation>
</xs:schema>

The five pieces of data in the msdata:Relationship element are the four pieces of data required when setting up a relationship. Pretty simple huh!

It makes me start to think of other DataSet allowable things that the Designer doesn't know about.

ADO.NET's DataAdapters and Opened Connections

I have been reviewing a bunch of code that utilizes ADO.NET's DataAdapters. This code has been some samples that are on the Internet, some questions directly to http://wildermuth.com and others from DevelopMentor's .NET Mailing Lists. One thing I have noticed is that much of that code is opening the database connection before using the DataAdapter to fill a DataSet.

This does work, but there seems to be some confusion about how this should work. In fact, under the covers all DataAdapters open and close the database if it has not already been done. This is because the DataAdapter knows when to open and close the connection to the database to minimize the length of time that the precious resource (the connection) is actually open. This is what the code looks like that I've been reviewing:


// Create the DataSet
DataSet dataSet = new DataSet();

// Create the Connection
SqlConnection conn = new SqlConnection("...");

// Create the Command
SqlDataAdapter adapter = new SqlDataAdapter("...", conn);

// Open the Connection
conn.Open();

// Fill the DataSet
adapter.Fill(dataSet);

// Close the Connection
conn.Close();

In reality, you don't need to open the close the connection before using it with an adapter. If the connection is closed, it will open it and close it as soon as it is done with the connection. I would expected to see more code that looked like this:


// Create the DataSet
DataSet dataSet = new DataSet();

// Create the Connection
SqlConnection conn = new SqlConnection("...");

// Create the Command
SqlDataAdapter adapter = new SqlDataAdapter("...", conn);

// Fill the DataSet
adapter.Fill(dataSet);

There are times when you would want to open the connection first, but usually only if you are doing many small Fill()'s or Update()'s. In most cases, letting the DataAdapter handle the connection object's state is the right thing to do.

Web Services and DataSets: Why the Bad Rap?

Why is everyone so down on using DataSets in .NET Web Services? Sure, I’ll admit that using DataSets directly as Web Service parameters are indeed a problem. But why throw the baby out with the bath water?

For the uninitiated, DataSets are a problem as Web Service parameters because XML that is automatically generated as the parameter is a DiffGram of the DataSet. Unfortunately DiffGrams are simply not interop-friendly. At the end of the day the obvious use of DataSets in .NET Web Services are simply a bad idea.

But if we deal with DataSets as XML instead of a class to be serialized we can actually achieve some real benefits. If you have experienced DataSets, you know that you can specify an .xsd as the schema of the DataSet. What that means is that you can deliver the contents of the DataSet with relevant schema as an XML document. Since the resulting XML document can refer to a specific schema, the consumers of the Web Service (whether they are using Java, WebSphere, or .NET) will receive a self-describing, strongly typed piece of information.

But how does this work? The trick is wrapping your DataSet in an XmlDataDocument. By specifying your Web Service method like so:


[WebMethod]
public XmlDocument GetAllTheData()
{
  return new XmlDataDocument(yourDataSet);
}

This works because the XmlDataDocument derives from XmlDocument so that the XmlSerializer serializes it as an XML document. Whether the 'yourDataSet' field is a TypedDataSet or just a DataSet with an .xsd specified for its schema, the Web Service will export it as vanilla XML that can be consumed by any number of clients.