2014-10-10 127 views
0

目前我正在使用[JsonIgnore]属性来避免模型中的循环引用。但我认为,它将应用于所有实现。如何避免在Linq to Sql查询中循环循环?

现在我使用像这个 -

我有两个型号:

public class Project 
{ 
    public int ProjectID { get; set; } 

    [Required] 
    public string ProjectName { get; set; } 

    public DateTime? EstimatedEndDate { get; set; } 
    public DateTime? ProjectStartDate { get; set; } 
    public string OrderNumber { get; set; } 

    public string ProjectDescription { get; set; } 
    public virtual List<ServiceObject> ServiceObjects { get; set; } 

    [Required] 
    public string RegardingUser { get; set; } 

    public string CreatedBy { get; set; } 
    public DateTime CreatedDate { get; set; } 
    public string ModifiedBy { get; set; } 
    public DateTime ModifiedDate { get; set; } 
    public bool IsProjectDeleted { get; set; } 
    [NotMapped] 
    public int? ServiceObjectTemplateID { get; set; } 

} 

彼此型号是 -

public class ServiceObject 
{ 
    public int ServiceObjectID { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public string RegardingUser { get; set; } 
    public int? ParentServiceObjectID { get; set; } 
    [ForeignKey("ParentServiceObjectID")] 
    public virtual List<ServiceObject> ServiceObjects { get; set; } 
    public int ProjectID { get; set; } 
    [JsonIgnore] 
    public virtual Project Project { get; set; }<--------------------------- 
    public virtual List<ServicePicture> ServicePictures { get; set; } 
    public bool IsServiceObjectDeleted { get; set; } 
    public string CreatedBy { get; set; } 
    public DateTime CreatedDate { get; set; } 
    public string ModifiedBy { get; set; } 
    public DateTime ModifiedDate { get; set; } 
} 

但我想申请JsonIgnore财产或任何其他属性在Linq to Sql中查询自己。我的意思是我想动态应用它。

查询是喜欢 -

var projectList = (from pro in context.Projects.All 
        select pro).ToList(); 

我希望有条件地适用。

在此先感谢。

+0

属性必须在编译时应用,因此不能动态添加它们。 – TGH 2014-10-10 04:13:46

+0

这意味着它将只适用于模型? – Abhinav 2014-10-10 04:15:34

+0

是的,你必须在编译时将它们应用到你的属性。 – TGH 2014-10-10 04:16:29

回答

1

好的,根据您的意见和我的猜测,您所看到的是一个典型的EF代码优先问题。 EF为您的每个实体生成动态代理,以便它可以跟踪对其的更改。但是,这使得系列化困难,因为它们被创建为dynamic对象。有一些方法可以避免这一点:

选项A:禁用代理的创建只是针对特定的查询:

// disable proxy creation just for the duration of query 
context.Configuration.ProxyCreationEnabled = false; 

// do the query, serialize, go crazy! 

// enable proxy again. or if your context goes out of scope after this call, then you can ignore re-enabling. 
context.Configuration.ProxyCreationEnabled = true; 

选项B:如果你不打算修改,并在一些更新实体稍后点

var entity = context.Where(...); // or whatever query 

// detach entity 
context.Entry(entity).State = EntityState.Detached; 

选项C:通过修改类型定义避免代理:

如果您创建不带虚拟属性的密封类型或类型,EF将不会创建代理,因为 对代理无效。

public sealed class Project {...} 

// or make it non virtual 
... 
public List<ServiceObject> ServiceObjects { get; set; } 
... 

注意,在这种情况下,你必须手动加载相关对象:

context.Projects.Include(p => p.ServiceObjects).ToList(); 

选项d:禁用代理的创建永久:

// in your initializer or DbContext class' constructor 
DbContext.Configuration.ProxyCreationEnabled = false; 

注意 :如果禁用代理创建,EF将不会跟踪更改a utomatically。您可以使用快照方法manually track them

根据您的设计,您可以按照其中一个或多个选项进行操作。我通常坚持使用选项A或B.

+0

谢谢你给我几个解决方案。所有的解决方案都很好。我希望所有这些方式都是标准方法。 :) – Abhinav 2014-10-11 03:07:24

+0

这些都是我知道的正式记录的方式。 – Mrchief 2014-10-11 13:37:18

+0

我认为'ProxyCreationEnabled'只适用于实体框架,而不是Linq to SQL,提问者询问关于Linq到SQL – 2017-10-11 13:34:16

2

XY问题。你的实际问题是“我想在运行时控制哪些属性被序列化”。

控制哪些属性被序列化的最常见方法是使用JsonIgnoreAttribute。然而正如其他人所说的那样,属性是在编译时应用的,并且通常不能在运行时进行修改(您也不希望这样做,因为它实际上是在运行时更改的全局设置,所以会遇到大量线程问题)。

相反,答案是使用IContractResolver接口来改变序列化行为。

public class OmitPropertyContractResolver 
     : IContractResolver 
{ 
    private readonly string[] _ignoredProperties; 
    private readonly IContractResolver _resolver; 

    public OmitPropertyContractResolver(IContractResolver resolver, params string[] ignoredProperties) 
    { 
     _ignoredProperties = ignoredProperties; 
     _resolver = resolver;   
    } 
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     var properties = _resolver.CreateProperties(type, memberSerialization); 
     return properties 
       .Where(p => _ignoredProperties.Contains(p.Name) == false) 
       .ToList(); 
    } 
} 

另一种可能是在你的Json.net设置,使用ReferenceLoopHandling设置。

var serializer = new JsonSerializer(
         new JsonSerializerSetting() 
           { 
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore 
           }); 

这将只序列化每个对象一次。

最后一个选项是使用ItemReferenceLoopHandling。这是序列化(和反序列化)具有循环引用的对象图(注释,图形而不是树)的非标准方式。

此方法的缺点是它是非标准的,可能无法在客户端上工作。

+0

嗯...其实我的应用程序完全是客户端应用程序。 – Abhinav 2014-10-10 09:04:35