如何在实体框架查询中的WHERE子句中使用变量

时间:2019-05-16 11:46:53

标签: c# entity-framework

我在具有多个联接的项目中运行查询。我想为WHERE子句提供一个变量,而不是现在的硬编码,但似乎无法获得正确的语法。

var data = (from a in db.StudentData
            join b in db.Contacts on a.SID equals b.SID
            join c in db.Addresses on a.SID equals c.SID
            join d in db.EntryQuals.DefaultIfEmpty() on a.SID equals d.SID                            
            where a.SID == searchTxt
                  select new
                    {
                        ID = a.SID,
                        Birthdate = a.BIRTHDTE,
                        FirstName = a.FNAMES,
                        PreviousName = a.PREVSURNAME,                                
                        EntryQualAwardID = d.ENTRYQUALAWARDID,
                        AwardDate = d.AWARDDATE
       }).ToList();

如何使我的WHERE子句与变量(即a。[fieldVar])一起使用,其中fieldVar可能是当前代码中的“ SID”。

2 个答案:

答案 0 :(得分:1)

在处理用户可选择的搜索条件时,您需要对可能的选择进行编码。在处理构建搜索时,我建议在Linq QL语法上使用Fluent语法,因为它可以构建易于随需进行有条件修改的表达式。从那里,您可以使用Predicate&PredicateBuilder动态地组合您的WHERE条件。

Jacques解决方案可以使用,但是这种方法的缺点是您正在构建一个相当大且复杂的SQL语句,该语句有条件地应用条件。我的首选是有条件地在代码中添加WHERE子句,以确保SQL仅根据需要复杂。

如果您想进行类似智能搜索的操作(想想Google只需输入一个文本即可在多个可能的字段中进行搜索)

var whereClause = PredicateBuilder.False<StudentData>();
int id;
DateTime date;
if(int.TryParse(searchTxt, out id))
    whereClause = whereClause.Or(x => x.SID == id);
else if(DateTime.TryParse(searchTxt, out date))
    whereClause = whereClause.Or(x => x.BirthDate == date);
else
   whereClause = whereClause.Or(x => x.FirstName.Contains(searchTxt));

var data = db.StudentData
    .Where(whereClause)
    .Select(a => new
    {
        ID = a.SID,
        Birthdate = a.BIRTHDTE,
        FirstName = a.FNAMES,
        PreviousName = a.PREVSURNAME,                                
        EntryQualAwardID = a.EntryQuals.ENTRYQUALAWARDID,
        AwardDate = a.EntryQuals.AWARDDATE
    }).ToList();

这会对搜索条件进行一些基本评估,以查看其是否符合搜索目的。即如果他们可以按名称,日期或ID进行搜索并且ID是数字,那么我们仅在条件是数字的情况下搜索ID。如果它看起来像一个日期,则按日期搜索,否则按名称搜索。 (以及其他可能的可搜索字符串)

如果他们可以搜索ID,FirstName和BirthDate并输入其中一个或多个作为单独的输入字段(“搜索条件”页面),则根据他们填写的条目,您可以传递单独的可为空的参数并根据传递什么参数,或传递带有诸如Enum之类的要搜索值的搜索值列表:

即通过参数:

private void ByParameters(int? id = null, DateTime? birthDate = null, string name = null)
{
    var whereClause = PredicateBuilder.False<StudentData>();
    if(id.HasValue)
        whereClause = whereClause.Or(x => x.SID == id.Value);
    if(date.HasValue)
    {
        DateTime dateValue = date.Value.Date;   
        whereClause = whereClause.Or(x => x.BirthDate == dateValue);
    }
    if (!string.IsNullOrEmpty(name))
       whereClause = whereClause.Or(x => x.FirstName.Contains(name));

    // ....
}

如果参数数量开始变大,则可以创建一个自定义类型来封装各个可空值。即:

[Serializable]
public class SearchCriteria
{
    public int? Id { get; set; }
    public DateTime? BirthDate { get; set; }
    public string Name { get; set; }
}
private void ByParameters(SearchCriteria criteria)
{
    // ....
}

或者您可以使用条件类型和值来组成一个更具动态性的参数列表对象,但是它开始变得比它可能值得的更为复杂。

答案 1 :(得分:0)

您不能在Linq中真正做到这一点,sine linq需要在编译时知道字段的类型。一种解决方法是

where (fieldVar=="SID" && a.SID == searchTxt) || 
      (fieldVar=="FNAMES" && a.FNAMES== searchTxt) || ...

如果您进行非法比较,这也会在编译时提醒您。比较日期和字符串。