简体   繁体   English

这是使用Dapper的正确方法还是我做错了?

[英]Is this the right way of using Dapper or am I doing it all wrong?

I am trying to get away from the Entity Framework since I have to support HANA Databases aside from SQL server Databases in our solution. 我正试图摆脱实体框架,因为除了我们的解决方案中的SQL服务器数据库之外,我必须支持HANA数据库。

I am doing some research with dapper so I created a quick test environment with some fictitious scenario. 我正在用小巧玲珑做一些研究,所以我用一些虚构的场景创建了一个快速测试环境。

I have the following POCOs that resemble my Database schema (I have more but I limited to showing these for simplicity): 我有以下POCO类似于我的数据库架构(我有更多,但我限于显示这些为简单):

public class Adopter
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public State State { get; set; }
    public int StateId { get; set; }
    public string Zip { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public string Fax { get; set; }
    public IEnumerable<Pet> Pets { get; set; }
}

public class State
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Abreviation { get; set; }
}

public class Pet
{
    public int Id { get; set; }
    public string IdTag { get; set; }
    public string Name { get; set; }
    public DateTime AdmitionDate { get; set; }
    public Status Status { get; set; }
    public int StatusId { get; set; }
    public string Notes { get; set; }
    public DateTime AdoptionDate { get; set; }
    public bool IsAdopted { get; set; }
    public int? AdopterId { get; set; }
    public int Age { get; set; }
    public decimal Weight { get; set; }
    public string Color { get; set; }
    public Breed Breed { get; set; }
    public int BreedId { get; set; }
    public Gender Gender { get; set; }
    public int GenderId { get; set; }
    public IEnumerable<PetImage> PetImages { get; set; }
}


public class Status
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

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

I am using the following in a repository to return a list of all the adopters: 我在存储库中使用以下命令返回所有采用者的列表:

        using (SqlConnection connection = new SqlConnection(_connectionString))
        {
            var adopters = connection.Query<Adopter>("SELECT a.* FROM Adopters a");
            foreach (var adopter in adopters)
            {
                adopter.State = connection.QueryFirst<State>("Select s.* FROM States s WHERE s.Id =  @Id", new { Id = adopter.StateId });
                adopter.Pets = connection.Query<Pet>("Select p.* FROM Pets p WHERE p.AdopterId = @Id", new { Id = adopter.Id });
                foreach (var pet in adopter.Pets)
                {
                    pet.Status = connection.QueryFirst<Status>("Select s.* FROM Status s WHERE s.Id =  @Id", new { Id = pet.StatusId });
                    pet.Gender = connection.QueryFirst<Gender>("Select g.* FROM Genders g WHERE g.Id =  @Id", new { Id = pet.GenderId });
                }
            }

            return adopters;
        }

As you can see, I am retrieving the data for each POCO individually based on the previous one and doing the Joins manually in code. 如您所见,我正在基于前一个POCO单独检索每个POCO的数据,并在代码中手动执行联接。

Is this the right way of doing it or should I be doing a big query with multiple joins and mapping the result somehow thru dapper and LINQ? 这是正确的方法吗?或者我应该使用多个连接进行大查询并通过dapper和LINQ以某种方式映射结果?

A possible improvement to your actual solution is through the use of QueryMultiple extension like this: 您实际解决方案的一个可能的改进是通过使用QueryMultiple扩展,如下所示:

using (SqlConnection connection = new SqlConnection(_connectionString))
{
    string query = @"SELECT * FROM Adopters;
                     SELECT * FROM States;
                     SELECT * FROM Pets;
                     SELECT * FROM Status;
                     SELECT * FROM Genders;";

    using (var multi = connection.QueryMultiple(query, null))
    {
        var adopters = multi.Read<Adopter>();
        var states = multi.Read<State>();
        var pets = multi.Read<Pet>();
        var statuses = multi.Read<Status>();
        var genders = multi.Read<Gender>();

        foreach (Adopter adp in adopters)
        {
            adp.State = states.FirstOrDefault(x => x.Id == adp.StateID);
            adp.Pets = pets.Where(x => x.IsAdopted && 
                                  x.AdopterID.HasValue && 
                                  x.AdopterID.Value == adp.AdopterID)
                                  .ToList();
            foreach(Pet pet in adp.Pets)
            {
                pet.Status = statuses.FirstOrDefault(x => x.Id == pet.StatusID);
                pet.Gender = genders.FirstOrDefault(x => x.Id == pet.GenderID);

            }
        }
    }
}

The benefit here is that you reach the database just one time and then process everything in memory. 这里的好处是您只需一次访问数据库,然后处理内存中的所有内容。

However this could be a performance hit and a memory bottleneck if you have a really big data to retrieve, (and from a remote location). 但是,如果你有一个非常大的数据要检索(并且从远程位置),这可能是性能损失和内存瓶颈。 Better to look closely at this approach and try also some kind of Async processing and/or pagination if possible. 最好密切关注这种方法,并尽可能尝试某种异步处理和/或分页。

I don't like to be negative, but... don't do this! 我不喜欢消极,但是......不要这样做! Don't even think like this. 甚至不要这样想。 You want to dump EF, but you're walking into the trap by wanting to emulate EF. 你想转储EF,但是你想通过模拟EF来进入陷阱。 The bridge between your app and your DB is not something to be built once for all time, for every conceivable purpose. 您的应用程序和数据库之间的桥梁不是一直可以构建的,无论出于何种目的。 Concretely, you shouldn't really ever bring back a whole table, and certainly not to then loop on every row and emit more queries. 具体来说,你不应该真的带回整个表,当然不要在每一行循环并发出更多的查询。 You may feel unjustly criticised, you were just testing the tools ! 您可能会受到不公正的批评,您只是在测试工具! If so, perhaps tell us what aspect of the tool your examining, and we'll focus in on that. 如果是这样,或许告诉我们您正在研究的工具的哪个方面,我们将重点关注它。

Dapper or QueryFirst greatly simplify running queries, and consuming the results, so bring back just what you need, just when you need it. Dapper或QueryFirst极大地简化了运行查询并消耗结果,因此只需在需要时就可以恢复所需内容。 Then denormalize a little, for the specific job in hand. 然后对于手头的具体工作进行反规范化。 Why are there no joins in your queries? 为什么查询中没有连接 RDBMSs are amazing, and amazingly good at doing joins. RDBMS非常棒,而且非常擅长加入。 If you're joining data outside the DB, crazy is the only word, even if Linq gives you a super (sql-like) syntax for doing it. 如果您正在加入数据库之外的数据,那么疯狂是唯一的一个词,即使Linq为您提供了超级(类似sql)的语法。 The unthinking assumption that 1 table corresponds to 1 class is the start of a lot of problems. 1表对应1类的不假思索的假设是许多问题的开始。

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

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