System.Runtime Schema: Type Details
Types are cornerstone of application programming. A .NET developer works with the CLR type system by programming the managed types. Some of the examples of CLR managed types are: Class, Structure, Enumeration, Delegate and Interface. A namespace is a user-defined scope in which managed types are defined. Most of the CLR built-in types are defined within the System namespace, such as System.Object, System.Int32, and System.String.
The following ER diagram shows the relationship between different entities related to the definition of a CLR Type.
Type Definitions
The TypeDefinitions entity is used to represent details of a type that belongs to a particular assembly. It “extends” from Types entity, just like TypeReferences does. It provides metadata about a type definition including access modifier (public, private, etc.), kind (class, interface, etc.), base type, containing type, etc. Let's take an example of a type definition for class Person: the class can be abstract and can have properties, methods and derive from other classes. A reference to the class Person defined in some external assembly, will only have its metadata stored in TypeReferences entity.
The following table shows some of the queries you can perform over these set of entities.
Note: You can scope these queries to an individual assembly or repository folder by doing joins over Types, Modules, Assemblies and Folders.
Description |
T-SQL Query |
Show all distinct namespaces scoped by folder ‘/Build/1.0.2.4’ |
SELECT distinct TD.Namespace, N.Name as NamespaceName, MO.Name as ModuleName FROM [Repository].System_Runtime.TypeDefinitions AS TD LEFT JOIN [Repository].System_Runtime.Types AS T ON TD.Id = T.Id LEFT JOIN [Repository].System_Runtime.Modules AS MO ON T.Module = MO.Id LEFT JOIN [Repository].System_Runtime.Namespaces AS N ON TD.Namespace = N.Id WHERE MO.Folder = [Repository].[Repository.Item].PathsFolder('/Build/1.0.2.4') |
Show all classes in the repository |
SELECT T.*, TD.* FROM [Repository].System_Runtime.TypeDefinitions AS TD LEFT JOIN [Repository].System_Runtime.Types AS T ON TD.Id = T.Id WHERE Kind = 1 |
Show all interfaces in the repository |
SELECT T.*, TD.* FROM [Repository].System_Runtime.TypeDefinitions AS TD LEFT JOIN [Repository].System_Runtime.Types AS T ON TD.Id = T.Id WHERE Kind = 5 |
Show all enumeration types in the repository |
SELECT T.*, TD.* FROM [Repository].System_Runtime.TypeDefinitions AS TD LEFT JOIN [Repository].System_Runtime.Types AS T ON TD.Id = T.Id WHERE Kind = 3 |
Show all abstract types (classes and interfaces) in the repository |
SELECT T.*, TD.* FROM [Repository].System_Runtime.TypeDefinitions AS TD LEFT JOIN [Repository].System_Runtime.Types AS T ON TD.Id = T.Id WHERE TD.IsAbstract = 1 |
Show all interfaces that have no methods |
SELECT * FROM [Repository].System_Runtime.Types AS T LEFT JOIN [Repository].System_Runtime.TypeDefinitions AS TD ON TD.Id = T.Id WHERE TD.Kind = 5 AND TD.Id NOT IN ( SELECT distinct T.Id FROM [Repository].System_Runtime.MethodDefinitions AS MD LEFT JOIN [Repository].System_Runtime.Methods AS M ON MD.Id = M.Id LEFT JOIN [Repository].System_Runtime.Types AS T ON T.Id = M.DeclaringType LEFT JOIN [Repository].System_Runtime.TypeDefinitions AS TD ON T.Id = TD.Id WHERE TD.Kind = 5 ) |
Show the types and count of methods in each type |
SELECT T.Id, T.QualifiedName, COUNT(M.Id) AS MethodCount FROM [Repository].System_Runtime.MethodDefinitions AS MD LEFT JOIN [Repository].System_Runtime.Methods AS M ON MD.Id = M.Id LEFT JOIN [Repository].System_Runtime.Types AS T ON T.Id = M.DeclaringType GROUP BY T.Id, T.QualifiedName |
Show the interfaces and count of methods in each interface |
SELECT T.Id, T.QualifiedName, COUNT(M.Id) AS MethodCount FROM [Repository].System_Runtime.MethodDefinitions AS MD LEFT JOIN [Repository].System_Runtime.Methods AS M ON MD.Id = M.Id LEFT JOIN [Repository].System_Runtime.Types AS T ON T.Id = M.DeclaringType LEFT JOIN [Repository].System_Runtime.TypeDefinitions AS TD ON T.Id = TD.Id WHERE TD.Kind = 5 GROUP BY T.Id, T.QualifiedName |
Show all types that contain other types |
SELECT T.Name AS Type, TD.Kind, T2.Name AS ContainingType FROM [Repository].System_Runtime.TypeDefinitions AS TD LEFT JOIN [Repository].System_Runtime.Types AS T ON T.Id = TD.Id LEFT JOIN [Repository].System_Runtime.Types AS T2 ON T2.Id = TD.ContainingType WHERE TD.ContainingType IS NOT NULL |
Show all types that have a base type |
SELECT T.Name AS Type, TD.Kind, TD.IsAbstract, T2.Name AS BaseType FROM [Repository].System_Runtime.TypeDefinitions AS TD LEFT JOIN [Repository].System_Runtime.Types AS T ON T.Id = TD.Id LEFT JOIN [Repository].System_Runtime.Types AS T2 ON T2.Id = TD.BaseType WHERE TD.BaseType IS NOT NULL |
Show all methods for interface “IFoo” in folder “/Build/2.0.0.0” |
SELECT T.Name, M.Name, * FROM [Repository].[System_Runtime].[Types] as T LEFT JOIN [Repository].[System_Runtime].[Methods] as M ON M.DeclaringType = T.Id WHERE T.Name = 'IFoo' And T.Folder = [Repository].[Repository.Item].PathsFolder('/Build/2.0.0.0') |
Implemented Interfaces
The ImplementedInterfaces entity keeps record of types that implement a particular interface.
I am going to use “M” query language and define a SQL Server table-valued function to demonstrate the examples in this section. Once the table-valued functions are available in the database, you can call these functions in SQL Server Management Studio (SSMS) similar to queries over tables and views.
Description |
T-SQL Query |
Show all assemblies in repository that provide interface by name “IFoo” |
SELECT * FROM [Repository].[System.Runtime.Analysis].[GetAssembliesThatProvideInterfaceByName]('IFoo') “M” Query Implementation GetAssembliesThatProvideInterfaceByName(interfaceName : Text) { (from interface in Types where interface.Name == interfaceName from interfaceSignature in TypeSignatures where interfaceSignature.TypeDefinition == interface from ii in ImplementedInterfaces where ii.Interface == interfaceSignature from class in TypeDefinitions where ii.Type == class from classType in Types where class.Id == classType from _module in Modules where classType.Module == _module from assembly in Assemblies where _module.Assembly == assembly from folder in FoldersTable where assembly.Folder == folder select { AssemblyId => assembly.Id, AssemblyName => assembly.Name, FolderName => folder.Name }).Distinct } |
Show all assemblies in repository that require interface by name “IFoo” |
SELECT * FROM [Repository].[System.Runtime.Analysis].[GetAssembliesThatRequireInterfaceByName]('IFoo') “M” Query Implementation GetAssembliesThatRequireInterfaceByName(interfaceName : Text) { (from interface in Types where interface.Name == interfaceName from iMethod in Methods where iMethod.DeclaringType == interface from calledMethod in CalledMethods where calledMethod.Callee == iMethod from classMethod in Methods where calledMethod.Caller == classMethod from classType in Types where classMethod.DeclaringType == classType from _module in Modules where classType.Module == _module from assembly in Assemblies where _module.Assembly == assembly from folder in FoldersTable where assembly.Folder == folder select { AssemblyId => assembly.Id, AssemblyName => assembly.Name, FolderName => folder.Name }).Distinct } |
“M” alternative to writing Queries
Here are the steps involved in making these functions available in the database.
Step 1: Author “M” file.
Provide a module name and then add the “M” functions within this module. Import any modules as necessary. See attached file.
module System.Runtime.Analysis
{
import System_Runtime;
import Repository.Item;
function1(…) ...
function2(…) ...
}
Step 2: Compile the “M” file to produce a database compliant package
Use the “M” compiler to compile the “M” source into a SQL package. (It will be nice if “M” compiler could produce a DAC package.)
m.exe ClrAnalysisQueries.m /r:System.Runtime.mx,repository.mx /o:CLRAnalysisQueries.mx
Microsoft (R) Codename "M" Compiler version 1.0.1949.0
Copyright (c) Microsoft Corporation. All rights reserved.
Step 3: Load the data package into a database
Install the data package into the target database.
mx.exe install ClrAnalysisQueries.mx /d:Repository
Microsoft (R) Codename "M" Command-line Utility version 1.0.1949.0
Copyright (c) Microsoft Corporation. All rights reserved.
(0,0): message : Installing: CLRAnalysisQueries;Version=1.0;Locale=neutral...
(0,0): message : Installed: CLRAnalysisQueries;Version=1.0;Locale=neutral
Summary
Use the TypeDefinitions and related entities to understand details about a particular class, interface or enumeration implementation in an assembly or folder. Besides using the “M” language for defining the schema (Tables and Views), you can also use it to define utility functions over one or more SSMoS schemas.