简体   繁体   English

将相关对象加载到内存中(无ORM)

[英]Loading related objects in memory (without an ORM)

I am using ADO.NET to read a bunch of data from the database into in-memory objects. 我正在使用ADO.NET将一堆数据从数据库读取到内存中的对象中。

This is my domain model: 这是我的域模型:

// Question.cs
public class Question
{
    public int ID { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public IEnumerable<Tag> Tags { get; set; }
}

// Tag.cs
public class Tag 
{
    public int ID { get; set; }
    public string Name { get; set; }
}

On retrieving the list of Questions, I would like to fetch the related tags for each question. 在检索问题列表时,我想获取每个问题的相关标签。 I am able to do this as follows: 我可以做到这一点,如下所示:

// QuestionRepository.cs

public IList<Question> FindAll()
{
    var questions = new List<Question>();

    using (SqlConnection conn = DB.GetSqlConnection())
    {
        using (SqlCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = "select * from questions";

            SqlDataReader reader = cmd.ExecuteReader();

            while (reader.Read())
            {
                Question question = new Question();
                // Populate the question object using reader
                question.Load(reader);

                questions.Add(question);
            }
            reader.Close();
        }
     }
    return questions;
}


// Question.cs
public void Load(SqlDataReader reader)
{
    ID = int.Parse(reader["ID"].ToString());
    Title = reader["Title"].ToString();
    Description = reader["Description"].ToString();

    // Use Tag Repository to find all the tags for a particular question
    Tags = tagRepository.GetAllTagsForQuestionById(ID); 
}

    return questions;
}

// TagRepository.cs
public List<Tag> GetAllTagsForQuestionById(int id)
{
    List<Tag> tags = new List<Tag> ();
    // Build sql query to retrive the tags
    // Build the in-memory list of tags 
    return tags;
}

My question is, are there any best practices/patterns for fetching related objects from the database? 我的问题是,是否有用于从数据库中获取相关对象的最佳实践/模式?

Most of the SO questions I came across for loading related data provide the solution for entity framework. 我在加载相关数据时遇到的大多数SO问题都为实体框架提供了解决方案。 There is no answer for this duplicate question. 这个重复的问题没有答案

Even though my code works, I would like to know other ways to do the same. 即使我的代码有效,我也想知道其他方法来做到这一点。 The closest explanation I came across that's targeting my particular problem was Martin Fowler's Lazy Load pattern, which I believe, will result in following implementation: 针对我的特定问题,我遇到的最接近的解释是Martin Fowler的Lazy Load模式,我相信它将导致以下实现:

public class Question
{
    private TagRepository tagRepo = new TagRepository();
    private IList<Tag> tags;

    public int ID { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public IEnumerable<Tag> Tags {
        get
        {
            if (tags == null)
            {
                tags = tagRepo.GetAllTagsForQuestionById(ID);
            }
            return tags;
        }
    }  
}

Are there any other alternatives? 还有其他选择吗?

If you are insisting on doing this in ADO.Net, then I would suggest using a little trick with anonymous types, LINQ, and Enumerable.Range(0,0). 如果您坚持要在ADO.Net中执行此操作,那么我建议对匿名类型LINQ和Enumerable.Range(0,0)使用一些技巧。

First, you need to create a list of an anonymous type (or just create an actual class that maps back to your SQL statement) 首先,您需要创建一个匿名类型的列表(或仅创建一个映射回您的SQL语句的实际类)

var data = Enumerable.Range(0, 0).Select(x => new
{
    QestionId = 0,
    Title = "Question.Title",
    Description = "Question.Description",
    TagId = 0,
    Name = "Tag.Name"
}).ToList();

Next is where you do your ADO.Net stuff query the database and get the results. 接下来是在其中执行ADO.Net的工作,查询数据库并获取结果。

The key thing here is to write a Query that returns all of the data you're looking for in one query. 这里的关键是编写一个查询,该查询返回一个查询中要查找的所有数据。

using (var conn = GetConnection())
{
    using (var cmd = conn.CreateCommand())
    {
        //Construct a valid SQL statement that joins questions to tags
        cmd.CommandText = "SELECT q.*, t.* FROM questions q JOIN tags t ON 1 = 1";

        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                data.Add(new
                {
                    QestionId = reader.IsDBNull(0) ? 0 : int.TryParse(reader.GetValue(0).ToString(), out var qId) ? qId : 0,
                    Title = reader.IsDBNull(1) ? string.Empty : reader.GetValue(1).ToString(),
                    Description = reader.IsDBNull(2) ? string.Empty : reader.GetValue(2).ToString(),
                    TagId = reader.IsDBNull(3) ? 0 : int.TryParse(reader.GetValue(3).ToString(), out var tId) ? tId : 0,
                    Name = reader.IsDBNull(4) ? string.Empty : reader.GetValue(4).ToString()
                });
            }
        }
    }
}

Now that you have your list fully populated with all of the rows, you just need to transform them back into the object you're looking for. 现在您已经用所有行完全填充了列表,只需要将它们转换回要查找的对象即可。

var questions = data.GroupBy(x => new {x.QestionId, x.Title, x.Description}).Select(y => new Question
{
    Id = y.Key.QestionId,
    Title = y.Key.Title,
    Description = y.Key.Description,
    Tags = y.Select(z => new Tag
    {
        Id = z.TagId,
        Name = z.Name
    })
}).ToList();

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

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