Return objects with populated list properties from stored procedure

后端 未结 2 1663
深忆病人
深忆病人 2021-01-26 09:10

I\'m new to SQL Server stored procedures, so apologies if I\'m being an idiot. I would like to use a stored procedure to return a list of objects, each of which has a property c

相关标签:
2条回答
  • 2021-01-26 10:06

    Here is your most basic type of ORM mapper.

    Well, most basic, with some maintainability and readability in mind.

    I would hit the database ONCE, but have multiple resultsets in your stored procedure. And look into the IDataReader.NextResult

    (as seen here LINK )

    Below is some basic ORM.

    [Serializable]
    public partial class Answer
    {
        public int AnswerKey { get; set; }                   
        public int ParentQuestionID { get; set; }
        public string AnswerText { get; set; }                   
    
        public Question ParentQuestion  { get; set; }    
    
    }
    
    internal static class AnswerDefaultLayout
    {
        public static readonly int AnswerKey = 0;
        public static readonly int ParentQuestionID = 1;
        public static readonly int AnswerText = 2;
    
    }
    
    public class AnswerSerializer
    {
        public ICollection<Answer> SerializeAnswers(IDataReader dataReader)
        {
            Answer item = new Answer();
            ICollection<Answer> returnCollection = new List<Answer>();
    
                int fc = dataReader.FieldCount;//just an FYI value
    
                int counter = 0;//just an fyi of the number of rows
    
                while (dataReader.Read())
                {
    
                    if (!(dataReader.IsDBNull(AnswerDefaultLayout.AnswerKey)))
                    {
                        item = new Answer() { AnswerKey = dataReader.GetInt32(AnswerDefaultLayout.AnswerKey) };
    
                        if (!(dataReader.IsDBNull(AnswerDefaultLayout.ParentQuestionID)))
                        {
                            item.ParentQuestionID = dataReader.GetInt32(AnswerDefaultLayout.ParentQuestionID);
                        }
    
                        if (!(dataReader.IsDBNull(AnswerDefaultLayout.AnswerText)))
                        {
                            item.AnswerText = dataReader.GetString(AnswerDefaultLayout.AnswerText);
                        }
    
    
                        returnCollection.Add(item);
                    }
    
                    counter++;
                }
    
                return returnCollection;
    
        }
        }
    
    
    [Serializable]
    public class Question
    {
        public int QuestionID { get; set; }
        public string Question { get; set; }
        public ICollection<Answer> Answers { get; set; }
    }
    
    internal static class QuestionDefaultLayout
    {
        public static readonly int QuestionID = 0;
        public static readonly int QuestionText = 1;
    }
    
    
    public class QuestionSerializer
    {
        public ICollection<Question> SerializeQuestions(IDataReader dataReader)
        {
            Question item = new Question();
            ICollection<Question> returnCollection = new List<Answer>();
    
    
                int fc = dataReader.FieldCount;//just an FYI value
    
                int counter = 0;//just an fyi of the number of rows
    
                while (dataReader.Read())
                {
    
                    if (!(dataReader.IsDBNull(QuestionDefaultLayout.QuestionID)))
                    {
                        item = new Question() { QuestionID = dataReader.GetInt32(QuestionDefaultLayout.QuestionID) };
    
                        if (!(dataReader.IsDBNull(QuestionDefaultLayout.LAST_NAME)))
                        {
                            item.LastName = dataReader.GetString(QuestionDefaultLayout.LAST_NAME);
                        }
    
    
    
                        returnCollection.Add(item);
                    }
    
                    counter++;
                }
    
                return returnCollection;
    
    
        }
    }
    
    
    
    
    
    
    public class QuestionManager
    {
    
        public ICollection<Question> GetAllQuestionsWithChildAnswers()
        {
    
        String myConnString  = "User ID=<username>;password=<strong password>;Initial Catalog=pubs;Data Source=myServer";
        SqlConnection myConnection = new SqlConnection(myConnString);
        SqlCommand myCommand = new SqlCommand();
        SqlDataReader myReader ;
    
        myCommand.CommandType = CommandType.StoredProcedure;
        myCommand.Connection = myConnection;
        myCommand.CommandText = "dbo.uspQuestionAndAnswersGetAll";
        int RecordCount=0; 
    
        try
        {
            myConnection.Open();
            myReader = myCommand.ExecuteReader();
    
            ICollection<Question> questions = new QuestionSerializer().SerializeQuestions(myReader);
    
            myReader.NextResult();
    
            ICollection<Answer> answers = new AnswerSerializer().SerializeAnswers(myReader);
    
            questions = this.MergeQuestionObjectGraphs(questions, answers);
    
        catch(Exception ex) 
        {
           MessageBox.Show(ex.ToString());
        }
        finally
        {
        if (null != myReader)
        {
            myReader.Close();
        }
        if (null != myConnection)
        {
            myConnection.Close();
        }
        }
        }
    
            private ICollection<Question> MergeQuestionObjectGraphs(ICollection<Question> qtions, ICollection<Answer> aners)
            {
                if (null != qtions && null != aners)
                {
                    foreach (Question qtn in qtions)
                    {
                        IEnumerable<Answer> foundLinks = aners.Where(lnk => lnk.ParentQuestionId == qtn.QuestionId);
                        if (null != foundLinks)
                        {
                            foreach (Answer link in foundLinks)
                            {
                                link.ParentQuestion = qtn;
                            }
    
                            qtn.Answers = foundLinks.ToList();
                        }
                    }
                }
    
                return qtions;
            }
    
    }
    

    TSQL

    CREATE PROC dbo.uspQuestionAndAnswersGetAll
    AS
        SELECT QuestionId, QuestionText FROM dbo.Question
        SELECT AnswerId, QuestionId, AnswerText FROM dbo.Answer
    GO 
    
    0 讨论(0)
  • 2021-01-26 10:08

    Actually a stored procedure delivers a relational result rather than objects. As an alternative, you could return XML using FOR XML and deserialize it into objects. Mapping this to objects is usually done using an O/R mapper.

    You can use datasets and table adapters to get the relational data into your applications. Once loaded into the dataset, you can populate your Question and Answer objects.

    Here is a sample toy code to fill the result of a stored procedure into a data set:

    var ds = new DataSet();
    
    using (var cn = new SqlConnection())
    using (var cmd = new SqlCommand("myStoredProcedure", cn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
    
        using (var adapter = new SqlDataAdapter(cmd))
        {
            adapter.TableMappings.Add("Table0", "Answers");
            adapter.TableMappings.Add("Table1", "Questions");
    
            adapter.Fill(ds);
        }
    }
    

    For actual development I'd suggest you to use a Typed Dataset and a proper SqlConnection. However, as comments pointed out too, use EF or another O/R mapper if you can.

    0 讨论(0)
提交回复
热议问题