LINQ y persistencia de operaciones de datos en memoria
-
lunes, 07 de mayo de 2012 12:47
Hola, buenos días.
Tengo un problema con Linq y la gestión de operaciones de datos en memoria.
Dispongo de una aplicación en la cual el usuario abre un formulario y realiza cambios en el origen de datos. El tema es que lo que quiero hacer, es guardar esos cambios en memoria y luego con un botón Aceptar salvarlos. Mientras tanto el usuario puede realizar cuantas operaciones desee (Agregar, Modificar o Eliminar). Traté con un BindingSource, sin embargo no logré el resultado deseado.
Ya probé de varias maneras, pero no puedo persistir esos datos sin llamar antes al SubmitChanges(), ya que si intento acceder a los Datos de la entidad, me arroja una Excepción.
Les dejo parte de mi código.
Formulario:
private void frmAMHorarios_Load(object sender, EventArgs e)
{
bsHorarios.DataSource = negHora.Traer();
bsHorarios.AllowNew = true;
}
private void AgregarEnMemoria()
{
Horarios Hora = new Horarios();
Hora.Hora_Inicial = TimeSpan.Parse(dtpHoraInicial.Text);
Hora.Hora_Final = TimeSpan.Parse(dtpHoraFinal.Text);
Hora.Pers_id = (int)cboPersonas.SelectedValue;
Hora.Horario_Dia.AddRange(HorarioDias());
Hora.Empr_id = (int)cboEmpresas.SelectedValue;
Hora.Activo = true
// Sin el agregado explícito los cambios no se reflejan en BD.
negHora.Agregar(Hora); // Negocio negHorarios
bsHorarios.Add(Hora); // BindingSource Horarios
}
private void btnAceptar_Click(object sender, EventArgs e){
// Aplica cambios en base de Datos.
bsHorarios.EndEdit();
negHora.Guardar();
}
Negocio (NegHorarios)
public void Agregar(Horarios obj){
ctx.Horarios.InsertOnSubmit(obj);
}
public void Guardar(){
ctx.SubmitChanges();
}
¿Alguna idea? Desde ya, gracias y saludos.
- Editado Agustín Gonzalez lunes, 07 de mayo de 2012 13:33
Todas las respuestas
-
lunes, 07 de mayo de 2012 13:27
Hola, ¿y cual es la excepción que te da?
Revisando tu código, ¿qué es negHora y bsHorarios?
Si usas Entity Framework y vas a hacer operaciones en modo desconectado para luego volvarlas en la base de datos, te recomiendo esta lectura ya que el Entity Framework te puede dar algun que otro dolor de cabeza
Entity Framework y los indices únicos
-
miércoles, 09 de mayo de 2012 13:30
Hola.
Supongo que estas usando Entity Framework, para hacer eso que dices te recomendaria usar POCO, ya que con estos crearias una instancia de un objeto y lo puedes manejar como quieras, y cuando temines de hacerlo solo debes salvar los cambios. Pero si lo que quieres es usar esa instancia desde cualquier parte de tu aplicacion te recomiendo que te crees una variable global o una Clase estatica que guarde una referncia de la instancia de la clase, asi podras manipularla a tu antojo.
De todas formas, seria bueno que expliques bien lo que quieres y con exactitud que tecnologia estas usando para poder tener una mejor idea.
Saludos.
-
miércoles, 09 de mayo de 2012 15:23
Buenas, en negHora se hallan las reglas de negocio correspondientes a "Horarios". bsHorarios, es el BindingSource. La excepción básicamente es la siguiente: El código de usuario no controló la InvalidOperationException: No se puede quitar una entidad que no se ha adjuntado.
Según tengo entendido, esto se debe a que los objetos no son grabados hasta el SubmitChanges(). ¿Como podría yo entonces trabajarlos en memoria? Un ejemplo simple es cuando el usuario antes de oprimir el botón guardar, se arrepiente y quiere borrar un registro que todavía no está en un almacenamiento fijo (en este caso me lanzaría la excepción).
By Alan: Yo trabajo con LINQ (de la Vers 3.5). Es similar a Entity Framework, en la mayoría de los aspectos. Lo de declarar instancias, es medio complejo, lo pensé, pero por ejemplo, si el usuario usuario realiza operaciones ABM en una lista, tendría que ir marcando los objetos en otra aparte en memoria y después verificar cuales son los que están siendo agregados, modificados o eliminados o revertir todo si el usuario e arrepiente, etc. Mi pregunta es si no hay una herramienta "nativa", que pueda realizar esta tarea, tal cual existe en ADO.
Saludos!
- Editado Agustín Gonzalez miércoles, 09 de mayo de 2012 15:30
-
miércoles, 09 de mayo de 2012 20:07
Hola.
Supongo que usas LINQ to SQL.
Con relacion a lo de una herramienta?, si, Entity FrameWork le funciona bien, tiene seguimiento de cambios y solo guarda los objetos que han sido modificados, todo esto se habilita con la opcion del proxy que se genera automaticamente si no lo desea.
Seria bueno que probaras algun ejemplo con entity y lo compares con el que usas actualmente a ver que tal los resultados.
Si lo quieres hacer como estas, te recomendaria que crees una lista con los objetos que estas usando, estos si no cierras la clase que los instancio no deberian destruirse y cuando acabes de trabajar con ellos si te interesa simplemente guardas los cambios.
PD: Mire la definicion de la excepcion que le esta lanzando InvalidOperationException (Clase)
Saludos
-
miércoles, 09 de mayo de 2012 22:08
Hola.
Pero hasta donde se todo esto deberia trabajar sobre la misma instancia, es decir, el grafo de objetos no debe cambiar... podrias intentar inyectando al metodo agregar el contexto actual.
Saludos.
Nicolás Herrera
Bogotá - Colombia
BLOG - Leader Group BogotaDotNet
"Daría todo lo que sé, por la mitad de lo que ignoro." Rene Descartes -
lunes, 14 de mayo de 2012 13:18
Buenas, les comento que trasladé el proyecto de LINQ a Entity, y este me permitió realizar acciones como eliminar en memoria (aunque con muchas "mañas", en especial en el tema de las relaciones de Muchos a Muchos). La cuestión está cuando modifico en memoria. Por ejemplo el Usuario agrega un objeto, pero antes de guardarlo, quiere modificarlo. Mi rutina sería de la siguiente manera:
public void Modificar(Horarios obj) { Horarios objM = (from l in ctx.Horarios where obj.Hora_id.Equals(l.Hora_id) select l).SingleOrDefault(); objM.Activo = obj.Activo; objM.Empr_id = obj.Empr_id; objM.Hora_Final = obj.Hora_Final; objM.Hora_Inicial = obj.Hora_Inicial; objM.Observacion = obj.Observacion; objM.Pers_id = obj.Pers_id; }
El tema está en que un objeto en memoria, aún no tiene ID, y entonces cuando lo compara el mismo es "0", quedándome "objM" con valor NULL, lo cual, obviamente, me genera una excepción. Mi pregunta es de que manera podría solucionar este inconveniente, es decir si hay alguna forma de "obtener" este objeto que aún no está guardado. Desde ya gracias.
Saludos!
- Editado Agustín Gonzalez lunes, 14 de mayo de 2012 13:19
-
lunes, 14 de mayo de 2012 13:30
Hola Agustin,
en los EntityObject tienes un campo EntiyState. Este valor te puede ayudar a saber si un objecto ha sido grabado o no. Quizá de esta formas puede hacer una búsqueda de los objectos añadidos a tu DataContext y que no han sido grabados.
Ahora bien, el problema que se plantea es que si tiene dos objetos añadidos que no han sido grabados. ¿Cómo sabrías cual de los dos objectos es el que se está intentando editar? Quizá es este contexto te interese generar tu lo identificadores de los objectos en vez de delegar esta tarea a la base de datos.
- Marcado como respuesta Agustín Gonzalez lunes, 14 de mayo de 2012 15:22
-
lunes, 14 de mayo de 2012 15:18
Muchas gracias a todos, ya pude solucionarlo. Lo que hice fue manejar el objeto en Memoria con un ID autogenerado según la siguiente rutina.
/// <summary> /// Retorna nuevo ID a asignar /// </summary> /// <returns></returns> private int TraerNuevoID() { int i = 0; var c = (from l in ctx.Horarios select new { l.Hora_id }).ToList(); // Máximo ID desde Base de Datos. i = c.ToList().Max(p => p.Hora_id); // Suma del ID según los objetos que se encuentren en memoria. foreach (System.Data.Objects.ObjectStateEntry e in ctx.ObjectStateManager.GetObjectStateEntries( EntityState.Added)) { // Si la entidad es de tipo Horarios if (e.Entity is Horarios) { i++; } } return i + 1; // Último ID + 1 }
Esto permite que si hay que modificar un objeto aún no persistido, lo busco, como bien mencionó Sergio, mediante el EntityState y este ID, que luego es sobreescrito con el Identity que le asigna la Base de Datos.
Este objeto no persistido, se obtiene de la siguiente manera:
if (e.Entity is Horarios) { Horarios Hora = (Horarios)e.Entity; if (Hora.Hora_id.Equals(obj.Hora_id)) { return Hora; } }
Sin más, doy por solucionado el tema.
Saludos y una vez más, gracias por la colaboración de todos!
- Editado Agustín Gonzalez lunes, 14 de mayo de 2012 15:22
- Marcado como respuesta Agustín Gonzalez lunes, 14 de mayo de 2012 15:22

