Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Tipos Genericos (https://www.clubdelphi.com/foros/showthread.php?t=89157)

doctorhd 06-10-2015 06:45:49

Tipos Genericos
 
Hola a todos tengo en siguiente problema: Cree una clase que acepta un parámetro de tipo genérico <T>, la idea de este parámetro es que acepte clases que descienden de una clase en común, lo cual también podría definirse de este tipo <t:class>, para acotar su definición. El problema que tengo es como acceder a los campos que tiene el parámetro <T>, ya que este representa la clase que es pasada. Para que quede mas claro detallo el código:
Código Delphi [-]
{Clase base que puede ser pasada como parámetro genérico a TField}
type
    TDomain = class
    private
      FName:String;
      FTipoSQL:TFieldType;
      FLenFieldIn:Integer;
      FLenFieldOut:Integer;
    protected
      constructor Create(const AName:String; ATipoSQL:TFieldType; ALenFieldIn:Integer; ALenFieldOut:Integer);
    public
      destructor Destroy; override;
    public
      property Name:String read FName;
      property TipoSQL:TFieldType read FTipoSQL;
      property LenFieldIn:Integer read FLenFieldIn;
      property LenFieldOut:Integer read FLenFieldOut;
    end;

{Clase que recibe el parámetro de tipo genérico}
type
    TField(T:class,constructor)= class
    private
      FNameField:String;
      FNameIn:String;
      FNameOut:String;
      FDomain:T;
    private
      function getNamesIn(const Index:Integer):String;
      function getNamesOut(const Index:Integer):String;
      function SepararCadena(const Cadena: string; const Delim: Char): TStringList;
      procedure setDomain(ADomain:T);
    protected
      constructor Create(const ANameField:String; ANameIn:String; ANameOut:String; ADomain:T);
    public
      destructor Destroy; override;
    public
      property NameField: String read FNameField;
      property NameIn: String read FNameIn;
      property NameOut: String read FNameOut;
      property NamesIn[const Index: Integer]:String read getNamesIn;
      property NamesOut[const Index: Integer]:String read getNamesOut;
      property Domain:T read FDomain;
    end;


{Procedimiento en donde necesito acceder a los campos de la clase que es pasada como parámetro}
procedure TField(T.setDomain)(ADomain:T);
begin
  {Creamos el objeto Domain o sus descendientes}
  FDomain:=T(GetTypeData(PTypeInfo(TypeInfo(T)))^.ClassType.Create);

  {Aqui el problema, el compilador no reconoce los campos}
  FDomain.FTipoSQL:=ADomain.TipoSQL;
  FDomain.FLenFieldIn:=ADomain.LenFieldIn;
  FDomain.FLenFieldOut:=ADomain.LenFieldOut;
end;{procedure}
Como ven la clase recibe un parámetro <T> que es asignado a FDomain. Esta asignación necesito hacerla campo a campo (clonar el objeto). Me imagino que el compilador al no saber que tipo de parámetro sera pasado no admite especificar sus campos en forma literal, pero debe existir alguna forma de invocarlos....

nota:Cambie <> por (), ya que las etiquetas de código Delphi no lo muestran.

Saludos...

Casimiro Notevi 06-10-2015 09:58:41

Cita:

Empezado por doctorhd (Mensaje 497600)
nota:Cambie <> por (), ya que las etiquetas de código Delphi no lo muestran.

Sí, es un bug, pero puedes poner un espacio entre ellos y ya se verán bien.

Ñuño Martínez 06-10-2015 10:24:59

Una de las razones por las que no terminan de gustarme las generics (o templates, como las llaman en C++) es que confunde al programador. Como en este caso.

Si lo que quieres es que un procedimiento, función o variable admita o use objetos que deriven de cierta clase, entonces no debes usar generics, sino herencia. Basta con indicar la clase base y admitirá cualquier objeto cuya clase derive de dicha clase base. No sólo podrás discriminar qué clases usar, sino que además generará ejecutables más ligeros.

doctorhd 06-10-2015 15:06:36

Cita:

Empezado por Casimiro Notevi (Mensaje 497603)
Sí, es un bug, pero puedes poner un espacio entre ellos y ya se verán bien.

^\||/

Cita:

Empezado por Ñuño Martínez (Mensaje 497606)
no debes usar generics, sino herencia.

Ya lo había pensado, pero (siempre hay un pero), cuando accedes al campo (FDomain) desde fuera de la clase, solo tendrás acceso a los integrantes de la clase base (TDomain) en forma directa. Si quieres tener acceso a los integrantes de la clase descendiente tendrás que especificarlo en forma explicita, por ejemplo:
Código Delphi [-]
TDomainString(FDomain).MiCampo;
Suponiendo que TDomainString es descendiente de TDomain. La idea es que dicho acceso sea transparente:
Código Delphi [-]
FDomain.MiCampo;
Saludos...

mamcx 06-10-2015 15:30:23

Accediendo una propiedad privada como si fuera una publica? Uno de los conceptos fundamentales de la OO es el *encapsulamiento*. Estas yendo contra el viento y por eso sufres.

Y la forma que pones de ver domain es absurda.

Casi siempre un programador se pone a dar vueltas a una aparente restriccion tecnica es porque su diseño esta deficiente. Osea: Hacks son un code-smell (una indicacion poderosa, 90% de los casos, que estas contra el viento, en vez de solucionando un genuino problema)

doctorhd 06-10-2015 15:46:12

Cita:

Accediendo una propiedad privada como si fuera una publica?
Eso es un error de escritura de mi parte los correcto era hacer alusión a Domain.
Cita:

Y la forma que pones de ver domain es absurda.
...???

Caminante 06-10-2015 16:40:56

Cita:

Empezado por doctorhd (Mensaje 497600)
...la idea de este parámetro es que acepte clases que descienden de una clase en común...

Hola

Puedes crear una referencia de clase como campo en tu clase generica.

Me explico.

En lazarus cree una clase que representa una lista generica a objectos (TClientes, TArticulos, etc). Para eso defini un campo privado

Código Delphi [-]
Private
FTipoClass=TBaseClass;

Que esta definido asi:

Código Delphi [-]
TBaseClass=Class of TClaseBase;

En el codigo para crear los objectos de la lista hago asi

Código Delphi [-]
ItemList:=FTipoClass.create;

Claro que de todas formas es necesario hacer un cast para obtener la clase que deseo

Código Delphi [-]
MiCLiente:=TCliente(Items[1]).UnMetodo

Espero sea de utilidad

Saludos

mamcx 06-10-2015 17:03:47

Cita:

Empezado por mamcx (Mensaje 497611)
Y la forma que pones de ver domain es absurda.

Ok, podrias explicar que es lo que estas tratando de hacer? Cual es el objetivo de este codigo?

elrayo76 06-10-2015 23:09:00

Podrías explicar que quieres haer con el código que pones?

Saludos

doctorhd 07-10-2015 00:14:59

Las clases que expongo son parte de la capa de datos de una aplicación, mas específicamente TField almacena la definición de un campo de la base de datos, junto con TDomain que almacena las características del dominio al que pertenece dicho campo, ya explicado lo anterior, lo que quería lograr era asignar a Tfield que representa al campo, el tipo de dominio que este posee, el cual puede ser de distinto tipo (string, integer, etc), debido a esto pensé que usar tipos genéricos era buena idea para almacenar el tipo de dominio especifico de cada campo. Se que se puede usar herencia de la clase base TDomian para conseguir el mismo efecto, pero haciendo esto necesariamente hay que hacer cast para acceder a la clase descendiente, cuestión que quería evitar para hacer transparente el acceso a los datos a los clientes de dichas clases. La aplicación cliente no tiene porque saber que tipo de Dominio tiene un campo, si las restricciones de ingreso de dicho campo, las cuales son accesibles desde las clases descendientes...
Espero haberme hecho entender..

Saludos.

AgustinOrtu 07-10-2015 00:45:27

La clase TField ya existe en Delphi. De todos modos, segundo a mamcx y creo que no esta bien diseñado

ecfisa 07-10-2015 01:08:49

Hola doctorhd.

Opino igual que AgustinOrtu. De la clase TField podes obtener los datos de las columnas relativas a la tabla asociada a un TDataSet.

(O he perdido el rumbo y no estoy entendiendo lo que intentas hacer...)


Saludos :)

