Upload
julian-perry
View
222
Download
1
Tags:
Embed Size (px)
Citation preview
The Weakest LINQ: Querying the AutoCAD® Database
James E. JohnsonSoftware Developer CaptiveAire Systems Inc.
Topics this session will be cover...
LINQ syntax and basics Querying a drawing database using LINQ. Queries on entities and properties. Enumerable generic collections Anonymous methods Anonymous types. Predicate delegates LINQ Lambda expressions. Creating Extension Methods
Questions...
Using LINQ ?
Using Generic List<T> ?
Use Anonymous methods ?
Use Anonymous type “var” ?
Using delegates ?
Using Object Initializers ?
What is LINQ ("Language Integrated Query")?
LINQ is a .NET programming model that adds querying capabilities to .NET programming languages.
“Language Integrated Query” designates that these query capabilities are accessible within the programming language(e.g., C#, Visual Basic).
LINQ is available with .NET framework version 3.0 and newer.
LINQ defines a standard set of query operators that can be used to query objects and filter datasources.
LINQ...
C# VB.NET OTHER...
.NET LINQ (Language Integrated Query)
Standard Query
Operators
LINQ To SQL
PROVIDER
LINQ To XML
PROVIDER
.NET Languages
ObjectsRelational Databases XML
Querying
Drawing databas
e objects
LINQ Namespace in System.Core
LINQ basics...var layernames =
from oid in lt.Cast<ObjectId>() select ((LayerTableRecord) tr,GetObject(oid, OpenMode.ForRead, false)).Name;
var layernames = lt.Cast<ObjectId>() .Select<ObjectId, string> (oid =>
{ return ((LayerTableRecord)tr.GetObject(oid, OpenMode.ForRead, false)).Name; }
Query Expressions
Extension Methods
Local Variable Type Inference
Lambda Expressions
Statement Expression
var dbObjCollection = from oid in btr.Cast<ObjectId>() select new {
DBObj = (DBObject)tr.GetObject(oid, OpenMode.ForRead, false)};
Anonymous types
Object Initializers
Linq basics VB
Dim layernames As List(Of String) = lt.Cast(Of ObjectId).Select(Of LayerTableRecord) _ (Function(oid) DirectCast(tr.GetObject(oid, OpenMode.ForRead, _ False),LayerTableRecord)) _ .Where(Function(ltr) (ltr.IsFrozen)).Select(Function(ltr) (ltr.Name)).ToList()
Dim layernames As List(Of String) = (From oid In lt.Cast(Of ObjectId)() _ Select DirectCast(tr.GetObject(oid, OpenMode.ForRead, False), _ LayerTableRecord).Name) .ToList()
Dim dbObjCollection = From oid In btr.Cast(Of ObjectId)() _ Select New With {.DBObj = _ DirectCast(tr.GetObject(oid, OpenMode.ForRead, False), DBObject)}
Query Expressions
Local Variable Type Inference
Lambda Expressions
Anonymous types
Object Initializers
Extension Methods
LINQ basics... Query expressions from... where...select
Extension methods .select .orderBy .where .Any
Local variable type inference var dbTxt = ............
Dim dbTxt = ............
Lambda Expressions Func<Point3d, bool> pFiltX = p => (p.X > 4.0);
Function(p) (p.X > 4.0)
Anonymous types new { ............ }
New With { ............ }
Object Initializers new pointObj { X = 1, Y = 2}
New pointObj With { .X = 1, .Y = 2}
Reasons to use LINQ...
Strongly typed arguments and results.
Standard query syntax.
Fully extensible.
Intellesence
Easy to read and maintain.
Visual Studio project requirements
To get started with LINQ, your project needs to have its target framework set to .NET Framework 3.0 or newer.
Add using statements in the class…using System.Collections;using System.Collections.Generic;using System.Linq;using System.Linq.Expressions;
Querying the AutoCAD® Database
Customizing for AutoCAD® applications often requires adding, modifying and removing drawing entities using selection sets or other ways of collecting drawing objects.
Every AutoCAD® Drawing has a database that contains tables (e.g. blocktable, layertable etc) and Dictionaries that can be retrieved as arrays or as a generic List<T> which are both enumerable.
Managing collections is typically done using common looping functions (e.g. For, ForEach etc) to step through collections of entities.
Enumerable collections can be queried using LINQ.
Querying the AutoCAD® Database Examples using foreach to step through the drawings layertable and using a
LINQ query with an anonymous method statement……
VIEW CODE
Query Syntax
LINQ query expressions are written in a declarative query syntax that is similar to SQL statements and was introduced in C# 3.0.
LINQ Comprehension Query Syntax (or just Query Syntax)
LINQ Method Query Syntax (or DOT Syntax)
var layernames = from oid in lt.Cast<ObjectId>() select ((LayerTableRecord) tr,GetObject(oid, OpenMode.ForRead, false)).Name;
var layernames = lt.Cast<ObjectId>() .Select<ObjectId, string> (oid =>
{ return ((LayerTableRecord)tr.GetObject(oid, OpenMode.ForRead, false)).Name; }
What are Generics?
The term "generic" is a common term for describing something that is not a brand name. Medicine prescriptions may be filled using a “generic” version.
In programming “generic” can refer to a class that is not forced to any specific Type.
Func<T, T> List<T> Dictionary<T>Queue<T>IEnumerable<T>
List<string> layernames = new List<string>;
Generic classes are created to allow definition of collections without specifying the actual types used.
Arrays, Generic List<T> and IEnumerable
LINQ extension methods for standard query operators add query functionality to the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable<T> types.
The Array class provides methods for creating, manipulating, searching and sorting arrays, it implements the IEnumerable interface.
ArrayList layernames = new ArrayList();
The List<T> class represents a strongly typed list of objects that can be accessed by index and is the generic equivalent of the ArrayList class.
List<T> vs. ArrayList()...
UnBoxing the opposite of boxing. A reference is retrieved to the value type (data fields) contained within an object. The common language runtime first ensures that the reference type variable is not null and that it refers to an object that is a boxed value of the desired value type. If the types match, then a pointer to the value type contained inside the object is returned.
Boxing is the process of converting a value type to a reference type. Memory is allocated from the heap. The amount of memory allocated is the size required by the value type plus any additional overhead. The values are copied to the newly allocated heap memory. The address of the object is returned as the reference type.
A Generic List<T> is strongly typed so does not require BOXING and UNBOXINGwhen enumerating the items.
IEnumerable<T> and IQueryable<T> interfaces The generic interface IEnumerable<T> is defined for generic
types to iterate the elements of a collection by exposing the enumerator, which supports a simple iteration of a specific type.
Any data type that implements the IEnumerable<T> interface can directly serve as a source for query expressions with LINQ.
The IQueryable<T> interface is primarily used for query providers and inherits the IEnumerable<T> interface so that a query can be enumerated.
Standard Query operators
Standard Query Operators are the base of LINQ. Extension methods that implement the IEnumerable<T> interface Operator Type Operator Name
Aggregation Aggregate, Average, Count, LongCount, Max, Min, Sum
Conversion Cast, ConvertAll, OfType, ToArray, ToDictionary, ToList, ToLookup, ToSequence
ElementDefaultIfEmpty, ElementAt, ElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault
Equality EqualAll
Generation Empty, Range, Repeat
Grouping GroupBy
Joining GroupJoin, Join
Ordering OrderBy, ThenBy, OrderByDescending, ThenByDescending, Reverse
Partitioning Skip, SkipWhile, Take, TakeWhile
Quantifiers All, Any, Contains
Restriction Where
Selection Select, SelectMany
Set Concat, Distinct, Except, Intersect, Union
LINQ Query Syntax Keywords
Clause Description
from Query syntax expressions must start with a ‘from’ clause. Specifies the data source and a range variable that represents each element in the source.
where Used in an expression to specify which elements will be returned. Applies a predicate to each element in the source specified in the ‘from’ clause range variable.
select Specifies the type of values in the returned sequence when the query is executed.
group Returns a sequence that contains none or many items that match a specified key value.
into Used to create an identifier that can serve as a reference to the results of a join, group or select clause.
orderby Sorts query results in ascending or descending order based on the default comparer for the element type.
join Joins two data sources based on an equality comparison between two specified matching criteria.
let Introduces a range variable to store sub-expression results in a query expression.
in Contextual keyword in a join clause.
on Contextual keyword in a join clause.
equals Contextual keyword in a join clause.
by Contextual keyword in a group clause.
ascending Contextual keyword in an orderby clause.
descending Contextual keyword in an orderby clause.
Anonymous Types
LINQ is data driven programming which uses static structures instead of objects, anonymous types are used to allow new structures to be defined “inline”.
Example creates an “inline” anonymous type with a property named “DBObj” returning DBObjects found to dbObjCollection…
var dbObjCollection = from oid in btr.Cast<ObjectId>() select new {
DBObj = (DBObject)tr.GetObject(oid, OpenMode.ForRead, false) };
var dbTxt = from obj in dbObjCollection where (obj.DBObj.GetType() == typeof(DBText))
select obj.DBObj;
List<DBText> dwgDBText = dbTxt.Cast<DBText>().ToList()
Anonymous Type “Var”
The “var” keyword may remind you of less strongly typed languages like VB6. Most languages now use strongly typed objects.
The “var” keyword tells the compiler to infer the type of the variable from the static type of the expression used to initialize the variable.
LINQ determines the type at compile time and VB6 determined the type at runtime.
var dbTxt = from obj in dbObjCollection where (obj.DBObj.GetType() == typeof(DBText))
select obj.DBObj;
Use “Var” or specify Type You can stick to Strongly typing:
The result type of “DBText” is specified so the result type of the query must be declared, this is a strongly type a query result.
Instead of:
The “var” local type inference is used to let the compiler determine the type.
IEnumerable<DBText> dbTxt = from obj in dbObjCollection
where (obj.DBObj.GetType() == typeof(DBText)) select (DBText)obj.DBObj;
var dbTxt = from obj in dbObjCollection where (obj.DBObj.GetType() == typeof(DBText) select (DBText)obj.DBObj;
Delegates and Anonymous methods
Delegates are used to pass methods as arguments to other methods.
A class or a method can be created for using a delegate.
Anonymous methods were introduced in C# 2.0 which allows defining anonymous (nameless) method to be called by a delegate.
delegate void sampDelegate(string s);static public void sampleDelegate(){ Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor; //anonymous delegate sampDelegate annonyDel = delegate(string s) { ed.WriteMessage(s); }; annonyDel("I am anonymous");
//lambda delegate sampDelegate lambdaDel = (x) => { ed.WriteMessage(x); }; lambdaDel("I am a Lambda expression");}
Anonymous method example:
VIEW CODE
Generic Delegate System.Func
The generic delegate System.Func can be used to define a delegate when needed without defining an explicit delegate type declaration.
The TArg0, TArg1, TArg2, and TArg3 parameters are argument types and the TResult parameter represents the result type.
Func<Point3d, bool> pointFilterX = p => (p.X > 4.0);
Func<TResult>();
Func<TArg0, TResult>(TArg0 arg0);
Func<TArg0, TArg1, TResult>(TArg0 arg0, TArg1 arg1);
Func<TArg0, TArg1, TArg2, TResult>(TArg0 arg0, TArg1 arg1, TArg2 arg2);
Func<TArg0, TArg1, TArg2, TArg3, TResult> (TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);
Generic Delegate System.Func Example:
VIEW CODE
Generic Delegate System.Action System.Action is a set of predefined delegates that encapsulate
up to 4 arguments with no return values…
static public void actionSamp(){ Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
Point3d newpoint = new Point3d(4.0, 4.0, 0.0); Action<Point3d, string> pointAction = (p, s) => ed.WriteMessage(s + p.X.ToString()); //execute action pointAction(newpoint, "value of X:");
}
Predicate Delegates
A predicate is a function that returns true or false and can be used to filter the results of a query.
A predicate defines a set of criteria, and determines if a specified object meets those criteria.
Predicates take advantage of the generic features introduced in the .NET Framework 2.0.
Some of the methods that use an instance of the System.Predicate delegate to perform their tasks are: Exists, Find, FindAll, FindIndex, FindLastIndex, FindLast, RemoveAll and TrueForAll.
The best way of thinking about predicates is to think about them as filters, that will evaluate to True or False.
Predicates Examples: Example searches for layers containing the string “Layer” in the delegate
used as the predicate:
VIEW CODE
MinX = objExtents.Min<Extents3d>(ext => ext.MinPoint.X);MinY = objExtents.Min<Extents3d>(ext => ext.MinPoint.Y);MinZ = objExtents.Min<Extents3d>(ext => ext.MinPoint.Z);
Lambda Expressions
Query operators provide functionality to perform filtering, projection, or extraction and build on the concept of lambda expressions.
Lambda expressions are an evolution of anonymous methods introduced in .NET 2.0.
The ‘=>’ symbol is used in lambda statements stating that the defined object “goes into” the expression…
Func<Point3d, bool> pointFilterX = p => (p.X > 4.0);Func<Point3d, bool> pointFilterY = p => (p.Y > 4.0);
Lambda Expressions
Nested lambda example (‘ent’ of type Entity can be used in second inline lambda statement):
Lambda expressions used in delegates:
Expressions or statement blocks can be contained in Lambda expressions.
.Where<Entity>(ent => layernames.Any<string>(lay => lay == ent.Layer))
string[] parts = { "Bolt", "Nut", "Flange","Pipe", "Bar", "Cylinder"};Func<string, bool> filt = s => s.Length > 5;Func<string, string> val = s => s;Func<string, string> sel = s => s.ToUpper();IEnumerable<string> query = parts.Where(filt).OrderBy(val).Select(sel);
a => 3.1416 * a // Expressiona => {return 3.1416 * a;} // Statement
Lambda Expressions
Delegates and lambda expressions are equivalent.
Func<int> funcDelegate = delegate(int a) { return a * 3.1416; };
Func<int> lambda = a => a * 3.1416;
Lambda Expressions
VIEW CODE
Expression Trees
LINQ provides a simple syntax for translating code into a data structure called an expression tree.
The System.Linq.Expressions namespace defines a generic type, Expression<T>, where T is the type of the delegate that defines the expression's signature.
Expression trees are used for creating LINQ Providers to extend querying to multiple data structures.
Expression Trees
Expression trees are created in-memory out of lambda expressions and then allow manipulation or inspection of the expression as data.
VIEW CODE
Object Initializers
A feature added in C# 3.0 is the syntax for object initializers.
Allow initializing an object by creating the object instance.
Assign values to one or more properties in a single sentence.
Initialize a collection with a set of values to add in a single expression similar to how it is done with arrays.
var dbObjCollection = from oid in btr.Cast<ObjectId>() select new {
DBObj = (DBObject)tr.GetObject(oid, OpenMode.ForRead, false)};
Object Initializers
Anonymous types can be populated using object initializers.
var dwgInfo = new { Description = "New Drawing", DrawnBY = "James", Date = "12/2/2009", DwgNumber = "123456", RevisionNo = "A" };
Object Initializers This example illustrates using object initializers to set the values
to instances of the class and then adding those objects to a generic list.
VIEW CODE
Extension Methods
Allow the creation of methods on an existing “Type” creating the illusion of new methods.
With extension methods developers can augment the “Type” with new methods to provide their own methods.
Extension methods are defined in static classes as static methods.
In C#, extension methods are indicated by the “this” modifier which must be applied to the first parameter of the extension method.
Add methods to a class compiled outside of the current assembly that can not be changed.
Extension Methods Extension methods are resolved at compile-time.
Namespaces imported with C#’s using statement or VB’s Import statement are defined by static classes and brought into scope.
LINQ standard query operators are extension methods in the System.Linq namespace, these extension methods extend IEnumerable<T> and IQueryable<T>.
Most of the standard query operators extend from the IEnumerable<T> interface, these types will get the standard query operators by adding the using statement ‘using System.Linq;’ in C#.
Extension methods show up in Intellesense
Extension Methods The type of the first parameter of an extension method indicates
what type the extension applies to.
VIEW CODE
Deferred Query Evaluation LINQ standard query operators return elements when
enumerated not when declared.
Operators do no work UNTIL the query requests an element then suspends until the next element is requested.
Deferred evaluation allows queries to be kept as IEnumerable<T> based values that can be evaluated multiple times, each time yielding potentially different results.
A query can be enumerated immediately, using ToList() or ToArray() which both will enumerate the entire sequence returning a result.
Deferred Query Evaluation Example uses one of the previous examples to get text entities
then modifies the “Last” text entity found and runs the query again…
VIEW CODE
LINQ Providers
LINQ works between the programming language and the data source that queries are applied against.
A provider works between the LINQ engine and the data source to extend the query functionality on the data source.
Thanks for Attending…