我有一个内部应用程序的搜索页面的LINQ方法。该方法如下所示
public static DataTable SearchForPerson(String FirstName, String MiddleName, String LastName, String SSN, DateTime? BirthDate)
{
var persons = (from person in context.tblPersons
where person.LastName == LastName || person.LastName.StartsWith(LastName)
join addresse in context.tblAddresses on person.PersonID equals addresse.PersonID
orderby person.LastName
select new { person.PersonID, person.LastName, person.FirstName, person.SSN, addresse.AddressLine1 });
var filteredPersonsList = persons.Where(p => p.LastName == LastName).ToList();
if (filteredPersonsList.Count == 0)
filteredPersonsList = persons.Where(p => p.LastName.StartsWith(LastName)).ToList();
var dataTable = filteredPersonsList.CopyLinqToDataTable();
return dataTable;
}
现在,正如您无疑可以看到的那样,我在创建此选项时进行了轻微监督,因为它仅按LastName
进行搜索。当我发现我可能没有正确地解决这个问题时,我正在扩展它。
所以,最后我的问题;使用一种机制(我正在考虑非空param上的SWITCH)是否更可取(读取最佳实践,更高效等等...... ) / em>)告诉我要搜索哪个参数,或者我应该简单地创建多个版本,la SearchForPersonByLastName
& SearchForPersonBySSN
?
此外,是否有一个更为精细的解决方案,我认为常见,问题?
答案 0 :(得分:2)
我是否正确理解只会使用其中一个参数进行搜索?如果是这样,那么绝对应该是单独的方法。每当您使用单词“and”或“or”描述方法(或类等)时,您可能有一个可以分解为多个方法的方法。所以听起来这种方法目前被描述为“此方法通过Person
或FirstName
或MiddleName
或LastName
或{{1}搜索SSN
s }“。所以,写方法
BirthDate
显然,这些方法之间会有一些共同的逻辑,你可以将它们分解为辅助方法。
请澄清我是否误解了,我会相应地编辑我的答案。
编辑:
好的,所以你说你可能会通过多个参数进行搜索。我仍然强烈希望为每个参数提供单独的方法(更好地分离关注点,更易于维护,更容易测试等)。这是将它们联系在一起的一种方法:
SearchByFirstName
SearchByMiddleName
SearchByLastName
SearchBySSN
SearchByBirthDate
或者:
DataTable Search(
string firstName,
string middleName,
string lastName,
string ssn,
DateTime? birthdate
) {
IQueryable<Person> query = context.tblPersons;
if(SearchParameterIsValid(firstName)) {
query = SearchByFirstName(query, firstName);
}
if(SearchParameterIsValid(middleName)) {
query = SearchByMiddleName(query, middleName);
}
if(SearchParameterIsValid(lastName)) {
query = SearchByLastName(query, lastName);
}
if(SearchParameterIsValid(ssn)) {
query = SearchBySSN(query, ssn);
}
if(birthDate != null) {
query = SearchByBirthDate(query, birthDate);
}
// fill up and return DataTable from query
}
bool SearchParameterIsValid(string s) {
return !String.IsNullOrEmpty(s);
}
IQueryable<Person> SearchByFirstName(
IQueryable<Person> source
string firstName
) {
return from p in source
where p.FirstName == firstName || p.FirstName.StartsWith(firstName)
select p;
}
// etc.
答案 1 :(得分:2)
如果我理解您的问题,那么您正尝试将其他参数添加到查询的where
子句中。我可以建议:
var persons = (from person in context.tblPersons
where (!string.IsNullOrEmpty(LastName) && (person.LastName == LastName || person.LastName.StartsWith(LastName))) &&
(!string.IsNullOrEmpty(SSN) && (person.SSN == SSN)) // && etc as needed
join addresse in context.tblAddresses on person.PersonID equals addresse.PersonID
orderby person.LastName
select new { person.PersonID, person.LastName, person.FirstName, person.SSN, addresse.AddressLine1 });
这将允许您传递任何参数组合以进行过滤,因此您不会被锁定以过滤一个参数。
答案 2 :(得分:1)
使用多种方法可以更加清晰。
如果我查看你的代码而你只使用一种方法,我就能弄清楚发生了什么,但是我必须看一下它看看你在做什么。也许一些评论有助于澄清事情等等......
但是,多种方法将完全显示您正在尝试做的事情。
正如杰森所说,一定要将公共代码分解为辅助方法。我不想在每种方法中看到相同的(或多或少)linq查询。
答案 3 :(得分:1)
您可以添加多个where子句,以便调用者可以指定要搜索的名称字段,或者为null以匹配任何内容:
var filteredPersonsList = persons
.Where(p => FirstName != null && p.FirstName == FirstName)
.Where(p => MiddleName != null && p.MiddleName == MiddleName)
.Where(p => LastName != null && p.LastName == LastName).ToList();
所以调用者可以指定:
var matches = SearchForPerson("firstName", null, "lastName", "SSN", dob);
忽略搜索中的中间名。
请注意,您可以将这些条款合并为一个使用&amp;&amp;虽然这可能难以阅读。
答案 4 :(得分:1)
你拥有的单一方法很好。
我会一次构建LINQ one where子句。这样,当您实际运行LINQ时,它只处理所需的where子句。这应该比提出的其他解决方案更有效。 LINQ很棒,因为您可以根据需要使用if逻辑逐个创建LINQ表达式然后运行它。如果可以在构建LINQ表达式时确定逻辑,则不需要将所有if逻辑放在LINQ表达式中。
我也会简化为只有StartsWith。
另外一件事,似乎filteredPersonsList过滤是多余的,因为你已经过滤了,我相信你可以摆脱这些线。
var persons = from person in context.tblPersons
select person;
if (!string.IsNullOrEmpty(FirstName))
persons = from person in persons
where person.FirstName.StartsWith(FirstName)
select person;
if (!string.IsNullOrEmpty(MiddleName))
persons = from person in persons
where person.MiddleName.StartsWith(MiddleName)
select person;
if (!string.IsNullOrEmpty(LastName))
persons = from person in persons
where person.LastName.StartsWith(LastName)
select person;
if (!string.IsNullOrEmpty(SSN))
persons = from person in persons
where person.SSN = SSN
select person;
if (BirthDate.HasValue)
persons = from person in persons
where person.BirthDate == BirthDate.Value
select person;
return (from person in persons
join address in context.tblAddresses
on person.PersonID equals address.PersonID
orderby person.LastName
select new { person.PersonID, person.LastName,
person.FirstName, person.SSN, address.AddressLine1 })
.ToList()
.CopyLinqToDataTable();
答案 5 :(得分:1)
可能想要创建一个反映某个人的对象,然后为其添加一个过滤方法:
Person.AddFilter(fieldToLimit,operator,value)
这样,您可以向对象添加任意数量的过滤条件。
示例:
Person.AddFilter(FirstName,Contains,“Bob”); Person.AddFilter(LastName,StartsWith,“Z”);
另一种方法是简单地将您的条件添加到Linq to SQL IQueryable数据类型中,以便您可以简单地:
Person.Where(t =&gt; t.FirstName.Contains(“Bob”))。其中(t =&gt; t.LastName.StartsWith(“Z”));