mamcx 07-10-2015 01:28:31

Cita:

Empezado por doctorhd (Mensaje 497634)
Las clases que expongo son parte de la capa de datos de una aplicación

Ok, estas haciendo un ORM ;). Hacer un ORM es de lo primero que hago cuando aprendo un nuevo lenguaje (y he hecho, con re-escrituras, un monton!) y justo ahora estoy diseñando un lenguaje relacional... y si vieras lo particularmente complejo que puede volverse el asunto.

El punto es que las BD y la OO no se llevan bien (tienen un "impedance mismatch"):

http://clubdelphi.com/foros/showpost...76&postcount=2

----

La parte mas importante del modelo relacional, es entender que una tabla es un valor, no un objeto!. Un valor como "1", "true", "hello world", Array(1, 2, 3), o sea como si en cada "momento" es un pantallazo estatico de la informacion, como una constante. Por lo tanto, una tabla es como un array, solo con multiples columnas.

----

Te voy a ahorrar un monton de tiempo y muchas vueltas de cabeza y te digo que:

1- Usa un ORM que ya este hecho. No creo que ninguno realmente sea bueno, pero sera mucho mejor que hacerlo. Te lo digo despues de intentar varios ORM en Delphi

2- El modelo que tiene sentido y exito en la OO es hacer como este proyecto:

