using System.Linq;
using System.Linq.Dynamic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
namespace DynamicExpression.Example
{
public static class DynamicExpressionTest
{
/// <summary>
/// This example requires the DynamicExpression API referenced at:
/// http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
///
/// The DXTEST command excercises rudimentary use of DynamicExpression to
/// generate a query expression from a string. In this example, the string
/// is hard-coded, but might just as easily be derived from user input, etc.,
/// at runtime in real world use. In essence, DynamicExpression implements
/// a very basic, rudimentary query language that has a syntax designed to
/// be familiar to C#, VB and SQL users.
///
/// It should be noted however, that direct use of user-supplied query
/// strings can be dangerous, without extensive error checking.
///
/// This example will obtain all insertions of the block named 'DOOR'
/// that are inserted on the layer named 'LEVEL1', and change their
/// color to red. Note that the dynamic expression is not used to
/// filter entities by type, as this is done using ObjectIds rather
/// than opened DBObjects. Hence, the input sequence contains only
/// BlockReference objects and is the type which the query operates
/// on and whose properties are used in the query string.
///
/// The example code also requires the AutoCAD Linq Extension Library
/// which is included (AcDbLinq.cs).
///
/// </summary>
[CommandMethod( "DXTEST" )]
public static void Method1()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
using( Transaction tr = doc.TransactionManager.StartTransaction() )
{
/// This returns an object that iterates over all BlockRefence
/// objects in model space:
var blockrefs = doc.Database.GetModelSpace<BlockReference>().AsQueryable();
/// There are three basic ways to compose a query string, and which is
/// best depends on where the parameters are coming from, and where the
/// query string itself comes from. For example, only the parameters
/// may be supplied by the user, or the entire query string may be
/// supplied by the user.
///
/// The first way is simply to express it as a literal string, using
/// escaped double-quotes to surround string constants, thusly:
/// var query = blockrefs.Where( "Name == \"DOOR\" && Layer = \"LEVEL1\"" );
///
/// Another way of doing it is by constructing the entire
/// query string using String.Format():
///
/// string queryString = string.Format(
/// "Name == \"{0}\" AND Layer == \"{1}\"", "DOOR", "LEVEL1" );
/// var query = blockrefs.Where( queryString );
///
/// And lastly, and the one we actually use here, is by using replacements,
/// which has the advantage of not requiring string parameters to be
/// surrounded by double quotes, presumably because the type of a parameter
/// can be inferred by the type of the expression on the left side of the
/// relational operator:
var query = blockrefs.Where( "Name == @0 && Layer == @1", "DOOR", "LEVEL1" );
/// The above 'query' var is an IQueryable<BlockReference>, which implicitly
/// is an IEnumerable<BlockReference> that we can walk using foreach():
foreach( BlockReference door in query.UpgradeOpen() )
{
door.ColorIndex = 1;
}
tr.Commit();
}
}
/// <summary>
///
/// A variation on the above that uses pattern matching for the
/// layer name, and selects all insertions of 'DOOR' from model
/// space, that reside on any layer whose name starts with "LEVEL".
/// Matching is achieved using the string.StartsWith() method
/// within the query expression.
///
/// </summary>
[CommandMethod( "DXTEST2" )]
public static void Method2()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
using( Transaction tr = doc.TransactionManager.StartTransaction() )
{
var blockrefs = doc.Database.GetModelSpace<BlockReference>().AsQueryable();
var query = blockrefs.Where( "Name == @0 && Layer.StartsWith(@1)", "DOOR", "LEVEL" );
foreach( BlockReference door in query.UpgradeOpen() )
{
door.ColorIndex = 1;
}
tr.Commit();
}
}
/// <summary>
/// This is a variation of the above example that uses DynamicExpression
/// to filter the initial set of ObjectIds and the opened BlockReferences.
/// </summary>
[CommandMethod( "DXTEST3" )]
public static void Method3()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
using( Transaction tr = doc.TransactionManager.StartTransaction() )
{
var ids = doc.Database.GetModelSpaceIds().AsQueryable();
var blockrefIds = ids.Where( "ObjectClass.DxfName == @0", "INSERT" );
var query = blockrefIds.GetObjects<BlockReference>().AsQueryable()
.Where( "Name == @0 && Layer.StartsWith(@1)", "DOOR", "LEVEL" );
foreach( BlockReference door in query.UpgradeOpen() )
{
door.ColorIndex = 1;
}
tr.Commit();
}
}
}
}