none
Actualización en base de datos usando STE RRS feed

  • Pregunta

  • Muy buenas,

    Sigo investigando con EF y STE, y ahora me he topado con una "pequeña" incidencia de nada... no puedo grabar en base de datos!Estoy utilizando SQL Server Compact ED. y os pongo el código que de momento estoy tirando. Estoy utilizando una implementación "a mi manera" del patrón repository.

    Más que nada por ir viendo temas, sobre todo de buenas prácticas, ya que aunque la aplicación la he preparado en capas y estoy usando repositorios y demás, no es estrictamente necesario. Posteo algo de código a ver si es que estoy muy zote y se me ha olvidado algun tema esencial.

    Este es el repositorio, que utiliza una clase ImportMode de STE y el contexto Infraestructure.Data.DataContext.

    Aunque he visto que se recomienda en el patrón repositorio que la creación del contexto no se haga dentro de ellos, también he visto que se recomienda que los contextos se basen en el patrón "short-lived context". Como esta aplicación es de laboratorio, me he inclinado por crear el contexto dentro de los repositorios. Ya tendré tiempo de refinar el código... implementar contratos mediante interfaces, crear pruebas unitarias.. etc. Primero necesito el concepto básico, y ese aún no lo tengo...

    Bueno, que me enrollo... el repositorio: 

    Public Class ImportModeRepository
    
     Public Function GetAll() As IEnumerable(Of ImportMode)
    
      Using context As New Infraestructure.Data.DataContext
       Return context.ImportModes
      End Using
    
     End Function
    
     Public Function GetElementById(ByVal id As Integer) As ImportMode
    
      If id <= 0 Then
       Throw New ArgumentException("id")
      End If
    
      Dim context As New Infraestructure.Data.DataContext
      Return context.ImportModes.Where(Function(c) c.ID = id).Single
    
     End Function
    
     Public Sub addImportMode(ByVal importMode As ImportMode)
    
      If importMode Is Nothing Then
       Throw New ArgumentNullException("fileMap")
      End If
    
      Using context As New Infraestructure.Data.DataContext
    
       context.ImportModes.AddObject(importMode)
       context.SaveChanges()
       context.AcceptAllChanges()
    
      End Using
    
     End Sub
    
    End Class
    
    

    Esta es la clase cliente del repositorio, muy sencillita, ya que sólo se dedica a hacer un "wrapper" de los métodos del repositorio.

    Public Class ImportModeManager
    
      Private _repository As New Infraestructure.Data.ImportModeRepository
    
      Public Function GetAll() As IEnumerable(Of ImportMode)
    
        Return _repository.GetAll()
    
      End Function
    
      Public Function GetImportMode(ByVal id As Integer) As ImportMode
    
        Return _repository.GetElementById(id)
    
      End Function
    
      Public Sub addImportMode(ByVal importMode As ImportMode)
    
        _repository.addImportMode(importMode)
    
      End Sub
    
    End Class

    Y este es el código desde el cliente. Para las pruebas lo estoy haciendo en una aplicación forms, desde un botón (mi intención es preparar test.. pero las cosas despacito y de una en una...).

    Dim a As New Domain.MainModule.ImportModeManager
    Dim b As New ImportMode
    b.ID = 7
    b.Name = "Test"
    a.addImportMode(b)

    La verdad es que con Entity Framework me estoy encontrando con alguna confusión entre las entidades que genera EF y las STE.

    Además, no me queda claro cuando aplicar los métodos ApplyChanges() (que no me aparece por ningun lado con el modelo STE) y SaveChanges().

    Creo que SaveChanges() confirma los cambios en los objetos del contexto (DataContext en mi caso) y además lanza las sentencias para realizar las modificaciones en base de datos... por lo que he leido, porque con las pruebas que estoy realizando, no veo nada de nada.

    Además, las pruebas las estoy haciendo con una entidad super sencilla (id y nombre). En el mismo modelo tengo otras con herencia que me está entrando risilla floja cada vez que las veo... porque también las intento grabar y nada de nada...

    En fins! seguiremos probando!

    Gracias!

    miércoles, 15 de diciembre de 2010 17:07