https://github.com/StackExchange/dapper-dot-net

Código PHP:

public class Dog
{
    public 
intAge getset; }
    public 
Guid Id getset; }
    public 
string Name getset; }
    public 
floatWeight getset; }

    public 
int IgnoredProperty get { return 1; } }
}            

var 
guid Guid.NewGuid();
var 
dog connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)nullId guid });

dog.Count()
    .
IsEqualTo(1);

dog.First().Age
    
.IsNull();

dog.First().Id
    
.IsEqualTo(guid);

// NOTA EN ESPECIAL ESTO
var rows connection.Query("select 1 A, 2 B union all select 3, 4");

((int)
rows[0].A)
   .
IsEqualTo(1); 

Este tipo de proyectos se llaman "micro-ORM". Lo *importante* es que no peleean en contra de la BD. No intentan replicar (pobremente, debido a ser lenguajes OO) lo que la BD ya tiene/sabe. La BD es mejor haciendo consultas, ordenando, filtrando, uniendo y haciendo introspeccion de si misma que cualquier ORM.


Nota como la interface de Dapper no le huye al SQL. Ademas, es mas rapido que los ORM tradicionales de .NET (obvio: No esta re-implementando gran cosa).

La unica cosa sofisticada es que puede usarse el LINQ, que es algo facil en .NET. No se que tanto se pueda con Delphi hacer eso, pero creo que una version moderna de Delphi es muy viable.

Estudia dapper y lee sobre los micro-ORM que te abriran la mente y simplificaran mucho la vida.

P.D: Delphi basicamente permite hacer algo muy simple: Usa TClientDataset para obtener resultados, y una clase plana para ejecutar SQL. Un micro-ORM asi se puede resolver con unos, digamos, 7-8 funciones y eso es todo.

Lo que hace un micro-ORM es solo mapear una tabla a una clase, y ojala una clase "plana": Osea= Sin metodos, funciones ni propiedades complejas. Quizas de extra, hacer un ayudador para hacer query o para generar SQL.

Ya que como te explique, una tabla es un valor, esto es lo que realmente tiene sentido:

Código PHP:

OO.Cliente.Nombre DB.Cliente.Nombre 

Sin NADA MAS. Nota como la clase "Dog" es identica a un tipo "Record" de pascal.

