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.
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()");
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