2009-11-11 4 views
1

Простите меня, если это было задано раньше; Я не смог найти ничего близкого после нескольких поисков:Итерация по неизвестным свойствам IQueryable?

Я пытаюсь написать ActionFilter в MVC, который «перехватит» IQueryable и аннулирует все отношения родитель-потомок во время выполнения. Я делаю это, потому что Linq не упорядочивает объекты должным образом, если у них есть отношения родитель-потомок (он выдает циклическую опорную ошибку, потому что родитель ссылается на дочерний элемент, который ссылается на родителя и т. Д.), И мне нужен объект сериализован для Json для вызова Ajax. Я попытался маркировать дочерние отношения в файле DBML со статусом конфиденциальности внутреннего, и, хотя это исправляет проблему сериализации, он также скрывает дочерние элементы из механизма просмотра, когда страница отображается, в результате чего возникает другая ошибка. Итак, исправляя одну проблему, я вызываю другую.

Единственное, что устраняет обе проблемы, - это вручную установить дочерние элементы на нуль перед возвратом сериализации, но я стараюсь избегать этого, потому что это громоздко, не может использоваться повторно и т. Д. Я бы предпочел использовать ActionFilter для проверки IQueryable, который сериализуется и аннулирует любые члены с типом EntitySet (как представлены внешние ключи/ассоциации). Тем не менее, у меня нет большого опыта работы с Reflection и я не могу найти примеров, иллюстрирующих, как это сделать. Итак ... возможно ли это с Reflection? Есть ли лучший способ сделать то же самое? Завтра я отправлю соответствующий код, когда вернусь на рабочий компьютер.

Спасибо,

Daniel


Как обещанный код:

[GridAction] 
public ActionResult _GetGrid() 
{ 
    IQueryable<Form> result = formRepository.GetAll(); 
    foreach (Form f in result) 
    { 
     f.LineItems = null; 
     f.Notes = null; 
    } 

    return View(new GridModel<Form> { Data = result }); 
} 

Добавленной морщин является то, что я использую новый MVC Telerik Extensions, так что я на самом деле не сериализует сам Json - я просто возвращаю IQueryable в IGridModel, а фильтр действий [GridAction] делает все остальное.

ответ

0

Существует два варианта: один из них должен игнорировать эти свойства во время сериализации с использованием [XmlIgnore]. Другой - аннулировать свойства с помощью отражения.

Игнорирование в сериализации, простой пример использования, который показывает, как использовать значение по умолчанию в сериализации:

[Serializable] 
public class MyClass 
{ 
    [XmlIgnore] 
    public int IgnoredVal { get; set; } 

    public int Val { get; set; } 
} 

public void UsageSample() 
{ 
    var xmlSerializer = new XmlSerializer(typeof(MyClass)); 
    var memoryStream = new MemoryStream(); 
    var toSerialize = new MyClass { IgnoredVal = 1, Val = 2 }; 
    xmlSerializer.Serialize(memoryStream, toSerialize); 
    memoryStream.Position = 0; 
    var deserialize = (MyClass)xmlSerializer.Deserialize(memoryStream); 

    Assert.AreEqual(0, deserialize.IgnoredVal); 
    Assert.AreEqual(2, deserialize.Val); 
} 

аннулирует с отражением, код образца:

public void NullifyEntitySetProperties(object obj) 
{ 
    var entitySetProperties = obj.GetType().GetProperties() 
     .Where(property => property.PropertyType == typeof(EntitySet)); 

    foreach (var property in entitySetProperties) 
    { 
     property.SetValue(obj, null, null); 
    } 
} 

На мой взгляд, если первый вариант может быть использован в вашем коде, это лучше. Этот вариант является более прямым и экономичным.

1

Итак, на всякий случай, кто-то любопытен, вот как я, наконец, решил эту проблему: я модифицировал шаблон T4 от Damien Guard, чтобы включить атрибут [ScriptIgnore] над сущностями типа Association. Это позволяет JSON-сериализатору знать, не беспокоить сериализацию данных, тем самым предотвращая круглую проблему с заданиями, которую я получал. Сгенерированный код заканчивает тем, как это:

private EntitySet<LineItem> _LineItems; 
    [ScriptIgnore] 
    [Association([email protected]"Form_LineItem", [email protected]"_LineItems", [email protected]"Id", [email protected]"FormId")] 
    public EntitySet<LineItem> LineItems 
    { 
     get { 
      return _LineItems; 
     } 
     set { 
      _LineItems.Assign(value); 
     } 
    } 

Это устраняет проблему сериализации у меня был без отключения использования дочерних таблиц с помощью LINQ.Действие сетки на контроллере выглядит следующим образом:

[GridAction] 
public ActionResult _GetGrid() 
{ 
    return View(new GridModel<Form> { Data = formRepository.GetAll() }); 
}