Esto significa que si tienes una vista o un SQL que retorna campos que no son identicos a las clases que ya tienes... no haces herencia (bueno digamos que no herencias profundas, y a lo sumo, solo heredas propiedades y YA), no haces arboles complejos de objetos, nada. Crea una clase tipo "record" adicional y ya.

Maso asi:
Código Delphi [-]

TValor = class
  property Campo1:Int
  property Campo2:Int
end

List< TValor > = getData("SELECT 1 AS Campo1, 2 AS Campo2")

Nota que (aparte de usar un TClientDataset, que sigue siendo demasiado pero ya esta inventado) este es la UNICA forma que *realmente* tiene sentido y *verdaderamente* refleja lo que es la BD. Una tabla no tiene herencia, no hay funciones, etc. Campo1:Tipo es Campo1:Tipo eso es todo.

Esto te ahorra mucho tiempo, hace el codigo mas simple, claro y veloz.

Igual, si quieres hacer clases que encapsulen estas otras ya es otro tema.

AgustinOrtu 07-10-2015 01:44:16

Lo que explico Mario (si se me permite llamarte por tu nombre ;)) es basicamente lo que hago (intento) desde casi que inicio en el mundo del OO + Relacional

En las versiones mas modernas de Delphi es mas sencillo todavia, ya que podes crearte la clase que el te dijo, un TObjectList<TTuClase> y enlazarla por LiveBindings. En un plumazo tenes separada la logica de tu aplicacion, del acceso a los datos, de la presentacion visual

Yo creo lo mejor es dar un pequeño paso mas, y pedirle a una clase que te retorne la instancia en cuestion de la forma que el lo propone. Es decir, tus clases de negocio en un principio no tienen porque saber que van a ser guardadas en una BD

Si sigo con el ejemplo del Dog

Código Delphi [-]
TDog = class
public
  property Name: string read FName write SetAge;
  property Age: Integer read FAge write SetAge;
  procedure Run;
end;

Esa clase no sabe nada de que se la va a guadar en una BD para que sea persistente. Eso quiere decir que tu clase es testeable sin depender de ninguna BD. Podes probar que tanto las propiedades Name, como Age, como el metodo Run funcionan bien usando Unit Testing.

Luego, para levantarlo de una BD, harias algo como esto

Código Delphi [-]
function GetDog(const DogId: Integer): TDog;
begin
  Result := TDog.Create;
  OpenQuery('SELECT [Campos] from Dogs');
  Result.Name := Query.FieldByName('Name');
  Result.Age := Query.FieldByName('Age');
end;

Tambien es posible que crees otra clase, como comenta Mario, que no tenga ningun metodo, simplemente los campos que mapea de la BD. Entonces, para crear un Dog, podrias tener un constructor que recibe como parametro una instancia del TDatabaseDog de donde tomar el Name y el Age

El tema es bastante complejo pero siempre me gusta este tipo de debates :)

doctorhd 07-10-2015 03:21:49

Gracias a todos por sus consejos y comentarios, la verdad no he investigado profundamente el tema de ORM y he ido construyendo el modelo que tengo en la medida que la necesidad a ido surgiendo, actualmente tengo un modelo de varias capas, una capa de negocios que se encarga de las validaciones y restricciones propias del negocio para con los datos, mas abajo una capa pivot que se encarga de direccionar los datos a la capa que interactua con la BD. Esta capa pivot la construí con el objetivo de permitir cambiar de proveedor de datos si así fuera necesario, por ahora trabajo con Firefird, pero la idea es extenderlo a SqlServer y Postgress. La capa que interactua con la BD recibe de la capa pivot los datos y los envía a BD, principalmente a través de procedimientos almacenados. Todo el manejo de inserciones, eliminación, update, select y demás se lo dejo a la BD (como dijo Mamcx para algo existe SQL). Solo llamo los store procedure que se encargan de realizar las tareas. Todo esto del lado del servidor y montado sobre datasnap. Por el lado del cliente la visualización de los datos a través de ClientDataSet y TDSProviderConexion.

Cita:

