Нет, невозможно PIVOT
обойтись без агрегатной функции, но вы можете сделать агрегатную функцию произвольной, обеспечив только одну исходную строку на группу. Из вашего вопроса не сразу понятно, в чем заключается ваша логика:
Например, у вас есть два значения для времени 12 (KA108112
и KA106360
) и 3 строки для времени 13 (TN04F6726
, TN28C3709
, TN52C4788
), так что есть несколько разных способов объединить эти два.
Вы можете вернуть декартово произведение:
12 13
----------------------
KA108112 TN04F6726
KA106360 TN04F6726
KA108112 TN28C3709
KA106360 TN28C3709
KA108112 TN52C4788
KA106360 TN52C4788
Или вы можете вернуть каждый результат один раз, например
12 13
----------------------
KA106360 TN04F6726
KA108112 TN28C3709
NULL TN52C4788
Но вам также необходимо предоставить дополнительную логику, то есть, почему KA106360
будет соответствовать TN04F6726
, а не любому из двух других значений (в приведенном выше примере у меня есть ordererd Trailer_RegNo в алфавитном порядке каждый раз, но может быть любое количество способов сделать это.
Исходя из вашего комментария, кажется, что вы хотите произвольно спарить значения, поэтому, чтобы убедиться, что каждое значение представлено, вам нужно сделать каждую строку уникальной , что вы можете сделать, используя ROW_NUMBER()
, например
DECLARE @T TABLE (Time INT, Trailer_RegNo VARCHAR(20));
INSERT @T (Time, Trailer_RegNo)
VALUES (12, 'KA108112'), (12, 'KA106360'), (13, 'TN04F6726'), (13, 'TN28C3709'), (13, 'TN52C4788');
SELECT Trailer_RegNo,
Time,
RowNumber = ROW_NUMBER() OVER(PARTITION BY [Time] ORDER BY Trailer_RegNo)
FROM @T;
, что дает:
Trailer_RegNo Time RowNumber
----------------------------------
KA106360 12 1
KA108112 12 2
TN04F6726 13 1
TN28C3709 13 2
TN52C4788 13 3
Теперь у вас есть способ сопряжения ваших предметов (например, KA106360 и TN04F6726, KA108112 и amp ; TN28C3709 и т. Д.) Чтобы изменить порядок группировки элементов, вам просто нужно изменить предложение ORDER BY
в функции ROW_NUMBER()
.
Таким образом, ваш последний запрос может выглядеть примерно так:
[114 ]I initially wanted to mock out calls like 'IQueryable.Where(Func)' too but I think it is testing at the wrong level. Instead in my tests I just mocked out IQueryable and then check the result:
// Setup a dummy list that will be filtered, queried, etc
var actionList = new List<ActionType>()
{
new ActionType() { Name = "debug" },
new ActionType() { Name = "other" }
};
_repository.Expect(x => x.Query<ActionType>()).Return(actionList);
var result = _service.GetAvailableActions().ToList();
// Check the logic of GetAvailableActions returns the correct subset
// of actionList, etc:
Assert.That(result.Length, Is.EqualTo(1));
Assert.That(result[0], Is.EqualTo(actionList[0]);
_repository.VerifyAllExpectations();
Не используя насмешки Rhino, вы можете создать список и затем вызвать .AsQueryable () для него. например,
var actionTypeList = new List<ActionType>() {
new ActionType {}, //put your fake data here
new ActionType {}
};
var actionTypeRepo = actionTypeList.AsQueryable();
Это, по крайней мере, даст вам поддельное хранилище, но не позволит вам проверить, были ли вызваны методы.
Where
is an extension method, this is not a method implemented by the interface IQueriable. Look at the members of IQueriable: http://msdn.microsoft.com/en-us/library/system.linq.iqueryable_members.aspx
An extension method is static and can't be mocked. IMO, there is no need to mock Where
, because it's part of the language. You should only mock the repository.
Edit, Example:
[TestFixture]
public class ServiceClassTester
{
private ServiceClass _service;
private IRepository _repository;
private IQueryable<ActionType> _actionQuery;
[SetUp]
public void SetUp()
{
_service = new ServiceClass(_repository);
// set up the actions. There is probably a more elegant way than this.
_actionQuery = (new List<ActionType>() { ActionA, ActionB }).AsQueryable();
// setup the repository
_repository = MockRepository.GenerateMock<IRepository>();
_repository.Stub(x => x.Query<ActionType>()).Return(_actionQuery);
}
[Test]
public void heres_a_test()
{
// act
var actions = _service.GetAvailableActions();
// assert
Assert.AreEqual(1, actions.Count());
// more asserts on he result of the tested method
}
}
Note: you don't need to expect the call, because your method depends on the return value of the mock. If it wouldn't call it, it would fail on the asserts. This makes your test easier to maintain.