【问题标题】:Cannot perform LINQ complex object search in Entity Framework无法在实体框架中执行 LINQ 复杂对象搜索
【发布时间】:2016-10-13 15:38:03
【问题描述】:

我在数据库中有实体,每个实体都包含一个键值对列表作为元数据。我想通过匹配元数据中的指定项目来返回对象列表。

即如果对象可以具有 KeyOne、KeyTwo 和 KeyThree 的元数据,我希望能够说“将 KeyOne 包含“abc”且 KeyThree 包含“de”的所有对象带回来

这是我的 C# 查询

 var objects = repository.GetObjects().Where(t =>
                    request.SearchFilters.All(f =>
                        t.ObjectChild.Any(tt =>
                            tt.MetaDataPairs.Any(md =>
                                md.Key.ToLower() == f.Key.ToLower() && md.Value.ToLower().Contains(f.Value.ToLower())
                            )
                        )
                    )
                ).ToList();

这是我的请求类

[DataContract]
public class FindObjectRequest
{
    [DataMember]
    public IDictionary<string, string> SearchFilters { get; set; }
}

最后是我的元数据 POCO

[Table("MetaDataPair")]
    public class DbMetaDataPair : IEntityComparable<DbMetaDataPair>
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { get; set; }

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

        public string Value { get; set; }
}

我得到的错误是

错误是无法创建类型的常量值 'System.Collections.Generic.KeyValuePair`2[[System.String, mscorlib, 版本=4.0.0.0,文化=中性, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, 版本=4.0.0.0,文化=中性,PublicKeyToken=b77a5c561934e089]]'。 仅支持原始类型或枚举类型 上下文。

【问题讨论】:

  • 这里的问题不在您帖子中的代码中。在执行查询之前,您正在其他地方转换为KeyValuePair&lt;string, string&gt;。您能找到执行此操作的代码并将其发布吗?
  • 我认为这是您可以在 C# 查询中看到的字典“request.SearchFilters”。我认为 EF 将 Dictionary 转换为 IList
  • 哦,等等,您没有转换 - 您在 Any()f 中使用了 kvp。使用前将f.Keyf.Value 保存到局部变量中
  • 我将假设您正在使用 Sql Server 并且您的 Collation 设置为 CI(默认),在这种情况下,所有 ToLower() 调用都是多余的。

标签: c# sql entity-framework linq


【解决方案1】:

所以看起来您查询中的f 变量是KeyValuePair&lt;string, string&gt;。您需要做的是在使用它们之前将它们保存为局部变量,因为 KVP 无法转换为 SQL。

var filters = request.SearchFilters.Select(kvp => new[] { kvp.Key, kvp.Value }).ToArray();

var objects = repository.GetObjects().Where(t =>
    filters.All(f =>
        t.ObjectChild.Any(tt =>
            tt.MetaDataPairs.Any(md =>
                md.Key.ToLower() == f[0] && md.Value.ToLower().Contains(f[1])
                )
            )
         )
    ).ToList();

你必须记住的是,当它仍然是 IQueryable&lt;T&gt; 类型时,你在 EF 中的 LINQ 中所做的任何事情 - 在你调用 ToList()ToArray()ToDictionary() 甚至可能是 AsEnumerable() 之前(老实说,我从未尝试过AsEnumerable()) - 必须能够表示为 SQL。这意味着只有在您的DbContext 中定义的 SQL 类型(字符串、int、long、字节、日期等)和实体类型可以在查询中使用。其他所有内容都需要分解为其中一种形式。

编辑:
您也可以尝试从查询的另一端来,但首先您需要做一些事情..

模型 ...

[Table("MetaDataPair")]
public class DbMetaDataPair : IEntityComparable<DbMetaDataPair>
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

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

    public string Value { get; set; }

    // this is the navigation property back up to the ObjectChild
    public virtual ObjectChild ObjectChild { get;set; }
}

public ObjectChild
{
    ...
    public ICollection<MetaDataPair> MetaDataPairs { get; set; }

    // this is the navigation property back up to the "Object"
    public virtual Object Object { get; set; }
    ...
}

现在开始查询...

public IEnumerable<Object> GetObjectsFromRequest(FindObjectRequest request)
{
    foreach(var kvp in request.SearchFilters)
    {
        var key = kvp.Key;
        var value = kvp.Value;

        yield return metaDataRepository.MetaDataPairs
            .Where(md => md.Key.ToLower() == key && md.Value.ToLower().Contains(value))
            .Select(md => md.ObjectChild.Object)
    }
}

这应该针对您需要匹配的元对数量执行“n”个 SQL 查询。更好的选择是尝试以某种方式联合它们,但没有一些代码可以使用,这可能是一项任务。

附带说明:我真的不知道您的课程名称,所以我使用了 >> 我能解决的问题。显然Object不是模特的名字..

【讨论】:

  • f 是一个 IList> - 所以会有不止一个。这就是问题所在。
  • 感谢您的编辑。我现在得到{“LINQ to Entities 不支持 LINQ 表达式节点类型 'ArrayIndex'。”}
  • 我们可以从另一个方向来吗?如获取首先匹配的MetaData,然后获取Object?
  • 实际上您的编辑代码并没有做有问题的提及。因此,您编写代码:(将 KeyOne 包含“abc”OR KeyThree 包含“de”的所有对象返回给我),但有问题 AND 已指定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-05
  • 2014-03-29
  • 1970-01-01
  • 2015-01-06
  • 1970-01-01
相关资源
最近更新 更多