Lo que hace un micro-ORM es solo mapear una tabla a una clase, y ojala una clase "plana": Osea= Sin métodos, funciones ni propiedades complejas.
Efectivamente así lo realizo una clase plana que se envía del cliente al servidor, inicialmente lo contrui con record por su simpleza, pero tuve que cambiar a una clase porque datasnap no soporta el tipo record como intercambio de datos entre servidor y cliente.

Las clases Tfield y TDomain, me sirven de apoyo para configurar tanto del lado del cliente como del servidor las especificaciones de cada campo, como su longitud, tipo, valores permitidos, etc. Esto me es muy útil para el ingreso y validación de los datos que suministra el usuario.

Hasta ahora mi modelo a funcionado, no digo que sea perfecto y obviamente se puede mejorar, mas aun con la experiencia de otros que ya han construido modelos con el mismo objetivo. Y como alguien dijo por ahí, para que inventar la rueda de
nuevo.

mancx, voy a revisar los enlaces y temas que me has propuesto, para expandir mis conocimientos.

Gracias a todos, un saludo...

AgustinOrtu 07-10-2015 03:52:34

No "ensucies" tus clases con ese tipo de validaciones estilo "Length > 30, error, el maximo es 30". Tus clases solamente hacen su trabajo, el cual es hacer negocios.

Es muy molesto tener que, en cada setter acordarse de poner el "aqui solamente aceptamos numeros enteros!". Y de pronto como decis, no es un modelo muy flexible para andar cambiando. Incluso si queres desactivarlo seria terminar comentando medio codigo fuente. No es la tecnica mas efectiva. Y eso es, porque como se comenta en el otro hilo que hablamos este tema, OO no es la solucion a todo. Simplemente hay cosas que se resuelven mejor usando otro paradigma.

De la misma manera que cuando empiezas a ver las estructuras de datos en los primeros años que estudias programacion, te enseñan primero los simples loops iterativos, luego te dan recursion, y te das cuenta de que algunos problemas son triviales de resolver usando una u otra tecnica (ejemplo clasico de los arboles, a quien se le ocurriria usar un for para recorrer un arbol binario??).

Aca hay un ejemplo de como hacerlo usando atributos: Using attributes in Delphi

Tambien hay otra forma que es muy interesante y por lejos la mas flexible de todas, es utilizando Aspect Oriented Programming (AOP). En este video se explica como hacerlo en Delphi. AOP te permitiria, en una unit separada tener toda tu logica de validacion de datos. Solamente tocando aca, tuneas todas las validaciones que se te antojen. Esto quiere decir que tu sistema en general "no se va a dar cuenta nunca" de que alguien esta monitoreando los valores permitidos y los que no. Esto es bueno porque simplemente sacas la unit, recompilas y tadá! Ahora los nombres pueden tener todos los caracteres que de la gana.

Tambien quiere decir que seria trivial serializar los parametros de configuracion de las validaciones hasta en un tonto fichero ini y con solo unos toques ahi ya podrias por ejemplo permitir, ahora 31 caracteres en el nombre de los clientes porque al jefe de turno le parece lo mas adecuado :)

AOP es una tecnica sumamente poderosa, y como se explica en el video, es muy bueno para implemtentar este tipo de cosas de forma horizontal en todo el sistema, pero a la vez "transparentemente"; notar tambien los otros casos que menciona que son buenos para atacar con AOP: el Loggin. Si uno quiere andar guardando registro de todo lo que pasa, es muy molesto el tener que andar acordandose de hacerlo en cada metodo. Ademas de que molesta, porque uno cuando esta programando cierto metodo quiere concentrarse solo en lo que hace el metodo, no de avisarle a la clase logger "hey mira, entre al metodo IncrementarExistenciaProudcto, son las 3 AM del dia Martes xx/xx/xxxx, el usuario que disparo la accion se llama juan, tiene nivel de acceso modo-dios, los parametros son: [...]"

ecfisa 07-10-2015 05:07:03

Ahora entiendo por donde van los tiros... :)

