[ORM-Lite] PetaPoco - El blog de Javier Torrecilla

[ORM-Lite] PetaPoco

Introducción

En este post voy a continuar la serie acerca de ORMS ligeros donde ya he hablado de Dapper y Massive, en esta ocasion voy a tratar PetaPoco.

¿Qué es PetaPoco?

PetaPoco es otro mini ORM basado en Massive, pero a diferencia de este para trabajar con objetos POCO.

Algunas de sus caracteristicas:

- Es un único fichero que sea agrega al proyecto.

- Permite trabajar con objetos POCO.

- Permite la generación de los objetos POCO a través de unas plantillas T4.

¿Por dónde empezar?

Para poder empezar a trabajar con PetaPoco, podemos realizar de la siguiente manera:

- Agregando desde Nuget el paquete a nuestro proyecto.

- Agregar el fichero desde GitHub.

En el ejemplo que voy a utilizar, he agregado el paquete desde Nuget. Y he configurado las plantillas de tal forma que me genere las clases poco contra SQL Server y las mismas tablas que hemos utilizado en ejemplos anteriores.

Algunos Ejemplos

Gracias a la plantilla T4, se ha generado la siguiente clase en mi proyecto:

   1: public partial class PetaPocoDB : Database
   2:     {
   3:         public PetaPocoDB() 
   4:             : base("")
   5:         {
   6:             CommonConstruct();
   7:         }
   8:  
   9:         public PetaPocoDB(string connectionStringName) 
  10:             : base(connectionStringName)
  11:         {
  12:             CommonConstruct();
  13:         }
  14:         
  15:         partial void CommonConstruct();
  16:         
  17:         public interface IFactory
  18:         {
  19:             PetaPocoDB GetInstance();
  20:         }
  21:         
  22:         public static IFactory Factory { get; set; }
  23:         public static PetaPocoDB GetInstance()
  24:         {
  25:             if (_instance!=null)
  26:                 return _instance;
  27:                 
  28:             if (Factory!=null)
  29:                 return Factory.GetInstance();
  30:             else
  31:                 return new PetaPocoDB();
  32:         }
  33:  
  34:         [ThreadStatic] static PetaPocoDB _instance;
  35:         
  36:         public override void OnBeginTransaction()
  37:         {
  38:             if (_instance==null)
  39:                 _instance=this;
  40:         }
  41:         
  42:         public override void OnEndTransaction()
  43:         {
  44:             if (_instance==this)
  45:                 _instance=null;
  46:         }
  47:         
  48:         public class Record<T> where T:new()
  49:         {
  50:             public static PetaPocoDB repo { get { return PetaPocoDB.GetInstance(); } }
  51:             public bool IsNew() { return repo.IsNew(this); }
  52:             public object Insert() { return repo.Insert(this); }
  53:             public int Update(IEnumerable<string> columns) { return repo.Update(this, columns); }
  54:             public static int Update(string sql, params object[] args) { return repo.Update<T>(sql, args); }
  55:             public static int Update(Sql sql) { return repo.Update<T>(sql); }
  56:             public int Delete() { return repo.Delete(this); }
  57:             public static int Delete(string sql, params object[] args) { return repo.Delete<T>(sql, args); }
  58:             public static int Delete(Sql sql) { return repo.Delete<T>(sql); }
  59:             public static int Delete(object primaryKey) { return repo.Delete<T>(primaryKey); }
  60:             public static bool Exists(object primaryKey) { return repo.Exists<T>(primaryKey); }
  61:             public static T SingleOrDefault(object primaryKey) { return repo.SingleOrDefault<T>(primaryKey); }
  62:             public static T SingleOrDefault(string sql, params object[] args) { return repo.SingleOrDefault<T>(sql, args); }
  63:             public static T SingleOrDefault(Sql sql) { return repo.SingleOrDefault<T>(sql); }
  64:             public static T FirstOrDefault(string sql, params object[] args) { return repo.FirstOrDefault<T>(sql, args); }
  65:             public static T FirstOrDefault(Sql sql) { return repo.FirstOrDefault<T>(sql); }
  66:             public static T Single(object primaryKey) { return repo.Single<T>(primaryKey); }
  67:             public static T Single(string sql, params object[] args) { return repo.Single<T>(sql, args); }
  68:             public static T Single(Sql sql) { return repo.Single<T>(sql); }
  69:             public static T First(string sql, params object[] args) { return repo.First<T>(sql, args); }
  70:             public static T First(Sql sql) { return repo.First<T>(sql); }
  71:             public static List<T> Fetch(string sql, params object[] args) { return repo.Fetch<T>(sql, args); }
  72:             public static List<T> Fetch(Sql sql) { return repo.Fetch<T>(sql); }
  73:             public static List<T> Fetch(long page, long itemsPerPage, string sql, params object[] args) { return repo.Fetch<T>(page, itemsPerPage, sql, args); }
  74:             public static List<T> Fetch(long page, long itemsPerPage, Sql sql) { return repo.Fetch<T>(page, itemsPerPage, sql); }
  75:             public static List<T> SkipTake(long skip, long take, string sql, params object[] args) { return repo.SkipTake<T>(skip, take, sql, args); }
  76:             public static List<T> SkipTake(long skip, long take, Sql sql) { return repo.SkipTake<T>(skip, take, sql); }
  77:             public static Page<T> Page(long page, long itemsPerPage, string sql, params object[] args) { return repo.Page<T>(page, itemsPerPage, sql, args); }
  78:             public static Page<T> Page(long page, long itemsPerPage, Sql sql) { return repo.Page<T>(page, itemsPerPage, sql); }
  79:             public static IEnumerable<T> Query(string sql, params object[] args) { return repo.Query<T>(sql, args); }
  80:             public static IEnumerable<T> Query(Sql sql) { return repo.Query<T>(sql); }
  81:             
  82:             private Dictionary<string,bool> ModifiedColumns;
  83:             private void OnLoaded()
  84:             {
  85:                 ModifiedColumns = new Dictionary<string,bool>();
  86:             }
  87:             protected void MarkColumnModified(string column_name)
  88:             {
  89:                 if (ModifiedColumns!=null)
  90:                     ModifiedColumns[column_name]=true;
  91:             }
  92:             public int Update() 
  93:             { 
  94:                 if (ModifiedColumns==null)
  95:                     return repo.Update(this); 
  96:  
  97:                 int retv = repo.Update(this, ModifiedColumns.Keys);
  98:                 ModifiedColumns.Clear();
  99:                 return retv;
 100:             }
 101:             public void Save() 
 102:             { 
 103:                 if (repo.IsNew(this))
 104:                     repo.Insert(this);
 105:                 else
 106:                     Update();
 107:             }
 108:         }
 109:     }

 

