【问题标题】:SQL Query Result to List<T> mappingSQL 查询结果到 List<T> 的映射
【发布时间】:2013-01-14 04:23:18
【问题描述】:

在我的数据库中,我有 2 个表:

id   | name |  city  | street
-------------------------------
   1 | John | London | Street1
   2 | Will | London | Street1
   3 | Adam | LA     | Street1

id   | uid | phone
------------------
   1 |    1| 12345
   2 |    1| 23456
   3 |    2| 16505
   4 |    3| 65909
   5 |    3| 68902
   6 |    3| 15905

我需要选择该数据并存储到列表中(或字典,因为用户 ID 是唯一的)

我的使用类如下所示:

public class User
{
    //lock
    private static readonly object userLock = new object();

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

    public List<string> Phones { get; private set; }

    public User()
    {
        Phones = new List<string>();
    }

    public void AddPhone(string phone)
    {
        lock (userLock)
        {
            Phones.Add(phone);
        }
    }
}

想法是将这些用户信息加载到应用程序中,添加/删除/修改手机并保存更改/删除/添加的内容。

我在这里找到了解决方案的想法:https://stackoverflow.com/a/11687743/965722,但我想这是做一个查询来获取用户列表,然后对于每个用户,我需要单独查询来获取他的手机。

我应该如何加载?
我可以只用一个查询吗?
我应该如何填充我的结果集合?
我应该使用列表还是字典?然后我可以从 User 类中删除 Id 并将其作为字典中的键。

我正在使用 .NET 3.5,并希望避免使用实体框架或 ORM。

【问题讨论】:

  • 只是好奇,为什么要避免最适合您的情况的 EF 或 ORM?
  • 你现有的数据库访问机制是什么?
  • @Cuong Le - 我正在构建我的应用程序模块化,我的想法是每个用户都可以添加自己的功能。如果我使用 EF,那么每个人都有义务使用它(我可能在这方面错了:P)
  • @Jon - 我主要使用 MSSQL 服务器和存储过程,从 C# 中我将它们称为异步,如下所示:stackoverflow.com/questions/12408835/…

标签: c# visual-studio-2008 .net-3.5


【解决方案1】:

创建一个电话类并相应地更改用户属性:

public class Phone
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public string Number { get; set; }
}

public class User
{
    // (etc)
    public List<Phone> Phones { get; set; }
    // (etc)        
}

制作一个PhoneRepository:

public class PhoneRepository
{
    public List<Phone> LoadPhonesFromId(IEnumerable<int> ids)
    {
       // write a query with the ids
       // SELECT * FROM Phones WHERE id IN (@id1, @id2, ...)
       // execute the query
       // convert the results to Phones and put them in a List<Phone>
       // return the list
    }
    public List<Phone> LoadPhonesFromUserId(IEnumerable<int> userIds)
    {
       // write a query with the userIds
       // SELECT * FROM Phones WHERE userId IN (@userId1, @userId2, ...)
       // execute the query
       // convert the results to Phones and put them in a List<Phone>
       // return the list
    }
}

还有一个 UserRepository:

public class UserRepository
{
    public List<User> LoadUsersFromUserIds(IEnumerable<int> userIds)
    {
       // write a query with the userIds
       // SELECT * FROM User WHERE id IN (@id1, @id2, ...)
       // execute the query
       // convert the results to Users and put them in a List<User>
       // return the list
    }

    public void IncludePhones(IEnumerable<User> users)
    {            
        var phones = PhoneRepository.LoadPhonesFromUserId
            (users.Select(x => x.Id));

        for each(var user in users)
        {
            user.Phones = phones
                .Where(x => x.UserId == user.Id)
                .ToList();
        }
    }
}

您可以极大地扩展和改进这种模式,例如,使用自定义过滤器参数(而不是为各种过滤器设置不同的函数)和确保 user 和 user.Phones 始终引用相同的 userID 的属性设置器,但是这超出了您的问题范围。

【讨论】:

  • 感谢您的建议,这与我现在的代码几乎相同,只是我拥有一个方法。这很好用,但正如我所写的,我想避免多次查询,但我认为这几乎是不可能的,尤其是用户一开始可能没有任何手机。
  • 抱歉我的愚蠢评论 :) 我可以只用 2 个查询而不是 n 来加载。现在我将继续使用这个解决方案。谢谢!
【解决方案2】:

如果您可以升级到 .net 4,请查看ObjectContext.Translate - 您可以在没有“真实”实体模型的情况下使用它,一个空的未子类化的 objectcontext 就足够了,即使它们不是实体,它们也会映射对象。此解决方案没有第三方依赖项,但与可用的开源库相比,速度稍慢且灵活性较差。

如果 .net 4.0 不是一个选项,或者您想要更多功能和性能,您可能需要查看第三方库:

  • Dapper 很好地展开普通 POCO 并具有很好的参数化查询。也非常快。最新版本是 .net 4.0,但也有 3.5 版本。
  • PetaPoco 另一个简单的 POCO 解包器,.net 3.5
  • ServiceStack.OrmLite这个我不太了解。

每个项目还列出了一些其他竞争对手;我相信您可以在其中找到一个合适的选择,允许您使用易于参数化的查询编写普通 sql,并将结果自动解包到普通对象中。性能开销几乎为零;所以这个解决方案(恕我直言)总是比原始数据阅读器更可取;在日常使用中要容易得多。

【讨论】:

  • 感谢您的建议,但这需要 .NET4(根据我在 MSDN 中看到的),正如我在问题中所写,我仅限于 .NET 3.5
  • 很遗憾 - 这当然是一个简单的解决方案。我将在答案中添加一些类似的变体。
  • 这些其他库有帮助吗?
  • 我不认识他们(还不认识 :))PetaPoco 看起来很棒,我可以在我的项目中添加一个 cs 文件,它会起作用 :) 你能帮我处理一下我使用 PetaPoco 的情况吗?
  • 文档应该足够了 - 它真的很简单。顺便说一句,您对手动锁定的使用看起来很危险:您正在锁定写入而不是读取,这可能导致未定义的行为(我建议避免对对象进行多线程读/写访问,只有极少数例外)。
猜你喜欢
  • 1970-01-01
  • 2017-05-13
  • 2016-05-26
  • 1970-01-01
  • 2021-08-13
  • 1970-01-01
  • 2012-08-05
  • 1970-01-01
  • 2011-01-06
相关资源
最近更新 更多