IDbConnection问题选择vs存在

时间:2014-07-01 12:16:25

标签: servicestack ormlite-servicestack

我在理解为什么我的Exists-query失败时遇到了一些困难。

这是SS 4.0.22 sqlite32中的一个问题,在预发行版4.0.23中它运行正常。向下滚动寻找解决方案

我有三个表,Token,ServiceInstance和一个映射表TokenServiceInstance:

[Alias("Token")]
public class Token
{
    [AutoIncrement]
    [Alias("Id")]
    [IgnoreDataMember]
    public int Id { get; set; }

    [References(typeof(Customer))]
    [Alias("CustomerId")]
    [IgnoreDataMember]
    public int CustomerId { get; set; }

    [Index]
    [Alias("TokenString")]
    public string TokenString { get; set; }

    [Alias("MasterTokenId")]
    [IgnoreDataMember]
    public int MasterTokenId { get; set; }

}

[Alias("ServiceInstance")]
public class ServiceInstance
{
    [AutoIncrement]
    [Alias("Id")]
    [IgnoreDataMember]
    public int Id { get; set; }

    public string ServiceName { get; set; }
}

[Alias("TokenServicesInstance")]
public class TokenServicesInstance
{
    [AutoIncrement]
    [Alias("Id")]
    public int Id { get; set; }

    [References(typeof(ServiceInstance))]
    [Alias("ServiceInstanceId")]
    public int ServiceInstanceId { get; set; }

    [References(typeof(Token))]
    [Alias("TokenId")]
    public int TokenId { get; set; }

    [Alias("Parameters")]
    public Dictionary<string, string> Parameters { get; set; }
}

我想做一个简单的查询,找出Token和ServiceInstance是否在Token中的某个TokenString和ServiceInstance中的某个ServiceName被映射。

我有这个SqlExpression:

SqlExpression<TokenServicesInstance> expr = db.From<TokenServicesInstance>();
        expr.Join<TokenServicesInstance, Entities.Token>()
            .Join<TokenServicesInstance, Entities.ServiceInstance>()
            .Where<Entities.Token>(token => token.TokenString == tokenString)
            .And<Entities.ServiceInstance>(si => si.ServiceName == serviceName);

如果我从调试器中的表达式中获取SQL:

SELECT "TokenServicesInstance"."Id", "TokenServicesInstance"."ServiceInstanceId", "TokenServicesInstance"."TokenId", "TokenServicesInstance"."Parameters"
FROM "TokenServicesInstance" 
INNER JOIN "Token"  ON ("Token"."Id" = "TokenServicesInstance"."TokenId") 
INNER JOIN "ServiceInstance"  ON ("ServiceInstance"."Id" = "TokenServicesInstance"."ServiceInstanceId")
WHERE ("Token"."TokenString" = 'B') AND ("ServiceInstance"."ServiceName" = 'A')

当我在Select中使用表达式时,它会产生行,如果有的话:

db.Select<TokenServicesInstance>(expr);

但我对这些行并不感兴趣,只要有任何行,所以我想使用Exists-method,但是这会抛出异常,使用完全相同的表达式。

db.Exists<TokenServicesInstance>(expr)

异常详情:

An exception of type 'System.Data.SQLite.SQLiteException' occurred in System.Data.SQLite.dll but was not handled in user code 
Additional information: SQL logic error or missing database
no such column: Token.TokenString

为什么选择Select的工作正常,Exists会引发异常?我的查询怎么样,看起来不错?

解决方案

作为对mythz'答案的跟进,我尝试使用Servicestack的预发布版本,4.0.23而不是版本4.0.22 - 现在代码可以正常运行。

进入生成的SQL显示版本0.22在计算行时忽略了查询的JOIN部分。

4.0.23:

DEBUG: SELECT COUNT(*) 
FROM "TokenServicesInstance" INNER JOIN "Token"  ON 
("Token"."Id" = "TokenServicesInstance"."TokenId") INNER JOIN "ServiceInstance"  ON 
("ServiceInstance"."Id" = "TokenServicesInstance"."ServiceInstanceId")
WHERE ("Token"."TokenString" = 'A') AND ("ServiceInstance"."ServiceName" = 'B')

4.0.22

DEBUG: SELECT COUNT(*) FROM "TokenServicesInstance" WHERE ("Token"."TokenString" = 'A')     AND ("ServiceInstance"."ServiceName" = 'B')

