[英]Code-First Entity Framework w/ Stored Procedure returning results from complex Full-text Searches
我正在尋找以下場景的設計建議:
我有一個代碼優先的EF5 MVC應用程序。 我正在構建一個全文搜索功能,它將包含來自許多表的多個加權列。 由於我無法使用這些表中的索引創建視圖(其中一些包含文本/二進制列),因此我創建了一個存儲過程,該過程將輸出我的對象的ID(例如PersonID
)以及與該對象關聯的排名。搜索條件。
我目前的方法是創建一個輔助類來執行全文搜索,該搜索調用存儲過程並根據返回的ID加載來自上下文的所有對象。
我的問題是:
UPDATE
將我的詳細實現從問題編輯轉移到自己的答案中,更符合經常推薦的內容@ meta.stackexchange.com
請記住,以下只是一個例子:
public List<Person> GetPeople(params string[] p)
{
var people = new List<Person>();
using (var db = new DataContext())
{
var context = ((IObjectContextAdapter)db).ObjectContext;
db.Database.Connection.Open();
var command = db.Database.Connection.CreateCommand();
command.CommandText = "SomeStoredProcedureReturningWeightedResultSetOfPeople";
command.CommandType = System.Data.CommandType.StoredProcedure;
//Add parameters to command object
people = context.Translate<Person>(command.ExecuteReader()).ToList();
}
return people;
}
盡管storedprocedure將具有權重值的列,但在翻譯時它將不會被映射。 如果需要,您可以從Person派生一個包含權重值的類。
將此作為答案而不是編輯我的問題:
獲取@ Drauka(和谷歌)提供的一些見解就是我最初的迭代所做的。
我使用存儲過程的結果中的總計和分頁信息填充結果對象,然后只加載當前結果頁面的實體:
int[] projectIDs = new int[Settings.Default.ResultsPerPage]; foreach (ProjectFTS_DTO dto in RankedSearchResults .Skip(Settings.Default.ResultsPerPage * (pageNum - 1)) .Take(Settings.Default.ResultsPerPage)) { projectIDs[index] = dto.ProjectID; index++; } IEnumerable<Project> projects = _repository.Projects .Where(o=>projectIDs.Contains(o.ProjectID));
全面實施 :
由於這個問題得到了很多觀點,我認為在發布我的最終解決方案的更多細節以供其他人幫助或可能的改進時可能是值得的。
完整的解決方案如下:
DatabaseExtensions類:
public static class DatabaseExtensions {
public static IEnumerable<TResult> ExecuteStoredProcedure<TResult>(
this Database database,
IStoredProcedure<TResult> procedure,
string spName) {
var parameters = CreateSqlParametersFromProperties(procedure);
var format = CreateSPCommand<TResult>(parameters, spName);
return database.SqlQuery<TResult>(format, parameters.Cast<object>().ToArray());
}
private static List<SqlParameter> CreateSqlParametersFromProperties<TResult>
(IStoredProcedure<TResult> procedure) {
var procedureType = procedure.GetType();
var propertiesOfProcedure = procedureType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var parameters =
propertiesOfProcedure.Select(propertyInfo => new SqlParameter(
string.Format("@{0}",
(object) propertyInfo.Name),
propertyInfo.GetValue(procedure, new object[] {})))
.ToList();
return parameters;
}
private static string CreateSPCommand<TResult>(List<SqlParameter> parameters, string spName)
{
var name = typeof(TResult).Name;
string queryString = string.Format("{0}", spName);
parameters.ForEach(x => queryString = string.Format("{0} {1},", queryString, x.ParameterName));
return queryString.TrimEnd(',');
}
public interface IStoredProcedure<TResult> {
}
}
用於保存存儲過程輸入的類:
class AdvancedFTS :
DatabaseExtensions.IStoredProcedure<AdvancedFTSDTO> {
public string SearchText { get; set; }
public int MinRank { get; set; }
public bool IncludeTitle { get; set; }
public bool IncludeDescription { get; set; }
public int StartYear { get; set; }
public int EndYear { get; set; }
public string FilterTags { get; set; }
}
結果對象:
public class ResultsFTSDTO {
public int ID { get; set; }
public decimal weightRank { get; set; }
}
最后調用存儲過程:
public List<ResultsFTSDTO> getAdvancedFTSResults(
string searchText, int minRank,
bool IncludeTitle,
bool IncludeDescription,
int StartYear,
int EndYear,
string FilterTags) {
AdvancedFTS sp = new AdvancedFTS() {
SearchText = searchText,
MinRank = minRank,
IncludeTitle=IncludeTitle,
IncludeDescription=IncludeDescription,
StartYear=StartYear,
EndYear = EndYear,
FilterTags=FilterTags
};
IEnumerable<ResultsFTSDTO> resultSet = _context.Database.ExecuteStoredProcedure(sp, "ResultsAdvancedFTS");
return resultSet.ToList();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.