简体   繁体   English

C#使用外键填充嵌套类

[英]C# Populate nested class using foreign key

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. 这些代表两个数据库表Persons和Status,它们与Persons表中的StatusId相关。

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> . 然后,我从SqlDataReader读取数据,构造一个Person对象,并返回一个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. 为了填充PersonStatus属性,当前我将StatusId传递到辅助过程中,该过程将再次往返数据库。

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. StatusDao().GetStatus()仅执行以下过程并构造一个Status对象。

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? 填充PersonStatus属性的正确方法是什么? Obviously I shouldn't do an additional round trip to the database for each Person . 显然,我不应该为每个Person进行一次额外的数据库往返之旅。 Let's assume I can't edit the procedure and just add Name to the SQL query. 假设我无法编辑过程,而仅将Name添加到SQL查询中。

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. 我当前未使用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. 我也不允许使用内联SQL。

Since you have a rather odd requirement of not being able to add a new Stored Procedure or Using Inline SQL; 由于您有一个非常奇怪的要求,即无法添加新的存储过程或使用内联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: 如果您有一个Status对象和一个Person对象,并且想要将它们放在一起,则可以使用以下方法:

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;

Use Enums 使用枚举

If Status is a series of integer constants (much like an enum ) then you could simply use an enum and store the possible states. 如果Status是一系列整数常量(很像enum ),那么您可以简单地使用enum并存储可能的状态。

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 . 如果Status动态地添加或删除值,那么在不使用ORM时,您必须求助于恢复数据的常规方法: A DataReader

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM