在存储器装载相关的对象(没有ORM)(Loading related objects in memo

2019-10-30 08:52发布

我使用ADO.NET来读取一串从数据库中的数据到内存中的对象。

这是我的域模型:

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

在检索的问题的列表,我想对每个问题获取相关的标签。 我能做到这一点,如下所示:

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

我的问题是,是否有任何的最佳做法/模式从数据库中获取相关的对象?

大多数的SO问题,我碰到加载相关的数据提供了实体框架的解决方案。 目前还没有答案的这个重复的问题。

即使我的代码工作,我想知道其他的方法来这样做。 我跨来到最接近解释的定位我的具体问题是Martin Fowler的延迟加载模式,我相信,会导致以下实现:

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

是否有任何其他的选择吗?

Answer 1:

如果您在ADO.Net这样坚持,那么我会建议使用小窍门与匿名类型,LINQ和Enumerable.Range(0,0)。

首先,你需要创建一个匿名类型的列表(或者只是创建映射回SQL语句中的实际类)

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

接下来就是你做你的ADO.Net东西查询数据库并获得满意的结果。

这里的关键是要编写返回所有你在一个查询中寻找数据的查询。

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

现在,你有你的列表中的所有行完全填充,你只需将它们转换回到你正在寻找的对象。

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();


文章来源: Loading related objects in memory (without an ORM)