Question

Is it possible to generate SQL scripts using OrmLite without executing it against a database? I would like to load a list of DTOs from a live SqlServer database and output a script to DELETE and INSERT each record.

The provided mini profiler supports logging, but looks like it needs to wrap a real database connection.

Was it helpful?

Solution

This is trivial now that OrmLite extension methods are now mockable by providing your own OrmLiteResultsFilter.

E.g. this ResultsFilter below records every sql statement executed and inherts the behavior from OrmLiteResultsFilter to return empty results:

public class CaptureSqlFilter : OrmLiteResultsFilter
{
    public CaptureSqlFilter()
    {
        SqlCommandFilter = CaptureSqlCommand;
        SqlCommandHistory = new List<SqlCommandDetails>();
    }

    private void CaptureSqlCommand(IDbCommand command)
    {
        SqlCommandHistory.Add(new SqlCommandDetails(command));
    }

    public List<SqlCommandDetails> SqlCommandHistory { get; set; }

    public List<string> SqlStatements
    {
        get { return SqlCommandHistory.Map(x => x.Sql); }
    }
}

You can wrap this in an using scope to capture each SQL statement without executing them, e.g:

using (var captured = new CaptureSqlFilter())
using (var db = OpenDbConnection())
{
    db.CreateTable<Person>();
    db.Select<Person>(x => x.Age > 40);
    db.Single<Person>(x => x.Age == 42);
    db.Count<Person>(x => x.Age < 50);
    db.Insert(new Person { Id = 7, FirstName = "Amy", LastName = "Winehouse" });
    db.Update(new Person { Id = 1, FirstName = "Jimi", LastName = "Hendrix" });
    db.Delete<Person>(new { FirstName = "Jimi", Age = 27 });
    db.SqlColumn<string>("SELECT LastName FROM Person WHERE Age < @age", 
        new { age = 50 });
    db.SqlList<Person>("exec sp_name @firstName, @age", 
        new { firstName = "aName", age = 1 });
    db.ExecuteNonQuery("UPDATE Person SET LastName={0} WHERE Id={1}"
        .SqlFmt("WaterHouse", 7));

    var sql = string.Join(";\n\n", captured.SqlStatements.ToArray());
    sql.Print();
}

Which prints out:

CREATE TABLE "Person" 
(
  "Id" INTEGER PRIMARY KEY, 
  "FirstName" VARCHAR(8000) NULL, 
  "LastName" VARCHAR(8000) NULL, 
  "Age" INTEGER NOT NULL 
); 
;

SELECT "Id", "FirstName", "LastName", "Age" 
FROM "Person"
WHERE ("Age" > 40);

SELECT "Id", "FirstName", "LastName", "Age" 
FROM "Person"
WHERE ("Age" = 42)
LIMIT 1;

SELECT COUNT(*) FROM "Person" WHERE ("Age" < 50);

INSERT INTO "Person" ("Id","FirstName","LastName","Age") VALUES (@Id,@FirstName,@LastName,@Age);

UPDATE "Person" SET "FirstName"=@FirstName, "LastName"=@LastName, "Age"=@Age WHERE "Id"=@Id;

DELETE FROM "Person" WHERE "FirstName"=@FirstName AND "Age"=@Age;

SELECT LastName FROM Person WHERE Age < @age;

exec sp_name @firstName, @age;

UPDATE Person SET LastName='WaterHouse' WHERE Id=7

More examples available in CaptureSqlFilterTests.cs


As CaptureSqlFilter is useful I've just added it to OrmLite in this commit which will be in the next v4.0.20 that's now available on MyGet.

OTHER TIPS

Using the DialectProvider directly seems to work well enough for what I need. ToInsertRowStatement takes a IDbCommand paramater, but does not use it so null works.

OrmLiteConfig.DialectProvider = SqlServerOrmLiteDialectProvider.Instance;
var dto = new PersonDTO { Id = Guid.NewGuid(), Name = "Carl" };
var deleteText = SqlServerOrmLiteDialectProvider.Instance.ToDeleteRowStatement(dto);
var insertText = SqlServerOrmLiteDialectProvider.Instance.ToInsertRowStatement((IDbCommand)null, dto);

Is there a better alternative?

I use this to capture the statement and keep running the sentense.

    public class CustomOrmLiteExecFilter : OrmLiteExecFilter
{
    public override T Exec<T>(IDbConnection dbConn, Func<IDbCommand, T> filter)
    {
        var holdProvider = OrmLiteConfig.DialectProvider;
        var dbCmd = CreateCommand(dbConn);
        try
        {
            var ret = filter(dbCmd);

            var pureSQL = holdProvider.MergeParamsIntoSql(dbCmd.CommandText, dbCmd.Parameters.OfType<IDbDataParameter>());
            //log or save the SQL Statement


            return ret;
        }
        finally
        {
            if (OrmLiteConfig.DialectProvider != holdProvider)
                OrmLiteConfig.DialectProvider = holdProvider;
        }
    }
}

and the usage:

 OrmLiteConfig.ExecFilter = new CustomOrmLiteExecFilter();

hope this can help you!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top