c# - 尝试使用 LINQ 以数据库字段作为参数获取不同的值

标签 c# asp.net sql-server entity-framework linq

我正在尝试使用 Linq 查询从 MsSQL 数据库中选择不同的值 并将数据库字段作为标准传递,但它给了我错误。

如果一个表有如下数据:

Name | Age | Class | school
----------------------------
Anna,     23, grade 2, Havard
Kendricks,34, grade 2, Havard
Vikander, 27, grade 3, Covenant
Hathaway, 18, grade1,  Covenant
Gemma,    23, grade 4, Bowen
Jolie,    23, grade 5, Havard
Arteton,  24, grade 1, Bayero
Ana Armas 30, grade 2, Coventry

现在,我试图从上表中通过传递“学校”或“类(class)”或更多字段来检索数据,然后返回基于这些字段的不同值。我该怎么做?

// filterParam - is the field(class, school)
// then how do I select the distinct values...

下面是我的代码:

  public IEnumerable<ScbDataInfo> GetScbOptionsByFilter(string filterParam) {
            using (SRSContext entityContext = new SRSContext()) {

                var query = (from e in entityContext.Set<ScbDataInfo>()

                             where e[filterParam] == searchParam   //i passed it here
                             orderby e.RefNo, e.datepmt                             
                             select e).Distinct();

                return query.ToArray();

            }
        }

最佳答案

这是一些代码,我前段时间从 DataTables.Queryable 拼凑而成的通过 Alexander Krutov行货MIT :

这通过表达式工作,在您调用 ToArray 之前不需要具体化您的数据。由你自己:

/// <summary>
/// Creates predicate expression like 
/// <code>(T t) => t.SomeProperty.Contains("Constant")</code> 
/// where "SomeProperty" name is defined by <paramref name="stringConstant"/> parameter, and "Constant" is the <paramref name="stringConstant"/>.
/// If property has non-string type, it is converted to string with <see cref="object.ToString()"/> method.
/// </summary>
/// <typeparam name="T">Data type</typeparam>
/// <param name="propertyName">Property name</param>
/// <param name="stringConstant">String constant to construnt the <see cref="string.Contains(string)"/> expression.</param>
/// <param name="caseInsensitive">Case insenstive Contains Predicate?</param>
/// <returns>Predicate instance</returns>
public static Expression<Func<T, bool>> BuildStringContainsPredicate<T>(string propertyName, string stringConstant, bool caseInsensitive)
{
    var type = typeof(T);
    var parameterExp = Expression.Parameter(type, "e");
    var propertyExp = BuildPropertyExpression(parameterExp, propertyName);

    Expression exp = propertyExp;

    // if the property value type is not string, it needs to be casted at first
    if (propertyExp.Type != typeof(string))
    {
        // If we have an Enum, the underlying Entity Framework Provider can not translate the Enum to SQL.
        // Therefore we converting it first to the underlying primitive type (byte, int16, int32, int64 etc)
        //Todo: Sideeffects beobachten
        //Todo: Evtl möglichkeit finden Display Attribute zu implementieren um eine String Suche zu ermöglichen?
        //Todo: Notwendigkeit in NET Core 2.1 überprüfen
        if (propertyExp.Type.IsEnum)
        {
            exp = Expression.Convert(exp, Enum.GetUnderlyingType(propertyExp.Type));
        }

        exp = Expression.Call(exp, ObjectToString);
    }

    // call ToLower if case insensitive search
    if (caseInsensitive)
    {
        exp = Expression.Call(exp, StringToLower);
        stringConstant = stringConstant.ToLower();
    }
    var someValue = Expression.Constant(stringConstant, typeof(string));
    var containsMethodExp = Expression.Call(exp, StringContains, someValue);
    return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}

/// <summary>
/// Builds the property expression from the full property name.
/// </summary>
/// <param name="param">Parameter expression, like <code>e =></code></param>
/// <param name="propertyName">Name of the property</param>
/// <returns>MemberExpression instance</returns>
private static MemberExpression BuildPropertyExpression(ParameterExpression param, string propertyName)
{
    var parts = propertyName.Split('.');
    Expression body = param;
    foreach (var member in parts)
    {
        body = Expression.Property(body, member);
    }
    return (MemberExpression)body;
}

/// <summary>
/// <see cref="object.ToString()"/> method info. 
/// Used for building search predicates when the searchable property has non-string type.
/// </summary>
private static readonly MethodInfo ObjectToString = typeof(object).GetMethod(nameof(ToString));


/// <summary>
/// <see cref="string.ToLower()"/> method info. 
/// Used for conversion of string values to lower case.
/// </summary>
private static readonly MethodInfo StringToLower = typeof(string).GetMethod(nameof(string.ToLower), new Type[] { });

/// <summary>
/// <see cref="string.Contains(string)"/> method info. 
/// Used for building default search predicates.
/// </summary>
private static readonly MethodInfo StringContains = typeof(string).GetMethod(nameof(string.Contains), new[] { typeof(string) });

这将创建一个过滤器表达式,其中 propertyName是列,stringConstant搜索值和 bool,如果搜索应该区分大小写或不区分大小写。 T是你的类型 IQueryable<T> .

PredicateBuilder 你可以这样做:

public static IQueryable<T> FilterColumns(this IQueryable<T> query, IEnumerable<string> columns, string searchValue)
{
    Expression<Func<T, bool>> predicate = null;
    foreach (var column in columns)
    {
        var expr = BuildStringContainsPredicate<T>(column,
                       searchValue, false);
        predicate = predicate == null ? PredicateBuilder.Create(expr) : predicate.Or(expr);
    }
    return query.Where(predicate);
}

这提供了一个扩展方法,因此包含的类必须是静态的。

现在您可以执行以下操作:

entityContext.ScbDataInfos
    .FilterColumns(columnNames, searchValue)
    .OrderBy(e => e.RefNo)
    .ThenBy(e => e.datepm)
    .Distinct()
    .ToArray();

关于c# - 尝试使用 LINQ 以数据库字段作为参数获取不同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57729824/

相关文章:

c# - 如何在 C# 中将数组添加到 SQL 行?

asp.net - 控制可见属性的数据绑定(bind)函数不起作用

sql-server - 是否有一种简单的方法可以将数据从多个 excel 苍蝇导入 SQL,包括使用 SSIS 的文件名?

sql-server - 两个选择的公共(public)组,sql server

c# - 在字符串中存储 SQL 函数值

c# - 显示存储的位少于分配的位的 DICOM monochrome2

java - 从 Java 使用 ASP.NET 表单例份验证

asp.net - 我使用了 css,现在无法滚动

sql - 如何在 SQL Server 的 where 子句中使用 sum 函数?

c# - TransformedBitmap 缩放模式