完整的测试代码:

using System.Collections.Generic;
using System.Data;
using System.Runtime.Serialization;
using NUnit.Framework;
using ServiceStack.DataAnnotations;
using ServiceStack.Logging;
using ServiceStack.OrmLite;
using ServiceStack.OrmLite.Sqlite;
using WAAPI.ApiToken.Data.OrmLite.Entities;

namespace Db.Tests
{
public class ExistsTests
{
    [Test]
    public void Can_Select_exists_on_JOIN_expression()
    {
        LogManager.LogFactory = new ConsoleLogFactory();
        var tokenString = "A";
        var serviceName = "B";

        var factory = SetupFactory();

        using(var db = factory.OpenDbConnection())
        { 
            db.DropAndCreateTable<Token>();
            db.DropAndCreateTable<ServiceInstance>();
            db.DropAndCreateTable<TokenServicesInstance>();

            var q = db.From<TokenServicesInstance>();
            q.Join<TokenServicesInstance, Token>()
                .Join<TokenServicesInstance, ServiceInstance>()
                .Where<Token>(token => token.TokenString == tokenString)
                .And<ServiceInstance>(si => si.ServiceName == serviceName);

            Assert.That(db.Select(q).Count, Is.EqualTo(0));
            Assert.That(db.Exists(q), Is.False);
        }
    }

    private OrmLiteConnectionFactory SetupFactory()
    {
        var factory = new OrmLiteConnectionFactory(":memory:", SqliteOrmLiteDialectProvider.Instance);
        using (var db = factory.OpenDbConnection())
        {
            CreateMissingTables(db);
        }
        return factory;
    }

    protected void CreateMissingTables(IDbConnection db)
    {
        db.CreateTable<Token>();
        db.CreateTable<ServiceInstance>();
        db.CreateTable<TokenServicesInstance>();
    }
}
}

namespace WAAPI.ApiToken.Data.OrmLite.Entities
{
[Alias("TokenServicesInstance")]
public class TokenServicesInstance
{
    [AutoIncrement]
    [Alias("Id")]
    public int Id { get; set; }

    [References(typeof(ServiceInstance))]
    [Alias("ServiceInstanceId")]
    public int ServiceInstanceId { get; set; }

    [References(typeof(Token))]
    [Alias("TokenId")]
    public int TokenId { get; set; }

    [Alias("Parameters")]
    public Dictionary<string, string> Parameters { get; set; }
}

[Alias("ServiceInstance")]
public class ServiceInstance
{
    public string ServiceName { get; set; }

    [AutoIncrement]
    [Alias("Id")]
    [IgnoreDataMember]
    public int Id { get; set; }
}

[Alias("Token")]
public class Token
{
    [AutoIncrement]
    [Alias("Id")]
    [IgnoreDataMember]
    public int Id { get; set; }

    [Index]
    public string TokenString { get; set; }

    [Alias("MasterTokenId")]
    [IgnoreDataMember]
    public int MasterTokenId { get; set; }

    [ServiceStack.DataAnnotations.Ignore]
    public bool IsMasterToken
    {
        get { return MasterTokenId == 0; }
    }
}
}

1 个答案:

答案 0 :(得分:0)

您的示例在此测试中没有问题:

[Test]
public void Can_Select_exists_on_JOIN_expression()
{
    LogManager.LogFactory = new ConsoleLogFactory();
    var tokenString = "A";
    var serviceName = "B";

    db.DropAndCreateTable<Token>();
    db.DropAndCreateTable<ServiceInstance>();
    db.DropAndCreateTable<TokenServicesInstance>();

    var q = db.From<TokenServicesInstance>();
    q.Join<TokenServicesInstance, Token>()
        .Join<TokenServicesInstance, ServiceInstance>()
        .Where<Token>(token => token.TokenString == tokenString)
        .And<ServiceInstance>(si => si.ServiceName == serviceName);

    Assert.That(db.Select(q).Count, Is.EqualTo(0));
    Assert.That(db.Exists(q), Is.False);
}

您可以使用确保已更新到最新版本的ServiceStack。如果问题仍然存在,您可以尝试latest version of ServiceStack on MyGet,以确保我们能够运行相同的版本。

如果仍然存在问题,您可以使用生成的SQL更新您的问题,您可以通过以下方式获取OrmLite:

LogManager.LogFactory = new ConsoleLogFactory();