【问题标题】:Populate Model class from Data in Backend从后端的数据填充模型类
【发布时间】:2016-06-29 18:35:21
【问题描述】:

我有一个数据库有两个表如下,请忽略数据但格式如下

现在我有一个如下构造的模型类

public class FamilyModel
    {

        public string Name { get; set; }
        public List<FamilyModel> FamilyList { get; set; }
        public FamilyModel()
        {
            FamilyList = new List<FamilyModel>();
        }
}

现在我只想从两个表中获取数据并填充列表。

所以我有一个存储过程,返回数据如下

所以我写了一些代码来填充上面的类。但它不起作用。我调试时数为 5。我希望计数为 2,扩展时我想要 FamilyA ->{Nick, Tom, Pam}.. FamilyB->{Harry} 等。请帮助修复此代码。

    public static FamilyModel familyData()
            {
                //FamilyModel fml = new FamilyModel();
                //fml.FamilyList = new List<FamilyModel>();
                using (SqlConnection con = new SqlConnection(@"Data Source=(LocalDB)\v11.0; AttachDbFilename=|DataDirectory|\Families.mdf; Integrated Security=True; Connect Timeout=30;"))
                {
                    con.Open();
                    SqlCommand cmd = new SqlCommand("sp_GetFamilies", con);
                    cmd.CommandType = CommandType.StoredProcedure;
                    SqlDataReader dr = cmd.ExecuteReader();
                    while (dr.Read())                                                             {                                                          
                        FamilyModel fm = new FamilyModel();                    
                        fm.Name = dr["FamilyName"].ToString();
                        foreach (var item in dr["ChildName"].ToString())
                        {
                            if (Convert.ToInt32(dr["id"]) == Convert.ToInt32(dr["FID"]))
                            {
                                fm.FamilyList.Add(new FamilyModel() { Name = dr["ChildName"].ToString() });
                            }
                        }

                    }
 return fm;
                }

    }

【问题讨论】:

  • List&lt;FamilyModel&gt; 应该是 List&lt;Person&gt; 而不是。

标签: c# stored-procedures sqldatareader


【解决方案1】:

这里有一些源代码应该可以理解正确的想法。在它下面,我对发生的事情做了一些解释。

using Dapper;
public class FamilyModel
{
    public int Id { get; set;}
    public string FamilyName { get; set; }
    public List<Person> Members { get; set; } = new List<Person>();//Initializer for Auto-Property, C#6<= only
}
public class Person
{
    public int Id { get; set;}
    public string Name { get; set; }
}
public class DatabasePOCO
{
    public string FamilyName { get; set; }
    public string ChildName { get; set; }
    public int Fid { get; set; }
    public int Id { get; set;}
}
void Main()
{
    using (IDbConnection conn = new SqlConnection("..."))
    {
        conn.Open();
        var raw = conn.Query<DatabasePOCO>("sp_GetFamilies",
        commandType: CommandType.StoredProcedure);//Could be dynamic, not typed
        var familyList = raw
        .GroupBy(x => x.Fid)
        .Select(x =>
        {
            var rawMembers = x.ToList();
            var fId = x.First().Fid;
            var fName = x.First().FamilyName;
            var members = rawMembers.Select(y => new Person 
            {
                Id = y.Id,
                Name = y.ChildName
            });
            return new FamilyModel
            {
                Id = fId,
                FamilyName = fName,
                Members = members.ToList()
            };
        });
        //Whatever else you want to do here
    }
}
  1. 考虑使用Dappper。这是一个很棒的 ORM,它使访问数据库中的数据变得非常容易。它旨在与 SQL Server 一起使用,但我也成功使用了 Oracle,而且大多数其他 RMDBS 系统可能也可以使用。
  2. 考虑使用Slapper。如果您可以控制您的存储过程,这可以减少很多下面的样板代码。
  3. 如果您使用 Dapper(我希望您这样做),您可以使用 C# 动态对象,或者您可以创建一个 POCO 来帮助对您的代码进行一些类型强制。
  4. 了解您是否关心引用相等性。我在下面提供的代码强制对象的引用相等。根据我的经验,引用平等不会给您带来太多好处,而且执行起来很痛苦。

【讨论】:

  • 感谢您的回答,但我的最终目标是解决这个问题stackoverflow.com/questions/38084429/… 这就是我考虑自己的类结构作为模型的原因。
  • 我对使用 Dapper/Slapper 的建议仍然有效(当你有更复杂的对象时它会帮助你!)并且在那个链接中,有不同的父对象和子对象,但也许我只是不看不到微妙之处。无论如何,祝你好运!
【解决方案2】:

您需要区分数据集中的新行和新的FamilyModel。一种方法是声明一个模型列表,然后在添加当前子行之前查找“正确”的模型:

var rootModel = new FamilyModel();
rootModel.Name = "root";

// ... Set up data reader ...

while (dr.Read()) 
{
    //This requires support for the Id in your FamilyModel:
    var id = (int)dr["Id"];
    //You could also use ".Single(...)" here
    var fm = rootModel.FamilyList.Where(x => x.Id == id).First();
    if (fm == null) 
    {
        fm = new FamilyModel();
        fm.Name = dr["FamilyName"].ToString();
        rootModel.FamilyList.Add(fm);
    }
    fm.FamilyList.Add(new FamilyModel() { Name = dr["ChildName"].ToString() });
}

对于数据库查询中的每一行,您将:

  1. 尝试在您的列表中查找该家庭
  2. 如果没有找到,请创建一个新的。将其添加到您的顶级列表中。
  3. 将子名称添加为“当前”系列的子元素。

【讨论】:

  • 给布赖恩工作。我为 id 添加了一个属性。但是请看一下 var fm = rootModel.FamilyList.Where(x => x.Id == id) 返回 IEnumerable 所以 fm=new FamilyModel 是无效的吧。
  • 好点。我已经编辑了我的答案来解决这个问题。在 Stackoverflow 编辑器中编写的代码有时会遗漏这样的细节 :)
  • 谢谢布赖恩我试一试。
猜你喜欢
  • 2013-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多