6

I use LinqPad with the MySQL IQ driver to query data from a Magento database. I not only use this for reporting on the database but for doing updates. I can use the standard SubmitChanges() method to update data, but that often ends up with unbearably slow updates that can literally take hours - one of my tables has 35,707 records that I recreate on a regular basis.

So instead I generate SQL statements in my LinqPad queries and then execute them in a separate tab after selecting "SQL" in the language drop-down.

For example, my output might be something like this:

UPDATE catalog_category_product SET position = 6040 WHERE (category_id = 156 AND product_id = 12648);
UPDATE catalog_product_entity_media_gallery_value SET label = 'Sandy Beach' WHERE ((store_id = 0) AND (value_id = 8791));
-- Done.

I have recently found that LinqPad has a nice class called Hyperlinq that allows me to write code like this:

(new Hyperlinq(QueryLanguage.SQL, myGeneratedSqlText, "Run Query")).Dump();

The result is that a hyperlinq is put in the output window that will run the query (in my example the contents of myGeneratedSqlText) in a new tab and execute the query.

This is very convenient.

However, I now want to be able to save a log of queries that are executed. There doesn't seem to be (an easy) built-in way to manually execute a "generated" query in LinqPad. I can certainly use Util.Run to execute an existing saved query, in fact I do something like this:

Util
    .OnDemand("Run Query", () =>
    {
        var fn = createOutputQueryFileName(); // Timestamped query name
        System.IO.File.WriteAllText(fn, myGeneratedSqlText);
        var run = Util.Run(fn, QueryResultFormat.Text);
        var result = run.AsString();
        return result.StartsWith("[]") ? "Success" : result;
    })
    .Dump();

The only drama with this is that I have to prefix the text in myGeneratedSqlText with the following:

var preamble = @"<Query Kind=""SQL"">
  <Connection>
    <ID>ec026b74-8d58-4214-b603-6d3145e03d7e</ID>
    <Driver Assembly=""IQDriver"" PublicKeyToken=""5b59726538a49684"">IQDriver.IQDriver</Driver>
    <Provider>Devart.Data.MySql</Provider>
    <CustomCxString>[DELETED]</CustomCxString>
    <Server>127.0.0.1</Server>
    <Database>prod_1_8</Database>
    <Password>[DELETED]</Password>
    <UserName>[DELETED]</UserName>
    <NoPluralization>true</NoPluralization>
    <NoCapitalization>true</NoCapitalization>
    <DisplayName>Production Tunnel</DisplayName>
    <EncryptCustomCxString>true</EncryptCustomCxString>
    <Persist>true</Persist>
    <DriverData>
      <StripUnderscores>false</StripUnderscores>
      <QuietenAllCaps>false</QuietenAllCaps>
      <Port>6606</Port>
    </DriverData>
  </Connection>
</Query>
";

I would really like to avoid all of this preamble stuff and include a line like this in my Util.OnDemand(...) code:

var run = Util.Run(QueryLanguage.SQL, myGeneratedSqlText, QueryResultFormat.Text);

(But this method doesn't exist.)

The key requirement here is to display a hyperlinq in the LinqPad output window that, if clicked, will save the query to disk as a log and also execute the query.

Can anyone suggest a clean way for me to do it?

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • 1
    A minor note about the "preamble": you don't need to include all the elements under . The element alone is sufficient if the connection is defined on that machine. – Joe Albahari Dec 07 '14 at 08:44
  • 1
    Another way to get the preamble is this: var reader = XmlReader.Create(Util.CurrentQueryPath, new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment }); reader.Read(); string preamble = XElement.ReadFrom (reader).ToString(); – Joe Albahari Dec 07 '14 at 08:55

1 Answers1

2

I hope I've understood you correctly. When you've selected a connection in the top bar, your UserQuery becomes a datacontext. For this reason, you can use ExecuteQuery and ExecuteCommand on this within an action based Hyperlinq.

new Hyperlinq(() => {
                "do log work here".Dump();
                this.ExecuteQuery<string>(generatedSelect).Dump("Results");
                this.ExecuteCommand(generatedCommand).Dump("Results");
             }, "Run Query").Dump();

Unfortunately this outputs to the current tab, but hopefully this will at least get you most of the way to done :)

Here's an image of it at work:

Example

As you're using MySQL, you can go via the connection property on this:

new Hyperlinq(() => {
            "do log work here".Dump();
            using (var command = this.Connection.CreateCommand())
            {
                // Usual command logic here
            }
         }, "Run Query").Dump();
Steve Lillis
  • 3,263
  • 5
  • 22
  • 41
  • Thanks for the answer, but I can't find the methods `ExecuteQuery` or `ExecuteCommand` under `this.`. Can you check if this code works for you? – Enigmativity Dec 05 '14 at 01:09
  • 1
    It does work for me, but only if I have selected a connection first(otherwise UserQuery does not derive from a Data Context) – Steve Lillis Dec 05 '14 at 07:07
  • Added an image of it at work. Noting that I have a Connection. In the image I have already clicked the Run Query link – Steve Lillis Dec 05 '14 at 08:51
  • Ah, it might then be because I'm using the IQ driver to access MySQL. I don't have any MSSQL servers to test. – Enigmativity Dec 05 '14 at 11:57
  • Updated to represent MySQL case scenario – Steve Lillis Dec 05 '14 at 13:35
  • This looks like a great solution, but it's just not working for me. It simply doesn't compile. What version of LINQPad are you using? – Enigmativity Dec 06 '14 at 02:35
  • I'm on the same version. I'm a little stumped. Do you have any extra assemblies loaded? – Enigmativity Dec 06 '14 at 13:05
  • Unfortunately not, fresh install, grabbed the IQ driver for MySQL using the dialog under Add Connection. Hooked it up to my MySQL DB that I installed fresh for testing. Selected the connection, wrote the above code and it worked. – Steve Lillis Dec 06 '14 at 13:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/66323/discussion-between-enigmativity-and-steve-lillis). – Enigmativity Dec 06 '14 at 13:34