C#通用绑定

时间:2016-03-11 15:32:50

标签: c# generics reflection propertyinfo

我正在为学校工作,并试图实现尽可能多的功能只是为了学习。因此,我制作了一个通用映射器,将数据库表映射到对象,看看有什么可能。在这种情况下,Db是本地的。我知道我正在进行大量的呼叫,并且应该以不同的方式解决这个问题,但是......

除了当一个类有另一个类的集合时,一切都按预期工作。

示例:

class Student {

public int Id { get; set; }
public string Name { get; set; }
}

我填写数据库中所有学生名单的方法。

public List<TModel> MapEntitiesFromDb<TModel>(string tablename, string customquery = "") where TModel : class, new() 
    {
        try
        {
            sql = ValidateSelectSql(tablename, customquery);
        }
        catch (AccessViolationException ex) { Console.WriteLine(ex.Message); }

        command.CommandText = sql;
        command.Connection = conn;

        List<TModel> list = new List<TModel>();
        try
        {
            using (conn)
            {
                Type t = new TModel().GetType();

                conn.Open();
                using (reader = command.ExecuteReader())
                {

                    if (t.GetProperties().Length != reader.FieldCount)
                        throw new Exception("There is a mismatch between the amount of properties and the database columns. Please check the input code and try again.");

                    //Possible check is to store each column and property name in arrays and match them to a new boolean array, if there's 1 false throw an exception.
                    string columnname;
                    string propertyname;

                    //Pairing properties with columns 
                    while (reader.Read())
                    {
                        TModel obj = new TModel();

                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            columnname = reader.GetName(i).ToString().ToLower();

                            PropertyInfo[] properties = t.GetProperties();
                            foreach (PropertyInfo propertyinfo in properties)
                            {
                                propertyname = propertyinfo.Name.ToLower();

                                if (propertyname == columnname)
                                {
                                    propertyinfo.SetValue(obj, reader.GetValue(i));
                                    break;
                                }
                            }
                        }

                        list.Add(obj);

                    }
                }
            }
        }
        catch (Exception ex) { Console.WriteLine(ex.Message); }

        return list;
    }

我的ValidateSelectSql只返回需要在查询中使用的sql字符串。

致电:

List<Student> = MapEntitiesFromDb<Student>("students");

它将返回一份包含所有学生的列表。

例如,当我添加一个集合时出现问题:

class Student {

public Student()
{
    this.Courses = new List<Course>();

    string customsqlquery = ::: this works and is tested! :::
    Courses = MapEntitiesFromDb<Course>("", customsqlquery);
}

public int Id { get; set; }
public string Name { get; set; }

public ICollection<Course> Courses;
}

课程列表返回为空,在调试器工具的帮助下,我在创建对象时发现Id属性当然为0。在我的查询中,我正在过滤学生ID,但在执行方法填写构造函数中的课程列表时,学生的ID将始终为0,因为它在稍后阶段设置,结果将不是列表中的课程

我想知道是否应该在设置其他属性后检查ICollection属性,如果是,则在对象上执行一个方法,该方法返回执行现在在构造函数中的方法?

我不能在TModel上调用任何方法,否则它就像查找TModel是否具有集合属性并调用obj.FillCollection();在GetEntitiesFromDb方法中分配了Id属性之后。

我也在考虑递归。再次,我必须找到obj是否有一个集合属性然后调用GetEntitiesFromDB,但它似乎是可撤消的,因为我还需要找出介于&lt;&gt;之间的类型我不能从外面发送任何自定义查询...

或许从另一个角度解决这个问题?

我真的可以就如何解决这个问题提出一些建议。

1 个答案:

答案 0 :(得分:0)

解决这个问题最直接的方法是让collection属性延迟加载它需要的东西。我还建议您使用IEnumerable<T>而不是ICollection<T>,因为这代表了数据库中当前内容的只读视图,没有人应该以任何方式修改它。

public class Student
{    
    private readonly Lazy<IEnumerable<Course>> courses;

    public int Id { get; set; }
    public IEnumerable<Course> Courses => this.courses.Value;

    public Student()
    {
        this.courses = new Lazy<IEnumerable<Course>>(LoadCourses);
    }

    private IEnumerable<Course> LoadCourses()
    {
        var sql = "custom SQL query that uses this.Id after it's loaded";
        return MapEntitiesFromDb(sql);
    }
}

我只是推荐这种方法,因为您提到这只是一个学术练习,可以帮助您了解可用的工具。在实际的生产环境中,这种方法很快会变得难以处理,我建议使用实体框架(这可能是您可能想要了解的其他内容)。