Y las clases relativas a mis entidades:

   1: [TableName("CandidateInfo")]
   2:     [PrimaryKey("CandidateId", autoIncrement=false)]
   3:     [ExplicitColumns]
   4:     public partial class CandidateInfo : PetaPocoDB.Record<CandidateInfo>  
   5:     {
   6:         [Column] 
   7:         public Guid CandidateId 
   8:         { 
   9:             get
  10:             {
  11:                 return _CandidateId;
  12:             }
  13:             set
  14:             {
  15:                 _CandidateId = value;
  16:                 MarkColumnModified("CandidateId");
  17:             }
  18:         }
  19:         Guid _CandidateId;
  20:  
  21:         [Column] 
  22:         public string CandidateName 
  23:         { 
  24:             get
  25:             {
  26:                 return _CandidateName;
  27:             }
  28:             set
  29:             {
  30:                 _CandidateName = value;
  31:                 MarkColumnModified("CandidateName");
  32:             }
  33:         }
  34:         string _CandidateName;
  35:  
  36:         [Column] 
  37:         public string CandidateLastName 
  38:         { 
  39:             get
  40:             {
  41:                 return _CandidateLastName;
  42:             }
  43:             set
  44:             {
  45:                 _CandidateLastName = value;
  46:                 MarkColumnModified("CandidateLastName");
  47:             }
  48:         }
  49:         string _CandidateLastName;
  50:  
  51:         [Column] 
  52:         public DateTime CandidateBirthDate 
  53:         { 
  54:             get
  55:             {
  56:                 return _CandidateBirthDate;
  57:             }
  58:             set
  59:             {
  60:                 _CandidateBirthDate = value;
  61:                 MarkColumnModified("CandidateBirthDate");
  62:             }
  63:         }
  64:         DateTime _CandidateBirthDate;
  65:  
  66:         [Column] 
  67:         public byte[] CandidatePhoto 
  68:         { 
  69:             get
  70:             {
  71:                 return _CandidatePhoto;
  72:             }
  73:             set
  74:             {
  75:                 _CandidatePhoto = value;
  76:                 MarkColumnModified("CandidatePhoto");
  77:             }
  78:         }
  79:         byte[] _CandidatePhoto;
  80:  
  81:         [Column] 
  82:         public int CandidateCountry 
  83:         { 
  84:             get
  85:             {
  86:                 return _CandidateCountry;
  87:             }
  88:             set
  89:             {
  90:                 _CandidateCountry = value;
  91:                 MarkColumnModified("CandidateCountry");
  92:             }
  93:         }
  94:         int _CandidateCountry;
  95:  
  96:         [Column] 
  97:         public int CandidateCity 
  98:         { 
  99:             get
 100:             {
 101:                 return _CandidateCity;
 102:             }
 103:             set
 104:             {
 105:                 _CandidateCity = value;
 106:                 MarkColumnModified("CandidateCity");
 107:             }
 108:         }
 109:         int _CandidateCity;
 110:  
 111:         [Column] 
 112:         public string CandidateEmail 
 113:         { 
 114:             get
 115:             {
 116:                 return _CandidateEmail;
 117:             }
 118:             set
 119:             {
 120:                 _CandidateEmail = value;
 121:                 MarkColumnModified("CandidateEmail");
 122:             }
 123:         }
 124:         string _CandidateEmail;
 125:  
 126:     }
 127: [TableName("CountryInfo")]
 128: [PrimaryKey("CountryID")]
 129: [ExplicitColumns]
 130: public partial class CountryInfo : PetaPocoDB.Record<CountryInfo>  
 131: {
 132:     [Column] 
 133:     public int CountryID 
 134:     { 
 135:         get
 136:         {
 137:             return _CountryID;
 138:         }
 139:         set
 140:         {
 141:             _CountryID = value;
 142:             MarkColumnModified("CountryID");
 143:         }
 144:     }
 145:     int _CountryID;
 146:  
 147:     [Column] 
 148:     public string CountryName 
 149:     { 
 150:         get
 151:         {
 152:             return _CountryName;
 153:         }
 154:         set
 155:         {
 156:             _CountryName = value;
 157:             MarkColumnModified("CountryName");
 158:         }
 159:     }
 160:     string _CountryName;
 161:  
 162: }
 163:  
 164: [TableName("CityInfo")]
 165: [PrimaryKey("CityID")]
 166: [ExplicitColumns]
 167: public partial class CityInfo : PetaPocoDB.Record<CityInfo>  
 168: {
 169:     [Column] 
 170:     public int CityID 
 171:     { 
 172:         get
 173:         {
 174:             return _CityID;
 175:         }
 176:         set
 177:         {
 178:             _CityID = value;
 179:             MarkColumnModified("CityID");
 180:         }
 181:     }
 182:     int _CityID;
 183:  
 184:     [Column] 
 185:     public string CityName 
 186:     { 
 187:         get
 188:         {
 189:             return _CityName;
 190:         }
 191:         set
 192:         {
 193:             _CityName = value;
 194:             MarkColumnModified("CityName");
 195:         }
 196:     }
 197:     string _CityName;
 198:  
 199:     [Column] 
 200:     public int CountryID 
 201:     { 
 202:         get
 203:         {
 204:             return _CountryID;
 205:         }
 206:         set
 207:         {
 208:             _CountryID = value;
 209:             MarkColumnModified("CountryID");
 210:         }
 211:     }
 212:     int _CountryID;
 213:  
 214: }

Bien el primer paso vamos a ver como realizar un conjunto  de consultas a la Base de Datos:

Consultar Toda la Tabla

 

   1: var db = PetaPocoDB.GetInstance();
   2: var candidates = db.Fetch<PetaPoco.CandidateInfo>("SELECT * FROM CANDIDATEINFO");
   3: foreach (var candidate in candidates)
   4: {
   5:     Console.WriteLine(String.Format("Name: {0}", candidate.CandidateName));
   6: }

 

Consultar Filtrando

   1: var candidates = db.Fetch<PetaPoco.CandidateInfo>("SELECT * FROM CANDIDATEINFO WHERE CANDIDATELASTNAME LIKE @0","%Puertas%");
   2:  
   3:            foreach (var candidate in candidates)
   4:            {
   5:                Console.WriteLine(String.Format("Name: {0}", candidate.CandidateName));
   6:            }

 

   1: var candidates = db.Fetch<PetaPoco.CandidateInfo>(PetaPoco.Sql.Builder.
   2:                                                                     Select("*").
   3:                                                                     From("CandidateInfo").
   4:                                                                     Where("CandidateLastName like @0", "%Puertas%"));
   5:  
   6:             foreach (var candidate in candidates)
   7:             {
   8:                 Console.WriteLine(String.Format("Name: {0}", candidate.CandidateName));
   9:             }

 