Respuestas

  • Lo encontré!!!

    El tema es el siguiente: la aplicación tiene tres ensamblados:

    • Capa de UI
    • Capa de negocio
    • Capa de acceso a datos (Donde uso EF).

    La cadena de conexión tiene la siguiente forma:

    Source=|DataDirectory|\Database\MssDt.sdf

    El tema es que cada proyecto tiene su App.Config con esa misma cadena de conexión. Entiendo que el problema está en cómo interpreta cada ensamblado la variable |DataDirectory|.

    En el momento en que he utilizado rutas absolutas en los ficheros App.Config, todo ha empezado a funcionar!!

    Así que bueno, ahora la pregunta se convierte en ¿cómo puedo compartir ese App.Config o su cadena de conexión entre ensamblados? o mejor dicho ¿cual es la mejor manera de hacerlo?

    Al menos, he recuperado la fe en el Entity Framework para SQL Server CE!

    Voy a ver ahora como puedo resolver el tema de compartir la connectionString...

    Hale!

    lunes, 20 de diciembre de 2010 11:22

Todas las respuestas

  • Hola Antonio,

    El método AcceptAllChanges no es necesario, debería de ser capaz de realizar las actualizaciones sin él y haciendo un ApplyChanges antes del SaveChanges. Revisa este enlace que tiene un ejemplo de lo que te comento http://geeks.ms/blogs/adiazmartin/archive/2010/01/18/self-tracking-en-entity-framework-4-0.aspx

    Tú metodo Add, debería de quedar tal cual, perdona por el c#

        public void Save(ImportesKm item)
        {
          if (item.ChangeTracker.State == ObjectState.Added)
            context.ImportesKms.AddObject(item);
          context.ImportesKms.ApplyChanges(item);
          int result = context.SaveChanges();
        }


    Alberto Diaz Martin twitter://@adiazcan | http://geeks.ms/blogs/adiazmartin

    miércoles, 15 de diciembre de 2010 20:09
  • Hola de nuevo.

    Desconozco si el método en C# y en VB es distinto, pero a mi me aparece

    context.ImportModes.ApplyCurrentValues(importMode)
    
    
    

    En vez de el método ApplyChanges que comentas. ¿existe tal diferencia? ¿por qué no me aparece el método ApplyChanges?

    Además, si ejecuto el código siguiente:

    If importMode.ChangeTracker.State = ObjectState.Added Then
       context.ImportModes.AddObject(importMode)
       context.ImportModes.ApplyCurrentValues(importMode)
       Dim result As Integer = context.SaveChanges()
    End If
    Me da una excepción porque ApplyCurrentValues sólo se puede utilizar cuando el estado del objeto no ha cambiado o es "modificado".

    Gracias!

     

     

    jueves, 16 de diciembre de 2010 17:34
  • Hola!

    Avanzar avanzar, pues no mucho.. pero cosillas si que estoy viendo.. jejeje..

    Que curioso... no graba en base de datos, pero si intento grabar el mismo objeto 2 veces, da error por infracción de PK al intentar el Update... o sea, que el objeto si está en el contexto, pero por alguna razón no lo graba en base de datos...

    Seguiremos con ello!

    jueves, 16 de diciembre de 2010 18:18
  • Hola Antonio,

    1. ¿no ves el método ApplyChanges()? igual tienes una versión distinta de STE, a ver si reviso si tengo la último y te digo algo.

    2. El if del método no es así, debería de ser como sigue:

    If importMode.ChangeTracker.State = ObjectState.Added Then
      context.ImportModes.AddObject(importMode)
    End If
    context.ImportModes.ApplyCurrentValues(importMode)
    Dim result As Integer = context.SaveChanges()
    
    
     
    Primero compruebas que el objeto es nuevo y SOLO lo insertas. De todas formas, cuanto compruebe la versión de STE que tengo te paso un ejemplo sencillo.

    Alberto Diaz Martin twitter://@adiazcan | http://geeks.ms/blogs/adiazmartin
    viernes, 17 de diciembre de 2010 8:43
  • Mil gracias Alberto!

    Ahora mismo voy a probarlo. De todas maneras... ¿no da igual que esas instrucciones estén dentro o fuera del If? ... se van a ejecutar igualmente..El tema también es que empiezo a plantearme si STE puede tener algún tipo de incompatibilidad con SQL Compact Ed.

    Voy a ver que encuentro al respecto, porque la verdad es que empiezo a plantearme utilizar las entidades "conectadas" (¿cual es el nombre técnico más correcto?). El tiempo empieza a apretarme!

    Un saludo, Antonio.

     

    viernes, 17 de diciembre de 2010 10:35
  • Hola de nuevo.

    Pues nada de nada, sigo igual que estaba... pero más mosqueado con el tema del SQL Server CE. Supuestamente es compatible... peeeroo, las siguientes líneas funcionan en un SQL Server Express, y NO en un SQL Server CE.

    Dim importMode As New Pruebas_EF_05.ImportMode
    importMode.ID = 7
    importMode.Name = "Test3"
    
    Using context As New Pruebas_EF_05.Entities
       context.ImportModes.AddObject(importMode)
       context.SaveChanges()
    End Using
    

    He eliminado las entidades STE, por minimizar un poco el escenario y pensando que quizá no fuesen compatibles con SQL Server CE.
    Pero ahora si que estoy perdido. Dedicaré el día de hoy a ver si puedo ver algo más... y sino, paso de momento de EF para este proyecto. El tiempo apremia!

    ¿Alguna idea?
    Gracias!

     

    lunes, 20 de diciembre de 2010 8:45
  • Lo encontré!!!

    El tema es el siguiente: la aplicación tiene tres ensamblados:

    • Capa de UI
    • Capa de negocio
    • Capa de acceso a datos (Donde uso EF).

    La cadena de conexión tiene la siguiente forma:

    Source=|DataDirectory|\Database\MssDt.sdf

    El tema es que cada proyecto tiene su App.Config con esa misma cadena de conexión. Entiendo que el problema está en cómo interpreta cada ensamblado la variable |DataDirectory|.

    En el momento en que he utilizado rutas absolutas en los ficheros App.Config, todo ha empezado a funcionar!!

    Así que bueno, ahora la pregunta se convierte en ¿cómo puedo compartir ese App.Config o su cadena de conexión entre ensamblados? o mejor dicho ¿cual es la mejor manera de hacerlo?

    Al menos, he recuperado la fe en el Entity Framework para SQL Server CE!

    Voy a ver ahora como puedo resolver el tema de compartir la connectionString...

    Hale!

    lunes, 20 de diciembre de 2010 11:22
  • Ya meestaba a empezando a preocupar. Mis desarrollos con EF han sido con SQL Server y no había tenido problemas y lo SQL CE me parecía raro.

    Lo de los App.Config es fácil. EF va a leer del App.Config del ensamblado que ejecuta tu aplicación que supongo que será Capa de UI. Con que tengas este actualizado listo.

     


    Alberto Diaz Martin twitter://@adiazcan | http://geeks.ms/blogs/adiazmartin
    lunes, 20 de diciembre de 2010 11:26
  • Hola Alberto,

    La verdad es que yo también me estaba mosqueando mucho. Pero bueno, al final parece que todo sigue en su sitio.

    Gracias por tu ayuda!

    Un saludo, Antonio.

    lunes, 20 de diciembre de 2010 11:57
  • nada, por aquí estamos para lo que necesites.
    Alberto Diaz Martin twitter://@adiazcan | http://geeks.ms/blogs/adiazmartin
    lunes, 20 de diciembre de 2010 13:13