简体   繁体   中英

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.

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):

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.

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?

A possible improvement to your actual solution is through the use of QueryMultiple extension like this:

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. 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. 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. 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. The unthinking assumption that 1 table corresponds to 1 class is the start of a lot of problems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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