我在理解为什么我的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; }
}
}
}
答案 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();