Como lo menciona mamcx, existe casi un punto de inflexión entre la OPP y las tecnologías de bases de datos relacionales. Son paradigmas diferentes y las soluciones que tratan de conciliarlas son pobres e ineficientes. (Object Relational Impedance Mismatch)

No es que no se pueda poner un clavo con una pinza... Es sólo que para eso, es mejor el martillo.

Saludos :)

elrayo76 07-10-2015 16:09:02

Este tema me intereso mucho, ya que intento hacer algo similar y no se por donde comenzar.

Lo que en mi caso pretendo es hacer un especie de framework para la conexión con la base de datos para luego poder cambiarlo si es que cambia el motor de base de datos. Luego tendría como dijeron las clases con las propiedades que serían cada uno de los campos de la base.

Las distintas clases las usaría no solo para acualizaciónde datos, sino para consulta de los datos de las tablas, etc.

Para los tipos, tamaño etc de los campos de la base yo implementaria un diccionario de datos donde guardar esta información, así sería configurable por cada pantalla, ya que un mismo dato puede que en alguna pantalla necesite mostrarlo con un tamaño y en otra con otro (digo por no entrar en esa pantalla).

Lo que quisiera es que me orienten en como armar ese mini framework que quiero. También si saben de donde se puede sacar algún códio fuene de un mini-ORM para estudiarlo se los agradecería.

Saludos,
El Rayo

mamcx 08-10-2015 00:14:45

Cita:

Empezado por elrayo76 (Mensaje 497655)
Lo que quisiera es que me orienten en como armar ese mini framework que quiero. También si saben de donde se puede sacar algún códio fuene de un mini-ORM para estudiarlo se los agradecería.

Dapper, el que puse, es el mas "famoso" de esa categoria, al menos en lo que he visto. Si buscar en google veras muchos mas.

P,D: Me acorde que escribi sobre eso hace años:

http://edn.embarcadero.com/article/32388
http://blog.elmalabarista.com/post/4...h-un-mejor-rad

Que pueden verse como un micro-ORM, en pocas lineas de delphi ;)

Cita:

hacer un especie de framework para la conexión con la base de datos para luego poder cambiarlo si es que cambia el motor de base de datos.
Un punto para ambos: Programar para el caso incierto, futuro de *si es que a lo mejor quien sabe, yo realmente se es X pero y que pasa si la luna se pone roja y toca usar Y???* es una de las formas mas *populares* entre nosotros los programadores de perder el tiempo.

Que tan igual es Firebird a Sql Server? Superficialmente, mucho, pero en la *practica*? A parte de los mas elementales SELECTs no hay mucho que se pueda compartir entre motores, Asi que piensen: Que es mas productivo, practico y realista: Hacer decenas de clases que intenten abstraer (aun mas de lo que el estandar SQL mas elemental + librerias de acceso a datos *ya hacen*) y todo el esfuerzo que eso implica VS hacer asi:

Código Delphi [-]

if Engine='sqlServer' then
   return 'SELECT sqlServer'
.....
.....

Chequen estas librerias:

https://github.com/krisajenkins/yesql
https://bitbucket.org/rick/jasql

El truco que tienen, muy obvio (y que en mis articulos apunte de una forma menos practica!) es que puedes convertir el SQL en "constantes". Usando jasql, uno tiene un archivo asi:

Código SQL [-]
-- name: create-user
INSERT INTO users (name, email) VALUES(@name, @email)

-- name: find-one-user-by-email
SELECT id,name,email FROM users WHERE email = @email LIMIT 1

"name: create-user" es un llave al sql, que desde el codigo se invoca asi:

Código PHP:

