简体   繁体   English

如何避免Linq to Sql查询中的循环循环?

[英]How to avoid circular loop in Linq to Sql query?

Currently I am using [JsonIgnore] property to avoid circular references in the models. 当前,我正在使用[JsonIgnore]属性来避免模型中的循环引用。 But I think, it will be applied in all implementations. 但我认为,它将应用于所有实现中。

Right now I am using like this- 现在我正在这样使用-

I have two Models: 我有两个模型:

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

}

One another Model is- 另一个模型是-

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

But I want to apply JsonIgnore property or any other property In Linq to Sql query itself. 但是我想将JsonIgnore属性或任何其他属性应用于Sql查询本身。 I mean I want to apply it dynamically. 我的意思是我想动态地应用它。

The Query is like- 查询就像-

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

I want to apply conditionally. 我想有条件地申请。

Thanks in advance. 提前致谢。

XY problem. XY问题。 Your actual problem is "I want to control at runtime what properties get serialized". 您的实际问题是“我想在运行时控制要序列化的属性”。

The most common method of controlling what properties are serialized is using the JsonIgnoreAttribute . 控制序列化哪些属性的最常见方法是使用JsonIgnoreAttribute However as others have commented, attributes are applied at compile time, and cannot normally be modified at runtime (nor would you want to, since it would in effect be a global setting being changed at runtime, you would run into a ton of Threading issues). 但是,正如其他人所评论的那样,属性是在编译时应用的,通常不能在运行时进行修改(您也不希望这样做,因为实际上是在运行时更改了全局设置,因此会遇到大量线程问题)。

Instead, the answer is to use the IContractResolver interface to change the serialization behavior. 相反,答案是使用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();
    }
}

The other possibility is to use ReferenceLoopHandling setting in your Json.net settings. 另一种可能性是在Json.net设置中使用ReferenceLoopHandling设置。

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

This will serialize each object only once. 这只会序列化每个对象一次。

The last option is to use ItemReferenceLoopHandling . 最后一个选项是使用ItemReferenceLoopHandling This is a non-standard way of serializing (and deserializing) Object-Graphs (note, graph and not tree) which have circular references. 这是序列化(和反序列化)具有循环引用的对象图(注释,图而不是树)的非标准方法。

The disadvantage of this method is that it is non-standard, and might not work on the client end. 此方法的缺点是它是非标准的,可能无法在客户端上使用。

Ok, so based on your inputs and as I suspected, what you're seeing is a typical EF Code First issue. 好的,因此根据您的输入以及我的怀疑,您看到的是典型的EF Code First问题。 EF generates dynamic proxies for each of your entity so that it can track changes to it. EF为您的每个实体生成动态代理,以便它可以跟踪对其的更改。 However, this makes serialization difficult since they are created as dynamic objects. 但是,由于序列化是作为dynamic对象创建的,因此很难进行序列化 There are few ways to avoid this: 有几种方法可以避免这种情况:

Option A: Disable proxy creation just for the particular query: 选项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;

Option B: If you are not going to modify and update the entity at some later point 选项B:如果以后不打算修改和更新实体

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

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

Option C: Avoid proxies by modifying type definition: 选项C:通过修改类型定义来避免代理:

If you create sealed type or type without virtual properties, EF will not create a proxy since there is nothing for the proxy to do. 如果您创建密封类型或没有虚拟属性的类型,则EF将不会创建代理,因为该代理无事可做。

public sealed class Project {...}

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

Note that in this case, you have to load related objects manually: 请注意 ,在这种情况下,您必须手动加载相关对象:

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

Option D: Disable proxy creation permanently: 选项D:永久禁用代理创建:

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

Note : If proxy creation is disabled, EF will not tracked changes automatically. 注意 :如果禁用了代理创建,则EF不会自动跟踪更改。 You can manually track them using the Snapshot method. 您可以使用Snapshot方法手动跟踪它们

You can follow one or more of these options depending on your design. 您可以根据自己的设计采用这些选项中的一个或多个。 I usually stick with option A or B. 我通常坚持使用选项A或B。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM