I need to pull back information from two separate Database calls into one object.
Consider the following classes
public class Status
{
public int StatusId { get; set; }
public string Name { get; set; }
}
public class Person
{
public int PersonId { get; set; }
public Status PersonStatus { get; set; }
}
These represent two database tables Persons and Status that are related by the StatusId in the Persons table.
CREATE TABLE [dbo].[Status](
[StatusId] [INT] NOT NULL PRIMARY KEY,
[Name] [NVARCHAR](50) NOT NULL )
CREATE TABLE [dbo].[Persons](
[PersonId] [int] NOT NULL PRIMARY KEY,
[StatusId] [int] NOT NULL REFERENCES dbo.Status (StatusId) )
Here is the procedure to get People:
CREATE PROCEDURE dbo.spGetPersons
AS
BEGIN
SELECT PersonId ,
StatusId
FROM dbo.Persons
END
I then read the data from the SqlDataReader
, construct a Person object, and return an IList<Person>
. In order to populate the PersonStatus property, currently I pass the StatusId into a secondary procedure which makes another round trip to the database.
IList<Person> People = new List<Person>();
while (reader.Read())
{
People.Add(new Person()
{
PersonId = (int)reader["PersonId"],
//This causes the extra round trip to the database
StatusId = new StatusDao().GetStatus((int)reader["StatusId"])
});
}
StatusDao().GetStatus()
just executes the following procedure and constructs a Status
object.
CREATE PROCEDURE dbo.spGetStatus
@StatusId INT = NULL
AS
BEGIN
SELECT StatusId ,
Name
FROM dbo.Status
WHERE @StatusId IS NULL
OR @StatusId = StatusId
END
What is the proper way to populate the PersonStatus
property? Obviously I shouldn't do an additional round trip to the database for each Person
. Let's assume I can't edit the procedure and just add Name
to the SQL query.
I did see this question that suggested using an enumerator. That's a good option in some cases, but let's just assume that the Status data changes regularly. That makes this no longer an option.
I am not currently using an ORM.
I can't add a new Stored Procedure, nor can I edit the existing stored procedure. I'm also not allowed to use Inline SQL.
Since you have a rather odd requirement of not being able to add a new Stored Procedure or Using Inline SQL; it's going to take two trips to the database no matter what (Unless, again, Status is something that can be captured in an Enum).
If you have a Status
object and a Person
Object and you want to put them together, you can use the following method:
public static List<Person> GetStatusForPerson(List<Person> people, List<Status> statuses)
{
List<Person> peopleWithStatuses = new List<Person>();
foreach (var p in people)
{
Person person = new Person();
person.PersonId = p.PersonId;
person.Status = statuses.Where(s => s.StatusId == person.StatusId).FirstOrDefault());
peopleWithStatuses.Add(person);
}
return peopleWithStatuses;
}
To get this information in one round-trip to the Database (for anyone who has this issue without a weird requirement):
var persons = new List<Person>();
using (SqlConnection connection = new SqlConnection(connectionString)) {
string sqlText = "Select p.PersonId, ps.Name, ps.StatusId FROM Person p INNER JOIN PersonStatus ps on p.StatusID = ps.StatusId WHERE p.PersonId = @personId";
SqlCommand command = new SqlCommand();
command.Parameters.Add("@personId", SqlDbType.Int);
command.Parameters["@personId"].Value = personId;
connection.Open();
using (SqlDataReader reader = command.ExecuteReader()) {
while (reader.Read())
{
var person = new Person();
var status = new PersonStatus();
person.PersonID = reader["PersonId"];
status.StatusId = reader["StatusId"];
status.Name = reader["Name"];
person.Status = status;
persons.Add(person);
}
}
}
return persons;
If Status
is a series of integer constants (much like an enum
) then you could simply use an enum
and store the possible states.
If Status
dynamically adds or removes values, then you have to resort to the normal method of pulling data back when you're not using an ORM: A DataReader
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.