问题
I have the following Subsonic 3.0 query, which contains a nested NotIn query:
public List<Order> GetRandomOrdersForNoReason(int shopId, int typeId)
{
// build query
var q = new SubSonic.Query.Select().Top("1")
.From("Order")
.Where("ShopId")
.IsEqualTo(shopId)
.And(OrderTable.CustomerId).NotIn(
new Subsonic.Query.Select("CustomerId")
.From("Customer")
.Where("TypeId")
.IsNotEqualTo(typeId))
.OrderDesc("NewId()");
// Output query
Debug.WriteLine(q.ToString());
// returned typed list
return q.ExecuteTypedList<Order>();
}
The internal query appears to be incorrect:
SELECT TOP 1 *
FROM [Order]
WHERE ShopId = @0 AND CustomerId NOT IN (SELECT CustomerId
FROM [Customer]
WHERE TypeId = @0)
ORDER BY NewId() ASC
You'll notice that both parameters are @0. I'm assuming that the parameters are enumerated (starting at zero), for each "new" Select query. However, in this case where the two Select queries are nested, I would have expected the output to have two parameters named @0 and @1.
My query is based on one that Rob Conery gave on his blog as a preview of the "Pakala" query tool that became Subsonic 3. His example was:
int records = new Select(Northwind.Product.Schema)
.Where("productid")
.In(
new Select("productid").From(Northwind.Product.Schema)
.Where("categoryid").IsEqualTo(5)
)
.GetRecordCount();
Has anyone else seen this behavior? Is it a bug, or is this an error or my part? Since I'm new to Subsonic I'm guessing that this probably programmer error on my part but I'd like confirmation if possible.
回答1:
Just came across this exact same issue in the latest release, so apparently it hasn't been fixed yet. I tried switching the order of the conditions (putting the NotIn condition first) and that did the trick. Here's what the new code looks like, which produced parameters @0 and @1 instead of @0 and @0:
var q = new SubSonic.Query.Select().Top("1")
.From("Order")
.Where(OrderTable.CustomerId).NotIn(
new Subsonic.Query.Select("CustomerId")
.From("Customer")
.Where("TypeId")
.IsNotEqualTo(typeId)
)
.And("ShopId")
.IsEqualTo(shopId)
.OrderDesc("NewId()");
回答2:
I'm not sure about SubSonic 3 but in SubSonic 2 if you would run this code the inner query would be executed first and the second query would have the CategoryIds allready defined as a parameter in the query.
Maybe this is a bug and you should post it on github.
Anyway you could make your query work for the moment and behave like a SubSonic 2 Subquery with this little change:
var q = new SubSonic.Query.Select().Top("1")
.From("Order")
.Where("ShopId")
.IsEqualTo(shopId)
.And(OrderTable.CustomerId).NotIn(
new Subsonic.Query.Select("CustomerId")
.From("Customer")
.Where("TypeId")
.IsNotEqualTo(typeId)
.ExecuteTypedList<int>()
)
.OrderDesc("NewId()");
NotIn should take a IEnumerable as a parameter but q will contain the whole list of CustomerIds as a parameter before the outer part is executed.
Not a real solution but a quick fix for the moment (if it doesn't affect performance to much).
来源:https://stackoverflow.com/questions/2995268/subsonic-3-activerecord-nested-select-for-notin-bug