var jaSql JaSql.FromFile("queries.sql");
using (var cn = new SQLiteConnection("<your connection string here>"))
using (var jaRunner jaSql.CreateRunner(cn))
{
  
jaRunner.Execute("create-users-table");

  
jaRunner.Execute("create-user", new {name "John Doe"email "j.doe@verymuchnotalive.com"});
  var 
user jaRunner.Query<User>("find-one-user-by-email", new {Email "j.doe@verymuchnotalive.com"}).First();



Cita:

Las clases Tfield y TDomain, me sirven de apoyo para configurar tanto del lado del cliente como del servidor las especificaciones de cada campo, como su longitud, tipo, valores permitidos, etc. Esto me es muy útil para el ingreso y validación de los datos que suministra el usuario.
Ok, ya veo que lo que buscan tiene que ver con ORM, pero es mas acerca de como soportar el escenario de dejar configurable la app/tablas/formularios/etc.

Ahora es popular usar JSON en blob de una tabla para guardar arboles de objetos/configuraciones, pero antes que los hipsters entraran en escena uno simplemente usaba tablas con campos y ya. Por ejemplo, digamos que uno tiene:

Código PHP:

FormLogin =
  
user Num check notEmpty
  pwd 
Num check notEmpty
check user 
pwd 

Pues uno puede aceptar que eso exactamente, puede hacerlo la BD y generar el sql que construye esa tabla con esos checks. Si el formulario cambia, pues se hace DROP a la tabla y se recrea. Es ideal tener una BD de usuario dinamico separada de la estatica del sistema, que es muy facil en la mayoria de los motores, o usar SQLITE que se invento especificamente para esto: Para ser un excelente sistema de creacion de formatos de archivos personalizados (que reemplace .INI, .XML, etc)

Usando introspeccion se puede extraer mucho de una BD. Si el asunto se pone complejo es porque realmente se esta intentando re-crear un sistema de datos personalizado, y eso si que es complejo.

FoxPro efectivamente guardaba proyectos, formularios, reportes, tablas y base datos en tablas .dbf. Eso significaba que uno podia abrir un formulario y hacer el insert con un nuevo campo si se respetaba las reglas de como debe ser la informacion.

Pero eso tambien signfica que mientras mas personalizado quieras que el usuario haga sus formularios, informes, menus, etc mas cerca estas de re-inventar foxpro o acces.

Si ese es su objetivo, les digo que estoy haciendo eso, creando ese tipo de herramienta, y no me chocaria tener mas brazos ;) El punto es que lo estoy haciendo en .NET + F#

elrayo76 08-10-2015 02:34:44

Gracias por la respuesta.

De todo lo que escribiste, te puedo decir que no pretendo hacer un ORM. Lo que pretendo es hacer alguna forma de que los desarrolladores no tengan que escribir código SQL en las aplicaciones y solo llamen a métodos de las distintas clases para ejecutar alguna consulta

Lo que tengo en mente es algo como lo siguiente:

1) Se tiene una clase que solo contiene los campos de las tablas como propiedades con sus respectivos read y write. Ejemplo: TCliente.
2) Otra clase que hace uso de la anterior contendría todos los métodos necesarios para Listar, Cargar, insertar, actualizar, eliminar. Podría luego el desarrollador en estas clases crear métodos si se necesita haceer algo mas específico de lo que ya exista. Ejemplo: TClienteServicios.
3) Tener otra clase que solo sirva para hacer la conexión con las distintas bases de datos que sean necesarias (dentro del mismo motor de base de datos). Esta clase podría ser llamada en el constructor o de alguna forma por la clase anterior. Ejemplo: TConexion
4) Si se quiere y se necesita se tendría una clase para armar la condición (WHERE), pasando solamente el nombre del campo, el tipo de condición (=, <>, IN, >, <) y el valor a comparar contra el campo. Esta condición se pasaría por ejemplo al método Listar de la clase TClienteServicio para filtrar los resultados que trae.
5) Igual que el punto 4 se podría crear otra clase para hacer el ordenamiento de los datos devueltos por el Listar.

En principio lo pense con tablas, pero podría usarse con vistas. Y algo que deje de lado pero que hay que tener en cuenta es un método para ejecutar Store Procedures, pasando el nombre del mismo y los parámetros (puede haber mas cosas para evaluar pero eso es lo básico).

Saludos,
El Rayo


La franja horaria es GMT +2. Ahora son las 08:51:53.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi