Subsonic 3 ActiveRecord вложенный выбор для NotIn ошибка?
У меня есть следующий запрос Subsonic 3.0, который содержит вложенный запрос NotIn:
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>();
}
Внутренний запрос кажется неверным:
SELECT TOP 1 *
FROM [Order]
WHERE ShopId = @0 AND CustomerId NOT IN (SELECT CustomerId
FROM [Customer]
WHERE TypeId = @0)
ORDER BY NewId() ASC
Вы заметите, что оба параметра @0. Я предполагаю, что параметры перечисляются (начиная с нуля) для каждого "нового" запроса Select. Однако в этом случае, когда два запроса Select вложены, я ожидал, что выходные данные будут иметь два параметра с именами @0 и @ 1.
Мой запрос основан на запросе, который Роб Конери дал в своем блоге для предварительного просмотра инструмента запросов "Pakala", который стал Subsonic 3. Его пример:
int records = new Select(Northwind.Product.Schema)
.Where("productid")
.In(
new Select("productid").From(Northwind.Product.Schema)
.Where("categoryid").IsEqualTo(5)
)
.GetRecordCount();
Кто-нибудь еще видел такое поведение? Это ошибка, или это ошибка или моя часть? Поскольку я новичок в Subsonic, я предполагаю, что это, вероятно, ошибка программиста с моей стороны, но я хотел бы получить подтверждение, если это возможно.
2 ответа
Просто сталкивался с точно такой же проблемой в последней версии, так что, видимо, она еще не исправлена. Я попытался изменить порядок условий (сначала поместив условие NotIn), и это помогло. Вот как выглядит новый код, который выдает параметры @0 и @1 вместо @0 и @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()");
Я не уверен насчет SubSonic 3, но в SubSonic 2, если вы запустите этот код, внутренний запрос будет выполнен первым, а второй запрос будет иметь уже идентифицированные CategoryIds в качестве параметра в запросе.
Может быть, это ошибка, и вы должны опубликовать ее на github.
В любом случае, вы можете сделать ваш запрос работающим на данный момент и вести себя как SubSonic 2 Subquery с этим небольшим изменением:
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 должен принимать IEnumerable в качестве параметра, но q будет содержать весь список CustomerIds в качестве параметра перед выполнением внешней части.
Не настоящее решение, но быстрое решение на данный момент (если это не сильно влияет на производительность).