迭代一个未知的IQueryable的属性?

时间:2009-11-11 02:43:44

标签: asp.net-mvc linq json telerik iqueryable

如果以前曾被问过,请原谅我;几次搜索后我找不到任何东西:

我正在尝试在MVC中编写一个ActionFilter,它将“拦截”IQueryable并在运行时使所有父子关系无效。我这样做是因为Linq没有正确地序列化对象,如果它们有父子关系(它抛出一个循环引用错误,因为父引用了孩子,它引用了父对象等等),我需要对象序列化为Json进行Ajax调用。我尝试在内部隐私状态的DBML文件中标记子关系,虽然这修复了序列化问题,但它也会在页面呈现时隐藏视图引擎中的子成员,从而导致抛出另一个错误。因此,通过解决一个问题,我会引发另一个问题。

唯一解决这两个问题的方法是在返回序列化之前手动将子成员设置为null,但我试图避免这样做,因为它很麻烦,不可重用等等。我宁愿使用ActionFilter检查正在序列化的IQueryable并使用Type of EntitySet(如何表示外键/关联)使任何成员无效。但是,我对Reflection没有太多经验,也找不到任何说明如何做这样的事情的例子。所以...这可以用反射吗?有没有更好的方法来完成同样的事情?我明天回到工作电脑时会发布相关代码。

谢谢,

丹尼尔


按照承诺,代码:

[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 });
}

另外一个问题是我正在使用新的Telerik MVC Extensions,所以我实际上并没有自己序列化Json - 我只是在IGridModel中返回IQueryable,而动作过滤器[GridAction]执行其余部分。

2 个答案:

答案 0 :(得分:1)

所以,以防万一有人好奇,这就是我最终如何解决这个问题:我修改了Damien Guard的T4模板,将属性[ScriptIgnore]包含在Association类型的实体之上。这让JSON序列化程序知道不打扰序列化这些,从而防止我得到的循环引用问题。生成的代码最终看起来像这样:

private EntitySet<LineItem> _LineItems;
    [ScriptIgnore]
    [Association(Name=@"Form_LineItem", Storage=@"_LineItems", ThisKey=@"Id", OtherKey=@"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() });
}

答案 1 :(得分: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);
}

使用反射进行Nullify ,代码示例:

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);
    }
}

在我看来,如果可以在代码中使用第一个选项,那就更好了。这个选项更直接,更经济。