C# 从存储过程返回具有填充列表属性的对象
我不熟悉SQL Server存储过程,所以如果我是个白痴,请道歉。我想使用存储过程返回一个对象列表,每个对象都有一个包含相关对象列表的属性。比如说C# 从存储过程返回具有填充列表属性的对象,c#,.net,sql-server,stored-procedures,C#,.net,Sql Server,Stored Procedures,我不熟悉SQL Server存储过程,所以如果我是个白痴,请道歉。我想使用存储过程返回一个对象列表,每个对象都有一个包含相关对象列表的属性。比如说 public class Question { public int QuestionID { get; set; } public string Question { get; set; } public List<Answer> Answers { get; set; } } public class Ans
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;}
}
公开课问题
{
public int QuestionID{get;set;}
公共字符串问题{get;set;}
公共列表答案{get;set;}
}
公开课答案
{
public int AnswerID{get;set;}
public int QuestionID{get;set;}
公共字符串答案{get;set;}
}
我想编写一个存储过程,返回问题列表,每个问题都有其Answers属性,其中填充了相关的Answer对象
非常感谢您的帮助
谢谢
Dave实际上,存储过程交付的是关系结果,而不是对象。或者,您可以使用
FOR XML
返回XML,并将其反序列化为对象。通常使用O/R映射器将其映射到对象
您可以使用数据集和表适配器将关系数据获取到应用程序中。加载到数据集中后,可以填充问题
和答案
对象
下面是一个示例玩具代码,用于将存储过程的结果填充到数据集中:
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);
}
}
对于实际开发,我建议您使用和适当的
SqlConnection
。然而,正如评论所指出的,如果可以,请使用EF或其他O/R映射器。这是您最基本的ORM映射器类型
嗯,最基本的,考虑到一些可维护性和可读性
我会点击数据库一次,但在您的存储过程中有多个结果集。
并查看IDataReader.NextResult
(如图所示)
下面是一些基本的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;
}
}
实体框架将为您执行此操作,否则它将必须是一个手动过程。是否使用实体框架上的存储过程或其他原因?@DGibbs是。只询问存储过程是否真的可以,但实现取决于您计划在客户端使用什么?实体框架、其他一些ORM、ADO.NET数据集、DataReader……是的,这将起作用,这里有两种方法:1。返回2个结果集(一个包含问题,一个包含所有相关答案)或2个。调用存储过程获取问题,然后为每个问题和答案调用第二个存储过程…-第一种方法意味着您可以更高效地获取数据,但需要一点处理,第二种方法的数据库命中率更高
CREATE PROC dbo.uspQuestionAndAnswersGetAll
AS
SELECT QuestionId, QuestionText FROM dbo.Question
SELECT AnswerId, QuestionId, AnswerText FROM dbo.Answer
GO