Question

We have a piece of code where we try to match a pattern against the data in the database.

We use ServiceStack.OrmLite against our SQLite DB.

So for example, given the below records:

ColA    ColB
-----   ---------
ABC     ABC_Long
GHI     GHI_Long
GHIP    GHIP_Long

We use a predicate as:

var result = db.Select(x => x.ColA.StartsWith("GHI_")); 

Everything works fine until we have a search pattern that includes an SQL special character such as '%' or '_' so for example given the search pattern of "GHI_":

The expected row should be:

GHI     GHI_Long

However we get:

GHI     GHI_Long
GHIP    GHIP_Long

Which is due to ORMLite not escaping the special character and generating the below SQL:

SELECT * FROM myTable WHERE UPPER(colA) LIKE 'GHI_%' OR UPPER(colB) LIKE 'GHI_%';

Instead of the correctly escaped version which should be:

SELECT * FROM myTable WHERE UPPER(colA) LIKE 'GHI\_%' OR UPPER(colB) LIKE 'GHI\_%' ESCAPE '\';

Can you think of a way to address this issue?

Was it helpful?

Solution

I've just added implicit support for escaping wildcards in this commit which will now escape wildcards in the typed expressions that make use of LIKE, namely StartsWith, EndsWith and Contains, e.g:

using (var db = OpenDbConnection())
{
    db.DropAndCreateTable<Poco>();

    db.Insert(new Poco { Name = "a" });
    db.Insert(new Poco { Name = "ab" });
    db.Insert(new Poco { Name = "a_c" });
    db.Insert(new Poco { Name = "a_cd" });
    db.Insert(new Poco { Name = "abcd" });
    db.Insert(new Poco { Name = "a%" });
    db.Insert(new Poco { Name = "a%b" });
    db.Insert(new Poco { Name = "a%bc" });
    db.Insert(new Poco { Name = "a\\" });
    db.Insert(new Poco { Name = "a\\b" });
    db.Insert(new Poco { Name = "a\\bc" });

    Assert.That(db.Count<Poco>(q => q.Name == "a_"), Is.EqualTo(0));
    Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a_")), Is.EqualTo(2));
    Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a%")), Is.EqualTo(3));
    Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a_c")), Is.EqualTo(2));
    Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a\\")), Is.EqualTo(3));
    Assert.That(db.Count<Poco>(q => q.Name.StartsWith("a\\b")), Is.EqualTo(2));
}

This will be available in v4.0.19 which is now available on MyGet.

OTHER TIPS

OrmLite does not have this built in but it does allow you to easy provide the correct SQL when you need it. You can simply do something like this:

var notes = db.Select<NoteDto>(" upper(\"NoteText\") like 'GHI@_%' ESCAPE '@' ");

In this manner you only have to write the where clause and you still get the benifits of the DTO auto population.

I changed the escape character just for clarity and to demonstrate it can be anything in SQLite.

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