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 в качестве параметра перед выполнением внешней части.

Не настоящее решение, но быстрое решение на данный момент (если это не сильно влияет на производительность).

Другие вопросы по тегам