C# CA2227:集合属性应为只读

C# CA2227:集合属性应为只读,c#,code-analysis,C#,Code Analysis,假设我的实体模型中有以下类: public Entity{ public int ID {get; set;} .... public virtual ICollection<SecondEntity> SecondEntities { get; set; } } 但是代码分析器现在抱怨我的集合中不应该有setter。如果删除setter,则无法(或不知道如何)在对数据库的同一调用中填充该集合。如果我将此调用分为两个单独的调用,一个用于获取实体,第二个用于获取实体

假设我的实体模型中有以下类:

public Entity{
   public int ID {get; set;}
   ....
   public virtual ICollection<SecondEntity> SecondEntities { get; set; }
}
但是代码分析器现在抱怨我的集合中不应该有setter。如果删除setter,则无法(或不知道如何)在对数据库的同一调用中填充该集合。如果我将此调用分为两个单独的调用,一个用于获取
实体
,第二个用于获取
实体。第二个实体
我将不得不编写更多代码并对数据库进行更多调用,加上我必须在
循环中这样做才能为每个
实体
对象获取
第二个实体
,我认为在这种情况下这不是最优的(事实上,我知道从循环中查询数据库是个坏主意)。有人能纠正我吗?或者有没有其他方法可以检索关系数据库,将它们投影到Dto类中,同时遵守让我的集合成为只读的规则

显然,它也在抱怨签名(嵌套泛型类型),但从我读到的内容来看,对于1-2级嵌套,我应该忽略这一点

另外,我也从中检查了这个示例,但我不知道这将如何适用于这种情况。

现在声明,在这种情况下禁用警告是合理的

如果属性是数据传输对象(DTO)类的一部分,则可以抑制该警告。 否则,请勿禁止显示此规则中的警告

根据您的反序列化需要,还有其他可供选择的方案:

  • 在DTO中包含一个接受对象并从中设置其属性的构造函数
  • 按照以下步骤使用初始设置器(C#9)

基本上,您不需要执行此操作,因为这将替换对集合的引用。您应该改为这样做:
SecondEntities.Clear();SecondEntities.AddRange(…)
但是,我必须为该集合中的每个
实体
编写一个循环,这意味着对于10000行数据,对该
第二实体
的数据库进行10000次调用,这将极大地损害性能,而不仅仅是从调用中获取整个数据表。。另一个更好的方法是不投影,但与较大的表相比,它会再次损害性能。。。这显然没有什么害处。。(或与其他2个选项相比伤害更小)。。。我错了吗?你为什么需要一个循环?在您当前的代码中只有一个SecondEntities=因此,如果使用oleksii发布的代码提供SetSecondEntities(ICollection se)方法,您将得到相同的结果,您可以删除setter,顺便说一句,将字段设为只读。
public EntityDto{
   public int ID {get; set;}
   ....
   public virtual ICollection<SecondEntityDto> SecondEntities { get; set; }
}
public async Task<ICollection<EntityDto>> GetAll()
        {
            using (var context = new entityContext())
            {
                try
                {
                    return await Task.FromResult(
                     context.Entity.Select(p => new EntityDto() {
                            Id = p.Id,
                            SecondEntities = p.SecondEntities.Select(q => new SecondEntity() {
                                 Id = q.Id })
                            .ToList() })
                     .ToList());
                }
                catch (System.Exception ex)
                {
                    log.Error("Error", ex);
                    throw;
                }
            }
        }