【问题标题】:Return objects with populated list properties from stored procedure从存储过程返回具有填充列表属性的对象
【发布时间】:2013-05-13 13:37:42
【问题描述】:

我是 SQL Server 存储过程的新手,如果我是个白痴,我深表歉意。我想使用一个存储过程来返回一个对象列表,每个对象都有一个包含相关对象列表的属性。例如

public class Question
{
    public int QuestionID { get; set; }
    public string Question { get; set; }
    public List<Answer> Answers { get; set; }
}

public class Answer
{
    public int AnswerID { get; set;}
    public int QuestionID { get; set; }
    public string Answer { get; set;}
}

我想编写一个存储过程,它返回一个问题列表,每个问题的 Answers 属性都填充了相关的 Answer 对象。

非常感谢任何帮助!

谢谢,

戴夫

【问题讨论】:

  • 实体框架会为你做这件事,否则它必须是一个手动过程
  • 有什么理由使用存储过程而不是实体框架之类的吗?
  • @DGibbs 是的。只询问存储过程是否真的可行
  • 它可能,但实施取决于您计划在客户端使用什么?实体框架、其他一些 ORM、ADO.NET DataSet、DataReader....
  • 是的,这会起作用,这里有两种方法:1. 返回 2 个结果集(一个带有问题,一个带有所有相关答案)或 2. 调用 sprocs 来获取问题,然后调用每个问题答案的第二个存储过程...... - 第一个意味着您可以更有效地获取数据但需要一些处理,第二个有更多的数据库命中

标签: c# .net sql-server stored-procedures


【解决方案1】:

实际上,存储过程传递的是关系结果,而不是对象。作为替代方案,您可以使用 FOR XML 返回 XML 并将其反序列化为对象。通常使用 O/R 映射器将其映射到对象。

您可以使用数据集和表适配器将关系数据导入您的应用程序。加载到数据集后,您可以填充 QuestionAnswer 对象。

这是一个将存储过程的结果填充到数据集中的示例玩具代码:

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);
    }
}

对于实际开发,我建议您使用Typed Dataset 和正确的SqlConnection。但是,正如 cmets 也指出的那样,如果可以,请使用 EF 或其他 O/R 映射器。

【讨论】:

    【解决方案2】:

    这是您最基本的 ORM 映射器类型。

    嗯,最基本的,考虑到一些可维护性和可读性。

    我会访问数据库一次,但在您的存储过程中有多个结果集。 并查看 IDataReader.NextResult

    (在这里看到LINK

    下面是一些基本的 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 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多