Reputation: 214
Suppose I want to parse the sql statement
SELECT foo, bar, baz FROM myTable WHERE baz = 2 ORDER BY baz ASC, bar DESC
and programmatically determine the columns and directions it's ordering by. After some googling, here's what I've come up with:
List<ParseError> Errors;
TSql100Parser parser = new TSql100Parser(true);
TSqlFragment result = parser.Parse(
new StringReader("SELECT foo, bar, baz FROM myTable WHERE baz = 2 ORDER BY baz ASC, bar DESC"),
out Errors);
foreach (var ts in (result as TSqlScript).Batches)
{
foreach (var st in ts.Statements)
{
SelectStatement selectStatement = (SelectStatement) st;
IList<ExpressionWithSortOrder> _list = selectStatement.QueryExpression.OrderByClause.OrderByElements;
var c0 = _list[0].Expression as ColumnReferenceExpression;
var c1 = _list[1].Expression as ColumnReferenceExpression;
Assert.AreEqual("baz", c0.MultiPartIdentifier.Identifiers[0].Value);
Assert.AreEqual("Ascending", _list[0].SortOrder.ToString());
Assert.AreEqual("bar", c1.MultiPartIdentifier.Identifiers[0].Value);
Assert.AreEqual("Descending", _list[1].SortOrder.ToString());
}
}
This code works fine, but I find it very confusing. There are two places where the "as" keyword seems weird to me.
The first of these is on line 6. TsqlScript is a subclass of TSqlFragment, so I guess I lucked into being able to cast it to a subclass. But TSqlFragment, which is the return type of the Parse method on line 3 doesn't have any useful properties, only its subclass has useful properties. So what kind of API would expose a class that is only helpful if you happen to know to cast it to something else?
The second, and more confusing use of "as", is used in the inner foreach. How is it possible that I've turned ExpressionWithSortOrders into ColumnReferenceExpressions? They are classes, not interfaces, and they don't inherit from each other. As far as I can tell, they have neither explicit nor implicit conversion into each other.
More generally, how can one learn to work with an API like this? I haven't found anything about this casting in the official scriptdom documentation. Visual Studio doesn't tell me that I can turn these classes into each other.
Upvotes: 0
Views: 306
Reputation: 49270
Concerning the "first case":
MSDN states that the overload of the Parse
method you use
Returns a script fragment and a list of errors by using the provided values. (Inherited from TSqlParser.)
So I guess that should be enough to know it is a TSqlScript
class ;-)
Concerning the "second case":
var c0 = _list[0].Expression as ColumnReferenceExpression;
var c1 = _list[1].Expression as ColumnReferenceExpression;
How is it possible that I've turned ExpressionWithSortOrders into ColumnReferenceExpressions?
But you didn't. You turned the Expression
property of the ExpressionWithSortOrder
class into a ColumnReferenceExpression
, which according to the docs is perfectly OK as Expression
is of type ScalarExpression
, and ColumnReferenceExpression
inherits from that.
Upvotes: 1