LinqPad - Helmut-Ortmann/EnterpriseArchitect_hoTools GitHub Wiki

LINQPad

If you want to analyze your EA model with SQL, you should consider using LINQPad. Write the query once for all your database types. Use the combination of SQL like syntax, modern .net languages like C#, VB and the compiler to find your typos.

The main benefits are:

  • Test your code and or query (SQL,XML,) interactive
  • Combine SQL like query language with the power of C#, VB, or F#
  • LINQ to have a common foundation for query of SQL, XML, Lists,
  • Database independent
  • IntelliSense, AutoComplete
  • Let the compiler find your typos
  • Debug and powerful outputs
  • Run query per batch or command
  • Tight integration in hoTools
    • hoTools uses the fitting LINQPad connection

LINQPad Connections

Integration hoTools

  • hoTools: Class LINQPad to encapsulate running LINQPad from your AddIn
  • AddInSimple: Example to run a LINQPad query from your AddIn
  • AddInSimple: Example SQL Query to get the requirent types of the EAExample.eap
  • AddInSimple: Example XML Query to get your EA Searches from XML
  • AddInSimple: XML Query to output the availabel Database connections

Overview LINQPad

The off-the-shelf interactive query and debugging tool:

  • EA query
  • Analyze without SQL limitations
  • Verify complex rules
  • Make metrics for your management
  • LINQPad abilities:
    • Interactive, let you help by
      • Compiler
      • Intellisense
      • Autocomplete
      • Debugging
    • LINQ to SQL (all the possible EA databases)
    • LINQ to Object
    • LINQ to XML
    • C#, F#, VB, SQL
    • Comprehensive Samples to see it working (learn LINQ, .net language like C#, VB, and more)
    • Tip: Load more free samples
    • etc.

Write it once and use it for all your EA databases - regardless of location or type. Just connect your query with the new Database.

Let's see an example using SPARX EAExample.eap: "Get the count of your requirements ordered by requirement type"

You can export the LINQPad results to Excel,

The LINQPad Query

// Requirement summary:
// - Type
// - Count
// - Percentage
// - Total count of requirements
var countReq = t_object.Where(e => e.Object_Type == "Requirement").Count();
var query =
                        (from c in t_object.AsEnumerable()
                         where c.Object_Type == "Requirement"
                         group c by c.Stereotype into g
                         orderby g.Key

                         select new
                         {
                             Type = (g.Key == null) ? "Simple" : $"<<{g.Key}>>",
                             Prozent = $"{ (float)g.Count() * 100 / countReq:00.00}%",
                             Count = g.Count(),
                             Total = countReq
                         });
query.Dump("EAExample JET, SqlServer, MySQL,..");

Use EA Context

You may use the EA Context. hoTools contains the function LinqPad.GetArg() to collect the context. AddInSimple shows it as running example..

IntelliSense, Autocomplete

Let the Compiler find your typos.

Just for fun: Try it with SQL.

Export to Excel

Export to Excel

Explore EA, Quick Query

You want to explore the EA database. See what tables and columns exists. Peek into some details with just a few clicks, without any SQL or LINQ to SQL knowledge.

Support by LinqToSql

hoTools:LinqToSql provides some useful helper functions.

Look inside

  • Write queries database independent
  • Combine queries like "query", "countReq",..
  • IntelliSence, Autocomplete, Compiler finds your typos
  • Arbitrary complex queries without the limitations of SQL and the different dialects
  • Use code (C#,VB, F#)
  • Same query independent of Database (all EA Databases supported)
  • LINQPad as an interactive query and debugging tool
  • Interactive develop, debug and see your valuable EA data on the spot
  • Use it in your Add-In (hoTools use LINQ to SQL, AddInSimple has to examples)

Steps with LINQPad

  • Create a new connection to your EA Database
  • Assign this connection to the query at hand
  • Enter the query and execute

LINQPad Connections

Just a few clicks

With the LINQPad templates you can quickly explore your repository.

Providers

In principle LINQ to SQL should be database independent. Different database providers may differ in e.g. name of the table (upper/lower cases). Therefore it's a good idea to try to use only one database provider to avoid such trouble.

My tests with EA, the databases Access, SQL Server and MySQL together with linq2db database providers work fine. Once, I used the Microsoft SQL driver and found that the table names startet with 'T_' instead of 't_' in case of linq2db drivers.

Connection

On the left side of LINQPad you have to add possible connections to your EA Databases you want to query on:

  • Add Connection
  • Only once: Install wanted driver
    • View more drivers
    • Choose your driver (I have chosen LINQ to DB Driver (open source)
    • DownLoad and install
  • Select driver
  • Enter connection string
  • Test

Note: The dialogs to parametrize a connection to a LINQ SQL Provider may differ. I've tested it with the linq2db driver. The linq2db driver e.g does't supports ODBC DSN names like "DSN=MyLovelyEA;".

Access

Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\Program Files (x86)\Sparx Systems\EA\EAExample.eap;

SQL Server

If you use only SQL Server you can also stick to the standard SQL Server driver from Microsoft.

Server=localhost\SQLEXPRESS;Database=EAExample;Trusted_Connection=True;

MySQL

Server=localhost;Database=eaexamplemysql;Uid=;Pwd=;

Example Command Line

void Main(string[] args)
{
	// process id
	int pid = 0;
	//
	// Use CMD symbol to check whether you're running in the GUI or from the command line, you can do this as follow
	// see: https://www.linqpad.net/lprun.aspx
#if CMD
        // run from command line via lprun
		if (args != null && args.Length > 0)
		{
			pid = Int32.Parse(args[0]);
			"_".Dump($"Run by Batch for process '{pid}'");
		}
#else
	// run in LINQPad GUI
	"_".Dump("Run by Dialog");
    // Get PID of EA
	Process processEa = Process.GetProcessesByName("EA").FirstOrDefault();
	if (processEa == null)
	{
		MessageBox.Show("","Can't determine running ea.exe instance!");
		return;
	}
	pid = processEa.Id.Dump("ProcessID");
	
#endif
	// run for found EA instance
	if (pid > 0)
	{
		Program p = new Program(pid);
		EA.Repository rep = p.Repository;
		rep.ConnectionString.Dump();
	}
}
//---------------------------------------------------------
// Get the Repository from the program ID
//---------------------------------------------------------
// This method is used to call this script from EA and access the Repository the call comes from
//
class Program
{
	private EA.Repository _repository = null;
	private int m_ProcessID = 0;
	// get the EA repository from the progid
	public Program(int pid)
	{
		m_ProcessID = pid;
		_repository = SparxSystems.Services.GetRepository(m_ProcessID);
		Trace("Running C# Console Application AppPattern .NET 4.0");
	}
	public EA.Repository Repository
	{
		get { return _repository;}
	}
	public void Trace(string msg)
	{
		if (_repository != null)
		{
			// Displays the message in the 'Script' tab of Enterprise Architect System Output Window
			_repository.WriteOutput("Script", msg, 0);
		}
		Console.WriteLine(msg);
	}
}

Example Access EA from LINQ

  • Access to database via Linq2db
  • Access via COM automatisation and connection string.
void Main()
{
	//----------------------------------------------------------------------------------------------
	// EaAutomationTemplate
	//----------------------------------------------------------------------------------------------
	//
	// Template to access EA with two strategies:
	// - LINQ to DB
	// - Native access to an EA Repository and access via COM and EA API (Interop.EA.dll)
	//   - opening *.eap file 
	string provider = "Access";
	// see: http://sparxsystems.com/enterprise_architect_user_guide/14.0/automation/repository3.html
	// Repository.OpenFile();
	// - path to *.eap(x) file, might be a shortcut to a DBMS/SQL Database
	// - connections string
	string repositoryPath = @"c:\Users\helmu\AppData\Roaming\Sparx Systems\EA\EAExample.eap";// Example database
	
	// Access to Repository
	EA.Repository rep = new EA.Repository();
	rep.OpenFile(repositoryPath);
	
	rep.ConnectionString.Dump();

	// Use LINQ to SQL
	// Use connection to SPARX Example Database
	string newConnectionString = ConstructConnectionString(Connection.ConnectionString, repositoryPath);
	using (TypedDataContext db = new TypedDataContext(provider, newConnectionString))
	{
		var rootPackages = from pkg in db.t_package
						   where pkg.Parent_ID == 0
						   orderby pkg.Name
						   select new { Name=pkg.Name, Package =pkg.Ea_guid};
		rootPackages.Dump();
	}

}

// Define other methods and classes here

// ------------------------------------------------------------------------------------------------------------------
// ConstructConnectionString
// ------------------------------------------------------------------------------------------------------------------
// Construct the connection string from datasource. This you can use to make a connection to the wanted connection by:
// - TypedDataContext db = new TypedDataContext("SQLite", newConnectionString);
// - TypedDataContext db = new TypedDataContext("Access", newConnectionString);
//
// Note: You uses the definitions of the used LINQPad connection
//
public string ConstructConnectionString(string oldConnection, string dataSource)
{
	Regex rx = new Regex(@"Data Source=[^;]*;");
	return rx.Replace(oldConnection, $"Data Source={dataSource};");

}

Trouble Shooting

Sometimes you get weird error messages. Something about SQL and LINQ to SQL can't...

Don't worry. LINQ to SQL tries to do a lot with SQL. Sometimes it easy doesn't add up. If you encounter such behavior: Force LINQ to work in memory.

// Process in memory to avoid SQL Access (e.g. string.Join(", ", isn't supported by Access SQL)
var tempRead = read.ToList().AsEnumerable();                 //.Dump("Read in memory");
var tempWrite = write.ToList().AsEnumerable();               //.Dump("Write in memory");;
var combined = tempRead.Concat(tempWrite).AsEnumerable();    //.Dump("Combined in memory");

It's simple. Just write your query to list by "write.ToList().AsEnumerable();". After that, you can work with the query, and you are sure that LINQ to SQL doesn't translate it into SQL.

Limitations

hoTools shows the first table named 't1' as grid in the EA Model Search window. hoTools doesn't support:

  • LINQPad Hierachical views
  • More than one table (hoTools shows only the first table/view)

Summary

LINQ to SQL is the solution for complex queries:

  • Interactive query tool LINQPad
  • In your Add-In to easily handle complex queries database independent
  • Database independent
  • IntelliSence and AutoComplete
  • Compiler verifies against EA Datbase (no typos)
  • Comprehensive debug features

References

⚠️ **GitHub.com Fallback** ⚠️