2

如果以前有人问过这个问题,请原谅我;经过几次搜索后,我找不到任何关闭的东西:

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

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

谢谢,

丹尼尔


正如所承诺的,代码:

[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 扩展,所以我实际上并没有自己序列化 Json——我只是在 IGridModel 中返​​回 IQueryable,而动作过滤器 [GridAction] 完成了其余的工作。

4

2 回答 2

1

所以,以防万一有人好奇,这就是我最终解决这个问题的方法:我修改了 Damien Guard 的 T4 模板,在 Association 类型的实体上方包含属性 [ScriptIgnore]。这让 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() });
}
于 2009-11-11T19:26:28.960 回答
0

有两种选择,一种是在使用[XmlIgnore]. 另一种是使用反射使属性无效。

Ignore in serialization,简单的使用示例,展示了如何在序列化中使用默认值:

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

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

于 2009-11-11T05:28:16.580 回答