繁体   English   中英

C#使用外键填充嵌套类

[英]C# Populate nested class using foreign key

我需要将来自两个单独的数据库调用的信息拉回到一个对象中。

考虑以下课程

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

这些代表两个数据库表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) )

这是获取人员的过程:

CREATE PROCEDURE dbo.spGetPersons
AS
BEGIN
    SELECT  PersonId ,
            StatusId
    FROM    dbo.Persons
END

然后,我从SqlDataReader读取数据,构造一个Person对象,并返回一个IList<Person> 为了填充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()仅执行以下过程并构造一个Status对象。

CREATE PROCEDURE dbo.spGetStatus
    @StatusId INT = NULL
AS
    BEGIN
        SELECT  StatusId ,
                Name
        FROM    dbo.Status
        WHERE   @StatusId IS NULL
                OR @StatusId = StatusId
    END

填充PersonStatus属性的正确方法是什么? 显然,我不应该为每个Person进行一次额外的数据库往返之旅。 假设我无法编辑过程,而仅将Name添加到SQL查询中。

我没有看到这个问题,用枚举建议。 在某些情况下,这是一个不错的选择,但是我们假设状态数据会定期更改。 这使得它不再是一种选择。

我当前未使用ORM。

我无法添加新的存储过程,也无法编辑现有的存储过程。 我也不允许使用内联SQL。

由于您有一个非常奇怪的要求,即无法添加新的存储过程或使用内联SQL; 无论如何,它将需要两次访问数据库(除非再次声明,状态是可以在枚举中捕获的东西)。

如果您有一个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;
}

要在一次数据库往返中获取此信息(对于那些没有奇怪要求的人):

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;

使用枚举

如果Status是一系列整数常量(很像enum ),那么您可以简单地使用enum并存储可能的状态。

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

暂无
暂无

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

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