[英]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.