#sql #asp.net-mvc-3 #entity-framework
#sql #asp.net-mvc-3 #entity-framework
Вопрос:
У меня есть приложение MVC 3, работающее с базой данных MS SQL 2008 с таблицей с именем Documents. Документы в базе данных разбиты по абзацам. В таблице Documents есть столбец DocText, содержащий текст каждого абзаца, столбец DocTitle, содержащий заголовок документа. В моем приложении MVC 3 есть функция поиска, которая может выполнять поиск слова или фразы в столбце DocText или в столбце DocTitle. Все работает нормально, за исключением того, что если в определенном документе слово для поиска встречается в нескольких абзацах, мой список возвращает несколько экземпляров этого документа. Например, если пользователь выполняет поиск по слову «Бюджет», а в одном из документов слово «бюджет» встречается в четырех разных абзацах, в моем возвращенном списке этот документ указан четыре раза.
Чего я хочу добиться, так это перечислить каждый документ, в котором есть искомое слово. Я хочу перечислить документ по названию только один раз, независимо от того, сколько раз поисковое слово встречается в этом документе. Единственный столбец, который действительно уникален, — это столбец RecordID, первичный ключ.
Мой контроллер:
public class SearchController : Controller
{
private GUICEEntities4 db = new GUICEEntities4();
//
// GET: /Search/
public ActionResult Index(string Keyword)
{
#region Keyword Search
if (!String.IsNullOrEmpty(Keyword)) {
var SearchDoc = db.Documents.Where(r => r.DocText.ToUpper().Contains(Keyword.ToUpper()) || r.Title.ToUpper().Contains(Keyword.ToUpper()) || r.DocNum.ToUpper().Contains(Keyword.ToUpper()));
ViewBag.CurrentKeyword = String.IsNullOrEmpty(Keyword) ? "" : Keyword;
return View(SearchDoc.ToList());
}
else{
return View();
}
#endregion
}
}
Мое представление имеет следующее:
@foreach (var item in Model) {
<tr>
<td>
<strong>AFI @Html.DisplayFor(modelItem => item.DocNum): @Html.DisplayFor(modelItem => item.Title)</strong>
<br />
@Html.DisplayFor(modelItem => item.DocSummary)
<br />
<span class="complianceitems">Number of compliance items:</span> (TBD)
</td>
<td>
<a href="/Documents/Index/@(Html.DisplayFor(modelItem => item.DocNum))">Checklist
Generator</a><br />
<a href="/UploadedDocs/@Html.DisplayFor(modelItem => item.DocFileName)" target="_blank">
Download PDF</a>
</td>
Есть предложения о том, как я могу достичь своей цели?
ДОБАВЛЕНО: Каждый документ может быть идентифицирован по столбцу DocNum, который имеет уникальный номер документа для этого конкретного документа. Я попытался выполнить итерацию по списку, чтобы извлечь каждый не отвечающий требованиям документ, а затем попытаться сделать так, чтобы этот документ больше не появлялся в цикле … но мне это не удалось.
Следующий оператор SQL дает мне нужные результаты. В инструкции предполагается, что искомое слово — «бюджет». Я не знаю, как получить те же результаты, используя EF. Есть предложения?
SELECT DISTINCT DocNum, Title FROM Documents
WHERE
DocText LIKE '%budget%'
OR
Documents.Title LIKE '%budget%'
OR
DocNum LIKE '%budget%'
Ответ №1:
Проблема здесь в вашем запросе EF, а не в чем-либо, связанном с MVC. Прошло некоторое время с тех пор, как я активно использовал EF, но самым простым способом, вероятно, было бы сначала вернуть только идентификаторы записей.
var recordIds= db.Documents
.Where(r =>
r.DocText.ToUpper().Contains(Keyword.ToUpper()) ||
r.Title.ToUpper().Contains(Keyword.ToUpper()) ||
r.DocNum.ToUpper().Contains(Keyword.ToUpper()))
.Select(d => d.RecordId)
.Distinct();
Я не совсем уверен, что вы будете делать с каждой отдельной записью с этого момента, поскольку в вашем вопросе недостаточно информации. Но это должно помочь.
Обновить:
var foundDocs = new List<YourType>();
recordIds.ToList().ForEach(r => foundDocs.Add(db.TblDocLists.Single(l => l.TheDocNum == r)));
//I must point out that I'm not familiar with the latest versions of EF so this might be overkill.
Комментарии:
1. Это приближает меня. Я использовал ваш код, но изменил RecordID на DocNum, что даст мне номер документа для каждого документа, в котором было найдено искомое слово.
2. Я исправил свой вопрос, чтобы показать изменения, которые я внес на основе вашего предложения.
3. Проблема здесь в том, что
SearchDoc
этоIQueryable<>
, а EF не поддерживает извлечение этих записей.