Закодируйте Первую Структуру Предприятия w/Хранимая процедура, возвратив результаты сложных Полнотекстовых Поисков

Я ищу совет дизайна для следующего сценария:

У меня есть код первое применение EF5 MVC. Я строю полнотекстовую функцию поиска, которая включит многочисленные взвешенные колонки от многих столов. Поскольку я не могу создать представление с индексом от этих столов (некоторые из них содержат текст/столбцы двоичных данных), я создал хранимую процедуру, которая произведет ID моего объекта (например, PersonID ) и разряд, связанный с этим основанным на объектах на критериях поиска.

Мой текущий подход должен создать класс помощника для выполнения полнотекстовых поисков, которые называют хранимую процедуру (процедуры) и загружают все объекты от контекста на основе возвращенных ID.

Мои вопросы:

  1. мой подход кажется разумным/следует разумной наиболее успешной практике?
  2. кто-либо еще сделал что-то похожее с какими-либо извлеченными уроками?
  3. - там способ сделать это более эффективно (т.е. иметь результаты возвращения/карты хранимой процедуры к предприятиям непосредственно без дополнительного требуемого поиска?)

ОБНОВЛЕНИЕ

Перемещенный мое подробное внедрение от того, чтобы редактировать вопроса в его собственный ответ, чтобы быть больше в соответствии с тем, что часто рекомендуется meta.stackexchange.com

16
nl ja de

2 ответы

  1. Видя, поскольку вы не можете использовать методы SQL как containstable с entityframework, кодирует сначала, какая остальная часть вашего заявления могла использовать вас, мог быть 'вынужден' сделать что-то с storedprocedure как ваш описывать. Является ли это наиболее успешной практикой, я не знаю. Однако, это, это сделало работу, я не вижу, почему это не было бы разумно.
  2. Да - я имею, и все еще работаю над проектом, строят вокруг EF codefirst, где я должен был сделать довольно сложный поиск, который включал несколько параметров поиска, отмеченных, как 'должен иметь' и несколько ценностей, отмеченных как 'хороший иметь' и в от того возвращения взвешенный результат.
  3. В зависимости от сложности набора результатов, я не думаю, что необходимо сделать вторую поездку туда и обратно к базе данных и я покажу вам способ, которым я делал его ниже.

Примите во внимание, что ниже просто пример:

    public List GetPeople(params string[] p)
    {
        var people = new List();

        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(command.ExecuteReader()).ToList();
        }

        return people;
    }

Даже при том, что у storedprocedure будет колонка для значения веса, это не будет нанесено на карту, когда вы переведете его. Вы могли потенциально получить класс от Человека, который включает значение веса, если вам было нужно оно.

13
добавлено

Регистрация этого как ответ, а не редактировать к моему вопросу:

Беря часть понимания, обеспеченного @Drauka (и Google), вот то, что я сделал для своего начального повторения.

  1. Created the stored procedure to do the full text searching. It was really too complex to be done in EF even if supported (as one example some of my entities are related via business logic and I wanted to group them returning as a single result). The stored procedure maps to a DTO with the entity id's and a Rank.
  2. I modified this blogger's snippet/code to make the call to the stored procedure, and populate my DTO: http://www.lucbos.net/2012/03/calling-stored-procedure-with-entity.html
  3. I populate my results object with totals and paging information from the results of the stored procedure and then just load the entities for the current page of results:

    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 projects = _repository.Projects
                .Where(o=>projectIDs.Contains(o.ProjectID));
    

Full Implementation:

Поскольку этот вопрос получает много взглядов, я думал, что может иметь смысл отправлять больше деталей моего конечного решения для помощи других или возможного улучшения.

Полное решение похоже:

Класс 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().ToArray());
    }

    private static List 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 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> {
    }
}

Класс, чтобы держать сохраненные исходные данные proc:

class AdvancedFTS : 
         DatabaseExtensions.IStoredProcedure {
    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 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 resultSet = _context.Database.ExecuteStoredProcedure(sp, "ResultsAdvancedFTS");
        return resultSet.ToList();

    }
11
добавлено
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot