Rants Tagged with “ADO.NET”
<< < 1 2 3 4 5 6 7 8 (Total Pages: 8/Total Results: 78)
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.
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.
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”
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....
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!
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.
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.
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.