Consulta Scalar

   1: var results = db.ExecuteScalar<long>("SELECT COUNT(*) FROM CANDIDATEINFO");
   2: Console.WriteLine(results.ToString());

Insertar un Dato

   1: var candidate = new CandidateInfo
   2:     {
   3:         CandidateName = "Álvaro",
   4:         CandidateLastName = "Torrecilla",
   5:         CandidateEmail = "a@torrecilla.com",
   6:         CandidateBirthDate = Convert.ToDateTime("30/12/2009"),
   7:         CandidateCountry = 1,
   8:         CandidateCity = 1
   9:     };
  10: db.Insert(candidate);

Actualizar un Dato

   1: var candidate = new CandidateInfo
   2: {
   3:     CandidateName = "Álvaro",
   4:     CandidateLastName = "Torrecilla",
   5:     CandidateEmail = "a@torrecilla.com",
   6:     CandidateBirthDate = Convert.ToDateTime("28/12/2009"),
   7:     CandidateCountry = 1,
   8:     CandidateCity = 1
   9: };
  10: db.Update(candidate, new Guid("00000000-0000-0000-0000-000000000000"));

Eliminar un Dato

   1: db.Delete<CandidateInfo>(new Guid("00000000-0000-0000-0000-000000000000"));

Peculiaridades

Durante las pruebas y examinando el código me he encontrado con algunas cosas curiosas:

- Los métodos IsNew y Save solo funcionan con columnas definidas en la Base de datos como Identity.

- Para Base de Datos Oracle se puede configurar a una determinada columna una secuencia.

- El mapeo de campos de tipo Image de SQL server los realiza a NVarchar por lo que genera problemas a la hora de generar inserciones a la BD.

- Si existe un valor por defecto definido en una columna de la BD, no lo utiliza, sino que genera el comando completo.

 

Conclusiones

PetaPoco nos permite de una forma rápida generar las clases POCO de nuestra BD gracias a la utilización de unas Plantillas T4, lo cual nos permite configurar y aportar nuestras propias mejoras a las mismas.

Tiene cosas mejorables, pero al ser un fichero que agregamos a nuestro proyecto, podemos incluir las características que consideremos oportunas.

Published 10/1/2012 11:06 por Javier Torrecilla
Archivado en: ,,,,,
Comparte este post:
http://geeks.ms/blogs/jtorrecilla/archive/2012/01/10/orm-lite-petapoco.aspx

Comentarios

# Comparativa ORM-Lite, EF y ADO.NET

Introducción A raíz de la serie de post que estoy escribiendo acerca de ORMS ligeros con ( Dapper , Massive

Thursday, January 12, 2012 12:06 PM por El blog de Javier Torrecilla

# Comparativa ORM-Lite, EF y ADO.NET

Introducción A raíz de la serie de post que estoy escribiendo acerca de ORMS ligeros con

Thursday, January 12, 2012 12:07 PM por El blog de Javier Torrecilla

# Agenda MVP ( del 17 al 22 de Enero 2012)

Artículos Error: error undefined in What’s New (Activity Feeds) By Pablo Peralta

Tuesday, January 17, 2012 6:15 PM por MVP Factor