【问题标题】:Comparing sql with c# list in query?在查询中比较 sql 和 c# 列表?
【发布时间】:2020-09-20 17:45:41
【问题描述】:

我在将我的 sql 数据库中的值与我的代码中的对象列表进行比较时遇到问题。

该对象在数据库中不存在

列表中的对象示例:

{
    public long CompareId
    public bool HasAccess
}

我在 C# 中使用 SQLBuilder 然后我想做一个这样的查询:

在编造的代码中

SELECT * FROM EntityPermission
WHERE EntityPermission.HasAccess = listOfObjects.Where(obj => obj.CompareId == EntityPermission.CompareId).HasAccess

在更多组成的代码中,但使用 sql builder

query.WHERE("(EntityPermission.HasAccess = {0})", listOfObjects.Where(obj => obj.CompareId == EntityPermission.CompareId).HasAccess)

我完全清楚我在这里混合了 c# 和 sql,但这是我可以解释我想要完成的最佳方式。

言辞

我想找到 HasAccess 列等于具有相同 Id 的对象的 HasAccess 属性的 EntityPermission。

非常感谢大家的帮助!

【问题讨论】:

  • 什么是listOfObjects?它是您数据库中的另一个实体吗?你可以做一个连接并获得你需要的数据。
  • 它不是我数据库中的另一个实体,它来自输入。所以它只是存在于代码中的那个时刻的价值
  • 您在此处尝试执行的操作本质上需要对表变量或表值参数进行内部连接;尴尬的一点本质上是:把你的listOfObjects 放到数据库中——listOfObjects 是多少位?取决于这是否可能是 20 vs 2000 vs 200000 有很多差异
  • 对象列表可能有大约 500 个实体,可能更多

标签: c# sql linq .net-core sqlbuilder


【解决方案1】:

我想找到 HasAccess 列等于具有相同 Id 的对象的 HasAccess 属性的 EntityPermission。

所以你有一张桌子EntityPermissions。此表中的每个EntityPermission 至少有一个布尔属性HasAccess,以及长属性Id 中的一个主键

此外,您还有一个对象列表,其中每个对象至少有一个 CompareId 和一个 HasAccess。

如果我正确阅读了您的要求,您希望所有具有 Id 的 EntityPermissions 也是您列表中的 CompareId,并且具有相同的 HasAccess 值。

所以如果你的列表有值:

{10, false}, {11, true}, {12, false},

你有 EntityPermissiont:

Id  HasAccess 
09  true         don't want this one, Id is not in the list
10  true         don't want this one, Id is in the list, but HasAccess incorrect
11  true         I want this one: Id is in the list, HasAccess is correct
12  false        I want this one: Id is in the list, HasAccess is correct

通常您会为此使用Where(x => y.Contains(x))。问题是你只能选择一个属性。

var checkValues = new
{
    new {CompareId = 10, HasAccess = false},
    new {CompareId = 11, HasAccess = true},
    new {CompareId = 12, HasAccess = false},
}

var result = dbContext.EntityPermissions.Select(entityPermission => new
{
    ValueToCompare = new
    {
         CompareId = entityPermission.Id,
         HasAccess = entityPermission.HasAccess,
    },

    Original = entityPermission,
})

// keep only those selected items that have a ValueToCompare in CheckValues
.Where(selectedItem => checkValues.Contains(selectedItem.ValueToCompare)

// from the remaining items, extract the original EntityPermission
.Select(selectedItem => selectedItem.Original);

【讨论】:

    【解决方案2】:

    您正在寻找的是 SQL WHERE...IN () 语法。

    如果您使用的是生成 SQL 的工具,您想要做的是这样的:

    1) 获取要比较的值列表

    2) 从它们中创建如下字符串:

    "('value1','value2','value3')"
    

    3) 然后生成如下所示的查询:

    SELECT * FROM EntityPermission
    WHERE EntityPermission.HasAccess
    IN ('value1','value2','value3')
    

    对于实体框架、NHibernate 等 ORM,您可以执行以下操作:

    var results = db.EntityPermissions
                    .Where(x => listOfObjects
                               .Where(obj => obj.CompareId == EntityPermission.CompareId)
                    .Select(y => y.HasAccess)
                    .Contains(x.HasAccess))
    

    【讨论】:

      【解决方案3】:

      可以使用表值参数和用户定义类型执行此操作,然后进行内部连接:

      SELECT * FROM EntityPermission ep
      INNER JOIN @foo f ON f.Id = ep.Id AND f.HasAccess = ep.HasAccess
      

      但是:UDT 和 TVP 真的很难使用;坦率地说,我很想创建两个串联的字符串:

      string with = string.Join(",", list.Where(x => x.HasAccess).Select(x => x.Id));
      string without = string.Join(",", list.Where(x => !x.HasAccess).Select(x => x.Id));
      

      并将其作为参数传递给string_split

      SELECT *
      FROM EntityPermission
      WHERE (Id in (select value from string_split(@with, ',')) and HasAccess = 1)
      OR (Id in (select value from string_split(@without, ',')) and HasAccess = 0)
      
      

      【讨论】:

        【解决方案4】:

        您可以先在结果表中获取您的 sql 查询,然后使用 LINQ 获取您想要的值。我知道这不是最有效的方法,但它可以工作。

                public virtual List<YOUR_DTO> ExampleOperation(YOUR_DTO dto)
                {
        
                    sqlText="SELECT * FROM EntityPermission ";
                    dbComm = db.GetSqlStringCommand(sqlText);
        
                    DataTable table = this.Database.ExecuteDataSet(dbComm).Tables[0];
        
                    List<YOUR_DTO> result = new List<YOUR_DTO>();
                    foreach (DataRow row in table.Rows)
                    {
                        result.Add(new YOUR_DTO()
                        {
                            ...
                        });
                    }
                    //LINQ
                    result = result.Where(obj => obj.CompareId == EntityPermission.CompareId).HasAccess;
                    return result;
                }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-21
          • 1970-01-01
          • 1970-01-01
          • 2013-04-11
          • 2013-10-11
          • 2021-12-17
          相关资源
          最近更新 更多