Remplir les POCO avec ServiceStack.OrmLite

dapper ormlite-servicestack servicestack

Question

Prenons le modèle de domaine suivant:

class Customer
{
  int id {get;set}
  string Name {get;set}
  List<Contact> Contacts {get;set}
}

class Contact
{
  int id {get;set}
  string FullName {get;set}
  List<PhoneNumber> {get;set}
}

class PhoneNumber
{
  int id {get;set}
  PhoneType Type {get;set}
  string Number {get;set}
}

Customer, Contact & PhoneNumbers sont des entités distinctes dans notre base de données.

Des suggestions quant à la manière la plus efficace de remplir un client complet avec tous ses contacts liés et les numéros de téléphone des contacts en utilisant ORMLite et / ou Dapper, en tenant compte des appels aux cycles db et cpu pour les mapper aux POCO? ¿

Réponse populaire

J'ai mis à jour mon exemple pour extraire la liste de clients à plat et la transformer en hiérarchie. Quelques points à noter:

  • Je spécifie explicitement des colonnes dans le générateur de jointure car les colonnes Id portent le même nom dans la jointure
  • la performance doit être décente car j'utilise un hachage pour les clients et en ajoutant des numéros de téléphone, de sorte que la seule véritable boucle est la recherche d'un contact correspondant

Des modèles:

class CustomerComplete
{
    [BelongTo(typeof(Customer))]
    public string CustomerName { get; set; }

    [BelongTo(typeof(Customer))]
    public int CustomerId { get; set; }

    [BelongTo(typeof(Contact))]
    public int ContactId { get; set; }

    [BelongTo(typeof(Contact))]
    public string ContactFullName { get; set; }

    [BelongTo(typeof(PhoneNumber))]
    public int PhoneNumberId { get; set; }

    [BelongTo(typeof(PhoneNumber))]
    public PhoneType Type { get; set; }

    [BelongTo(typeof(PhoneNumber))]
    public string Number { get; set; }
}

class Customer
{
    public Customer()
    {
        this.Contacts = new List<Contact>();
    }

    [AutoIncrement, PrimaryKey]
    public int Id { get; set; }

    public string Name { get; set; }

    [Ignore]
    public List<Contact> Contacts { get; set; }
}

class Contact
{
    public Contact()
    {
        this.PhoneNumbers = new List<PhoneNumber>();
    }

    [AutoIncrement, PrimaryKey]
    public int Id { get; set; }

    public string FullName { get; set; }

    [References(typeof(Customer))]
    public int CustomerId { get; set; }

    [Ignore]
    public List<PhoneNumber> PhoneNumbers { get; set; }
}

class PhoneNumber
{
    [AutoIncrement, PrimaryKey]
    public int Id { get; set; }

    public PhoneType Type { get; set; }
    public string Number { get; set; }

    [References(typeof(Contact))]
    public int ContactId { get; set; }
}

enum PhoneType { None = 0 }

Usage:

db.CreateTableIfNotExists<Customer>();
db.CreateTableIfNotExists<Contact>();
db.CreateTableIfNotExists<PhoneNumber>();

db.Insert<Customer>(new Customer { Name = "Widget Co Inc" });
var customerId = (int) db.GetLastInsertId();

db.Insert<Contact>(new Contact { FullName = "John Smith", CustomerId = customerId });
var contactId = (int)db.GetLastInsertId();

db.Insert<PhoneNumber>(new PhoneNumber { ContactId = contactId, Number = "555.555.5555", Type = PhoneType.None });
db.Insert<PhoneNumber>(new PhoneNumber { ContactId = contactId, Number = "444.444.4444", Type = PhoneType.None });

db.Insert<Contact>(new Contact { FullName = "Jack Smith", CustomerId = customerId });
contactId = (int)db.GetLastInsertId();

db.Insert<PhoneNumber>(new PhoneNumber { ContactId = contactId, Number = "111.111.1111", Type = PhoneType.None });

// contact without phone number test
db.Insert<Contact>(new Contact { FullName = "Jill Smith", CustomerId = customerId });

// build join
var jn = new JoinSqlBuilder<Customer, Customer>()
    .LeftJoin<Customer, Contact>(
        customer => customer.Id, 
        contact => contact.CustomerId,
        customer => new { CustomerId = customer.Id, CustomerName = customer.Name },
        contact => new { ContactId = contact.Id, ContactFullName = contact.FullName })
    .LeftJoin<Contact, PhoneNumber>(
        contact => contact.Id, 
        phone => phone.ContactId,
        null,
        phone => new { PhoneNumberId = phone.Id, phone.Number, phone.Type });

var all = db.Select<CustomerComplete>(jn.ToSql());

var customerHash = new Dictionary<int, Customer>();

foreach (var cc in all) 
{
    if (!customerHash.ContainsKey(customerId))
        customerHash[customerId] = new Customer { Id = cc.CustomerId, Name = cc.CustomerName };

    if (cc.ContactId == 0) continue; // no contacts for this customer

    var contact = customerHash[customerId].Contacts.Where(x => x.Id == cc.ContactId).FirstOrDefault();
    if (null == contact)
    {
        contact = new Contact
        {
            CustomerId = customerId,
            Id = cc.ContactId,
            FullName = cc.ContactFullName
        };

        // add contact
        customerHash[customerId].Contacts.Add(contact);
    }

    if (cc.PhoneNumberId == 0) continue; // no phone numbers for this contact

    contact.PhoneNumbers.Add(new PhoneNumber
    {
        ContactId = cc.ContactId,
        Id = cc.PhoneNumberId,
        Number = cc.Number,
        Type = cc.Type
    });
}

// our hierarchical customer list
var customers = customerHash.ToList();

Notez également que v4 semble prendre en charge une méthode beaucoup plus simple en utilisant l'attribut Reference, bien qu'il puisse effectuer plusieurs appels à la base de données. Voir les tests unitaires ici pour un exemple .




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi