【问题标题】:LINQ to SQL optional ColumnLINQ to SQL 可选列
【发布时间】:2025-11-25 01:35:01
【问题描述】:

我需要一个在 LINQ to SQL 定义中包含可选列的功能。因此 LINQ to SQL 通常会在选择和更新等中忽略此列。 但是如果一个选择包含该列的值,它应该使用这个值。

长版:

情景

我有以下表格:

如果 Field.FieldViews.Count() 大于 0,则该字段应该是可见的。

问题

如果我检查上面提到的可见性:

Field.FieldViews.Count()

比它对每个字段的数据库进行一次查询。 所以在我的项目中有时高达 1000 倍

我的解决方案

我写了一个存储过程:

 SELECT
   f.*,
   (SELECT COUNT(*) FROM [fieldViews] v WHERE v.fieldId = f.fieldId) AS Visible
  FROM [fields] f
  WHERE
   f.X BETWEEN @xFrom AND @xTo AND
   f.Y BETWEEN @yFrom AND @yTo

为了使用这个附加列,我添加了以下代码:

 public partial class Field
  {
   private bool visible = false;
 
   [Column(Storage = "Visible", DbType = "INT")]
   public bool Visible
   {
    get
    {
     return visible;
    }
    set
    {
     visible = value;
    }
   }
  }

这很好用。

但是……

问题

如果我在没有存储过程的情况下从 Fields 表中获取条目:

from d in DataContext.Fields select d;

我收到以下错误:

Bad Storage property: 'Visible' on member 'Models.Field.Visible'.

所以我在数据库表中添加了“可见”列:

ALTER TABLE dbo.Fields ADD
 Visible int NOT NULL CONSTRAINT DF_Fields_Visible DEFAULT 0

这样我就可以解决上面提到的错误了。

但是……

下一个问题

我已经使用存储过程获取了一些 Field 对象。 现在我对其中一些对象进行了一些更改。 如果我现在尝试提交这些更改,它将不起作用。查看生成的查询揭示了原因:

 UPDATE [dbo].[Fields]
 SET [X] = @p3
 WHERE ([FieldId] = @p0) AND ([X] = @p1) AND ([Y] = @p2) AND ([Visible] = 3)

这里的问题是,它在 where 语句中使用了“可见”列。但“可见”列始终为 0。 如果我使用存储过程获取数据,Visible 仅大于 0...

我需要什么

类似于不需要列的 ColumnAttribute

一种在更新时从 where 语句中删除列的方法。

【问题讨论】:

    标签: c# performance linq-to-sql stored-procedures


    【解决方案1】:

    我们通过查询详细信息表解决了最初的问题,例如:

    FieldViewsRepository.FieldViews.Where(fv => fv.FieldViewId == Field.FieldID).Count()
    

    这只会生成一个对数据库的查询。

    如果您需要具有附加 Visible 属性的对象列表,您可以执行以下操作:

    FieldRepository.Fields.Select(f => new { ID=f.FieldID, X=f.X, y=f.Y, Visible=f.FieldViews.Any() }
    

    FieldRepository.Fields.Select(f => new { Field=f, Visible=f.FieldViews.Any() }
    

    与 Visible 是 Filed 对象的一个​​属性并为每个字段执行查询的情况不同,在这种情况下,字段和 Visible 属性是在一个查询中从数据库中获取的。

    【讨论】:

      【解决方案2】:

      无需将此作为列存储在字段表中 - 您可以在 Field 类中计算:

      public bool Visible
      {
          get { return this.FieldViews.Count() > 0; }
      }
      

      【讨论】:

      • 是的,这行得通。我也使用了这个......但正如我所提到的:对于我检查的每个字段 - 这将产生 1 个查询。如果我检查 1000 个字段 - 它会产生 1000 次此查询: SELECT [t0].[FieldViewId], [t0].[FieldId] FROM [dbo].[FieldViews] AS [t0] WHERE [t0].[FieldId] = @p0 ...使用存储过程要快得多!?
      【解决方案3】:

      我找到了解决我的问题的方法:

              private bool visible = false;
          public bool Visible
          {
              get
              {
                  return visible;
              }
              set
              {
                  visible = value;
              }
          }
      
          private int fakeVisible
          {
              get
              {
                  return 0;
              }
              set
              {
                  visible = value > 0;
              }
          }
      
          [Column(Name="Visible", Storage = "fakeVisible", DbType = "Int NOT NULL")]
          public int FakeVisible { get; set; }
      

      还是谢谢!

      【讨论】: