【问题标题】:Entity Framework / Linq - Get distinct values of dynamically specified propertyEntity Framework / Linq - 获取动态指定属性的不同值
【发布时间】:2013-08-19 16:34:35
【问题描述】:

我需要获取实体集合的特定属性的不同值列表。

因此,假设表 A 具有字段 x、y、z、1、2、3,其中 x 是 PK(因此不在表中)。

我需要获取 y、z、1、2 或 3 的所有唯一值,而不必在我的方法中知道要获取哪个字段。所以该方法的模式是:

public List<ObjectName> GetUniqueFieldValues(string fieldname)

“ObjectName”对象是一个有两个属性的对象,上面的方法会为每个结果填充至少一个属性。

另一个问题中的某个人使用 ParameterExpression 和 Expression 类有类似的答案,但并没有真正提供足够的信息来帮助我完成特定任务。

我也尝试过反射,但当然 Linq 不太喜欢在 Select 表达式中这样做。

我只会使用 if 并称其为好,但实际表/对象中确实有大量字段/属性,所以这是不切实际的。如果基表发生变化,这也可以为我节省一些重构。

我正在尝试做的 SQL 版本:

SELECT Distinct [usersuppliedfieldname] from TableName where [someotherconditionsexist]

我已经拥有的伪代码:

public List<ReturnObject> GetUniqueFieldValues(int FkId, ConditionObject searchmeta)
{
    using(DbEntities db = new DbEntities())
    {
        // just getting the basic set of results, notice this is "Select *"
        var results = from f in db.Table
                      where f.FkId == FkId && [some static conditions]
                      select f;

        // filtering the initial results by some criteria in the "searchmeta" object
        results = ApplyMoreConditions(results, searchmeta);

        //  GOAL - Select and return only distinct field(s) specified in searchmeta.FieldName)

    }
}

【问题讨论】:

  • 查看可能重复的stackoverflow.com/a/3469744/430661
  • 这样的查询往往不适合在 LINQ 中开始。只需在不使用查询提供程序的情况下执行查询,或者如果您愿意,也可以使用微 ORM,当您的查询本身是静态的或 EF 设计支持的动态查询时,请使用 EF。
  • @AlexPaven - 这很像我在我的问题中提到的那个对我不起作用。我将编辑帖子,更详细地说明我正在寻找的内容。
  • @Servy - 我也会调查一下,谢谢!
  • 你知道...这可能是矫枉过正。重点是进行基于元数据的搜索并根据返回的字段动态构建选项列表......如果我已经获得搜索结果,我可能可以在客户端进行所有这些过滤并为自己节省很多这里有麻烦。

标签: c# linq entity-framework-5


【解决方案1】:

您可以尝试这样的事情(类似于被建议为重复的帖子)

public static class DynamicQuerier
{
    private delegate IQueryable<TResult> QueryableMonad<TInput, TResult>(IQueryable<TInput> input, Expression<Func<TInput, TResult>> mapper);

    public static IQueryable<TResult> Select<TInput, TResult>(this IQueryable<TInput> input, string propertyName)
    {
        var property = typeof (TInput).GetProperty(propertyName);
        return CreateSelector<TInput, TResult>(input, property, Queryable.Select);
    }

    private static IQueryable<TResult> CreateSelector<TInput, TResult>(IQueryable<TInput> input, MemberInfo property, QueryableMonad<TInput, TResult> method)
    {
        var source = Expression.Parameter(typeof(TInput), "x");
        Expression propertyAccessor = Expression.MakeMemberAccess(source, property);
        var expression = Expression.Lambda<Func<TInput, TResult>>(propertyAccessor, source);
        return method(input, expression);
    }
}

对于我的测试,我创建了一组名为 Tests 的虚拟实体,下面是从 Property2 获取不同值的查询

var values = context.Tests.Select<Test, int>("Property2").Distinct();

【讨论】:

  • QueryableMonad 委托是做什么的?此外,如果您在 OP 中查看我的伪代码,您会发现当我想要获取不同的列而不是完整表时,我正在使用该“结果”变量。这个例子会这样工作吗?如果我没有先收到您的来信,我还是会试一试。
  • @Matt QueryableMonad 代表只是完整签名的简写 - 而不是 Func&lt;IEnumerable&lt;TSource&gt;, Expression&lt;Func&lt;TSource, TResult&gt;&gt;, IEnumerable&lt;TResult&gt;&gt;。只要您正在处理的变量仍然是您应该设置的IQueryable&lt;T&gt;,它就会构建查询以让数据库返回请求的特定数据,而不是在内存中执行。
  • 它看起来应该,但我还没有真正有时间去搞砸它。我放弃了甚至这样做的选择,转而支持其他事情,因为我正处于时间紧缩状态。但经过进一步评估后,无论如何我可能不得不使用它,所以我现在会标记你的答案,并在我有机会实际实施它时更新。
猜你喜欢
  • 2014-02-18
  • 2022-08-20
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 2020-11-04
  • 2010-12-13
相关资源
最近更新 更多