Если я правильно понимаю ваши потребности, вам нужно отсортировать вывод таким образом, чтобы строки #temp1
отображались перед #temp2
строками для каждого значения cid
.
То, что вы могли бы сделать, - это сгенерировать дополнительный столбец ordnum
, присваивая значения для каждой таблицы только для целей сортировки, а затем избавиться от него во внешнем операторе select.
select cid, _data
from (
select 1 as ordnum, *
from #temp1
union all
select 2 as ordnum, *
from #temp2 t2
where exists (
select 1
from #temp1 t1
where t1.cid = t2.cid
)
) q
order by cid, ordnum
Я также переписал ваше условие where
для эквивалента, который должен работать быстрее, используя оператор exists
.
Вывод
cid _data
1001 text1
1001 text2
1001 sample1
1001 sample2
1002 text1
1002 text2
1002 sample1
1002 sample2
Я думаю, что Вы рассерженные ни по чему. Таким образом, что, если контроллер знает о JSON в своем открытом интерфейсе?
мне когда-то сказали: "Сделайте свой код универсальным, не подавайте свою универсальную заявку".
Вы пишете Контроллер Приложения здесь. Для Контроллера Приложения - хорошо, чья ответственность состоит в том, чтобы смягчить между моделью и представлениями и вызвать изменения в модели - для знания об определенном представлении (JSON, HTML, PList, XML, YAML).
В моих собственных проектах, у меня обычно есть что-то как:
interface IFormatter {
ActionResult Format(object o);
}
class HtmlFormatter : IFormatter {
// ...
}
class JsonFormatter : IFormatter {
// ...
}
class PlistFormatter : IFormatter {
// ...
}
class XmlFormatter : IFormatter {
// ...
}
В основном "средства форматирования", которые берут объекты и дают им другое представление. HtmlFormatter
с даже достаточно умны к таблицам выходных данных, если их объект реализует IEnumerable
.
Теперь контроллеры, которые возвращают данные (или это может генерировать части веб-сайта с помощью HtmlFormatter
, с берут аргумент "формата":
public ActionResult JoinMailingList(string txtEmail, string format) {
// ...
return Formatter.For(format).Format(
new { foo = "123", success = true }
);
}
Вы могли добавить свое "объектное" средство форматирования для Ваших модульных тестов:
class ObjectFormatter : IFormatter {
ActionResult Format(object o) {
return new ObjectActionResult() {
Data = o
};
}
}
Используя эту методологию, любой из Ваших вызовов queries/actions/procedures/ajax, независимо от того, что Вы хотите назвать их, может произвести во множестве форматов.
Обычно я стараюсь не беспокоиться об этом. В Asp.Net MVC достаточно разделения проблем, чтобы свести утечку к минимуму. Вы правы, хотя; при тестировании возникает некоторое препятствие.
Вот тестовый помощник, который я использую, и он хорошо работает:
protected static Dictionary<string, string> GetJsonProps(JsonResult result)
{
var properties = new Dictionary<string, string>();
if (result != null && result.Data != null)
{
object o = result.Data;
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(o))
properties.Add(prop.Name, prop.GetValue(o) as string);
}
return properties;
}
Вы можете использовать метод расширения Request.IsAjaxRequest () для возврата различных типов ActionResult:
if (this.Request != null && this.Request.IsAjaxRequest())
return Json(new { Message = "Success" });
else
return RedirectToAction("Some Action");
Примечание: вам понадобится Request! = Null, чтобы не прерывать ваши тесты.
Я не слишком волнуюсь по поводу возврата JSon, как я был прежде. Природа Ajax, кажется, такова, что сообщение, которое Вы хотите обработать в JavaScript только, касается той ситуации с Ajax. Потребность Ajax в производительности просто должна влиять на код так или иначе. Вы, вероятно, не хотели бы возвращать те же данные другому клиенту.
вещи Пары относительно тестирования JSonResult, который я заметил (и я все еще должен все же записать любые тесты для своего приложения):
1), когда Вы возвращаете JSonResult из своего метода действия, который 'получен' Вашим методом тестирования, у Вас все еще есть доступ к исходному Объекту данных. Это не было очевидно для меня сначала (несмотря на то, чтобы быть несколько очевидным). Ответ Rob выше (или возможно ниже!) использует этот факт, чтобы взять параметр Данных и создать словарь из него. Если Данные имеют известный тип затем, конечно, можно бросить их к тому типу.
Лично я только возвращал очень очень простые сообщения через Ajax без любой структуры. Я придумал дополнительный метод, который мог бы быть полезен для тестирования, если Вам просто создали простое сообщение из анонимного типа. Если у Вас есть больше чем один 'уровень' к Вашему объекту - Вы - вероятно, более обеспеченное создание фактического класса для представления объекта JSon так или иначе, в этом случае Вы просто бросаете jsonResult.Data
к тому типу.
Демонстрационное использование сначала:
Метод действия:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ContactUsForm(FormCollection formData){
// process formData ...
var result = new JsonResult()
{
Data = new { success = true, message = "Thank you " + firstName }
};
return result;
}
Модульный тест:
var result = controller.ContactUsForm(formsData);
if (result is JSonResult) {
var json = result as JsonResult;
bool success = json.GetProperty<bool>("success");
string message = json.GetProperty<string>("message");
// validate message and success are as expected
}
можно затем выполнить утверждения или независимо от того, что Вы хотите в своем тесте. Кроме того, дополнительный метод выдаст исключения, если тип не будет как ожидалось.
Дополнительный метод:
public static TSource GetProperty<TSource>(this JsonResult json, string propertyName)
{
if (propertyName == null)
{
throw new ArgumentNullException("propertyName");
}
if (json.Data == null)
{
throw new ArgumentNullException("JsonResult.Data"); // what exception should this be?
}
// reflection time!
var propertyInfo = json.Data.GetType().GetProperty(propertyName);
if (propertyInfo == null) {
throw new ArgumentException("The property '" + propertyName + "' does not exist on class '" + json.Data.GetType() + "'");
}
if (propertyInfo.PropertyType != typeof(TSource))
{
throw new ArgumentException("The property '" + propertyName + "' was found on class '" + json.Data.GetType() + "' but was not of expected type '" + typeof(TSource).ToString());
}
var reflectedValue = (TSource) propertyInfo.GetValue(json.Data, null);
return reflectedValue;
}
Я думаю, что у вас есть правильная точка зрения - почему бы не делегировать «разрешенные типы ответов по сравнению с созданными типами ответов» в какое-то место, где они действительно принадлежат?
Это напоминает мне одно из мнений Джереми Миллера о том, как сделать приложение ASP.NET MVC: «Мнения» о ASP.NET MVC
В их В приложении все действия контроллера имеют простой и понятный интерфейс - один объект модели представления входит, другой объект модели представления удаляется.
Я не уверен, насколько большой из проблемы это на самом деле, но "альтернативный шаблон" для следования в ASP.NET, который MVC должен был бы записать JSON ViewEngine. Это на самом деле не было бы настолько трудно, так как функциональность JSON, встроенная в платформу, сделает большую часть тяжелого подъема для Вас.
я действительно думаю, что это было бы лучшим дизайном, но я не уверен, что настолько лучше, что стоит идти вразрез с "официальным" способом реализовать JSON.
Я думал об этом и реализовал фильтр JsonPox , чтобы сделать это.
С другой стороны, если Вы не хотите входить в использование отражения, можно создать RouteValueDictionary со Свойством данных результата. Движение с данными OP...
var jsonData = new RouteValueDictionary(result.Data);
Assert.IsNotNull(jsonData);
Assert.AreEqual(2,
jsonData.Keys.Count);
Assert.AreEqual("123",
jsonData["foo"]);
Assert.AreEqual(true,
jsonData["success"]);