Хранимые процедуры Framework Entity Framework - Множественные наборы результатов с CodeFirst

Я использую приведенный ниже код для получения регулярного результата из хранимой процедуры:

var paramUserId = new SqlParameter
{
    ParameterName = "userId",
    Value = userId
};

string query = string.Format("{0} {1}",
              "SpSetFoo",
              "@userId");

var results = context.Database.SqlQuery<FooModel>(query,
                                             paramUserId);

result = results.ToList();

Между тем мне нужно получить несколько наборов результатов из другой хранимой процедуры, которые я нашел возможным в соответствии с этой документацией: http://msdn.microsoft.com/en-us/data/jj691402.aspx p >

Однако пример из Microsoft использует ADO.NET. Невозможно добиться того же результата без ADO.NET с помощью EF?

Спасибо

Ответ 1

См. эту ссылку. это сначала будет работать с EF 6.0 Code.

http://www.khalidabuhakmeh.com/entity-framework-6-multiple-result-sets-with-stored-procedures

У меня есть собственное расширение на основе указанной выше ссылки, С# 6.0, добавьте параметр и работайте с несколькими select, не требуя процедуры.

 public static class MultipleResultSets
{

    #region Public Methods
    public static MultipleResultSetWrapper MultipleResults(this DbContext db,string query,IEnumerable<SqlParameter> parameters=null) => new MultipleResultSetWrapper(db: db,query: query,parameters: parameters);
    #endregion Public Methods

    #region Public Classes
    public class MultipleResultSetWrapper
    {

        #region Public Fields
        public List<Func<DbDataReader,IEnumerable>> _resultSets;
        #endregion Public Fields

        #region Private Fields
        private readonly IObjectContextAdapter _Adapter;
        private readonly string _CommandText;
        private readonly DbContext _db;
        private readonly IEnumerable<SqlParameter> _parameters;
        #endregion Private Fields

        #region Public Constructors
        public MultipleResultSetWrapper(DbContext db,string query,IEnumerable<SqlParameter> parameters = null)
        {
            _db = db;
            _Adapter = db;
            _CommandText = query;
            _parameters = parameters;
            _resultSets = new List<Func<DbDataReader,IEnumerable>>();
        }
        #endregion Public Constructors

        #region Public Methods
        public MultipleResultSetWrapper AddResult<TResult>()
        {
            _resultSets.Add(OneResult<TResult>);
            return this;
        }

        public List<IEnumerable> Execute()
        {
            var results = new List<IEnumerable>();

            using(var connection = _db.Database.Connection)
            {
                connection.Open();
                var command = connection.CreateCommand();
                command.CommandText = _CommandText;
                if(_parameters?.Any() ?? false) { command.Parameters.AddRange(_parameters.ToArray()); }
                using(var reader = command.ExecuteReader())
                {
                    foreach(var resultSet in _resultSets)
                    {
                        results.Add(resultSet(reader));
                    }
                }

                return results;
            }
        }
        #endregion Public Methods

        #region Private Methods
        private IEnumerable OneResult<TResult>(DbDataReader reader)
        {
            var result = _Adapter
                .ObjectContext
                .Translate<TResult>(reader)
                .ToArray();
            reader.NextResult();
            return result;
        }
        #endregion Private Methods

    }
    #endregion Public Classes

}

и это пример, как его называть

var Policy = "123";
var Results=   db
        .MultipleResults($"EXEC GetPolicyInfo '{Policy}'")
        .AddResult<Driver>()
        .AddResult<Address>()
        .AddResult<Phone>()
        .AddResult<Email>()
        .AddResult<Vehicle>()
        .Execute();
        var Output= new clsPolicyInfo
        {
            Drivers = Results[0] as Driver[],
            Addresses = Results[1] as Address[],
            Phones = Results[2] as Phone[],
            Emails = Results[3] as Email[],
            Vehicles = Results[4] as Vehicle[]
        };

Ответ 2

Это старая тема, но добавление комментариев здесь просто на случай, если кому-то это понадобится. Мне нужно было использовать хранимую процедуру, которая возвращала две таблицы из другой базы данных, а затем после обработки возвращаемых данных, хранящихся в нашей базе данных приложений. Обращался к стандартной документации и выполнял шаги, но не понравился. Сначала были проблемы, и код обнаружил некоторое подбрюшье, что не было хорошей идеей с точки зрения ремонтопригодности.

То, что пакет Nuget, разработанный специально для обработки SP, входит в картину. Посмотрите CodeFirstStoredProcs. Блестящий пакет с очень специфическим фокусом и отлично работает. Это возвращает коллекцию объектов для каждого результирующего набора хранимой процедуры, которая затем может быть использована любым способом. Они являются хорошей и последовательной поддержкой для разных версий EF, включая версию 6. Также проверьте описание кода Code First Stored Procedures. Загруженный исходный код имеет даже PDF-документ, в котором объясняется, как использовать его в подробных шагах.

Большое спасибо автору aureolin.

Ответ 3

Однако пример от Microsoft использует ADO.NET. Невозможно достичь того же результата без ADO.NET, используя вместо этого EF?

Entity Framework является частью ADO.NET... этот документ, который вы связали, показывает вам, что вы хотите с помощью ADO.NET Entity Framework. В примере используется сырая команда sql для выполнения хранимой процедуры (нет смысла писать запрос LINQ, если вы уже написали свою процедуру SQL). Смотрите здесь:

Основной целью будущей версии ADO.NET является повышение уровня абстракции для программирования данных, что помогает устранить несоответствие импеданса между моделями данных и между языками, с которыми разработчикам приложений пришлось бы иметь дело в противном случае. Два нововведения, делающие этот шаг возможным, - это встроенный в язык запрос и ADO.NET Entity Framework. Entity Framework существует как новая часть семейства технологий ADO.NET. ADO.NET будет включать LINQ для многих компонентов доступа к данным: LINQ to SQL, LINQ to DataSet и LINQ to Entities.


Код:

Непонятно, какие наборы результатов вы возвращаете из своей процедуры: SpSetFoo... имя SpSetFoo предполагает, что процедура обновляет Foo в БД. Для упрощения я предполагаю, что у вас есть процедура с именем GetFooAndBarForUser:

CREATE PROCEDURE [dbo].[GetFooAndBarForUser] (@userId int)
AS
    SELECT * FROM Foo F WHERE F.UserId = @userId
    SELECT * FROM Bar B WHERE B.UserId = @userId

Вот как вы можете прочитать обе модели:

public void GetTwoResultSetsForUserId(int userId)
{
    using (var db = new MyDbContext())
    {
        // Create a SQL command and add parameter
        var cmd = db.Database.Connection.CreateCommand();
        cmd.CommandText = "[dbo].[GetFooAndBarForUser]";
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new SqlParameter("@userId", userId));

        // execute your command
        db.Database.Connection.Open();
        var reader = cmd.ExecuteReader();

        // Read first model --> Foo
        var blogs = ((IObjectContextAdapter)db)
            .ObjectContext
            .Translate<Foo>(reader, "Foo", MergeOption.AppendOnly);

        // move to next result set
        reader.NextResult();

        // Read second model --> Bar
        var bar = ((IObjectContextAdapter)db)
            .ObjectContext
            .Translate<Post>(reader, "Bar", MergeOption.AppendOnly);
    }
}      

Ответ 4

Нормализуйте свою базу данных, вы получите лучшие результаты!