2009-02-14 7 views
15

¿Cuál es la mejor práctica en términos de configuración de mi DataContext para facilitar el acceso en mis clases LinqToSql extendidas?¿LinqToSql declara y crea una instancia de las mejores prácticas de DataContext?

Por ejemplo, tengo una entidad "Usuario" en mi dbml y quiero añadir métodos a esa clase de esta manera:

Partial Public Class User 

    Public Function GetUser(ByVal UserID as Integer) as User 
     'Do Work 
    End Function 

End Class 

Con el fin de acceder a mi DataContext que tendría que declarar en el interior el método como lo siguiente:

Partial Public Class User 

    Public Function GetUser(ByVal UserID as Integer) as User 
     Dim dc as New MyDataContext() 
     Return (From u in dc.Users Where u.ID = UserID).Single() 
    End Function 

End Class 

Me gustaría no tener que hacer eso para cada método. Normalmente (si no estuviera extendiendo las clases DBML LinqToSql) tan sólo pudiera hacer esto:

Partial Public Class User 
    Private dc as MyDataContext 

    Public Sub New() 
     dc = new MyDataContext() 
    End Sub 

    Public Function GetUser(ByVal UserID as Integer) as User 
     Return (From u in dc.Users Where u.ID = UserID).Single() 
    End Function 

    Public Function GetAllUsers() as IEnumerable(Of User) 
     Return From u in dc.Users 
    End Function 

    'etc... 

End Class 

Esto permitiría que tenga acceso a la DataContext para cada método sin tener que declarar de nuevo cada vez. Pero, por supuesto, no puedes hacer eso porque el dbml ya tiene un constructor. Y agregar código en el dbml siempre se sobrescribe si alguna vez cambia algo.

¿Alguien tiene alguna buena idea sobre cómo ahorrarme un código de exceso aquí?

TIA!

Respuesta

13

¡Primero, asegúrese de que está eliminando su DataContext cuando haya terminado! Puede ser un bastardo pesado (edit no pesado para crear instancias, pero pesado para mantener si sigues usándolo sin eliminarlo); no quieres viejos DataContexts en la memoria.

En segundo lugar, el DataContext está destinado a representar una sola transacción lógica. P.ej. debe crear uno nuevo cada vez que desee iniciar una nueva transacción y deshacerse de él cuando se complete esa transacción. Entonces, para sus propósitos, es probablemente el alcance del método GetUser. Si tiene una serie de llamadas a DB que deben realizarse como un grupo, todas deben usar el mismo DC antes de deshacerse de él.

+1

El contexto de datos en sí es bastante ligero, aunque podría referirse a muchas entidades. Eliminarlo para liberar a las entidades es una muy buena idea. Si fuera un objeto pesado, estaría más inclinado a mantenerlo así no tendría que recrearlo. – tvanfosson

+0

@tvanfosson eso es lo que quise decir; editado para aclarar ese punto. El DC puede llevar mucho peso con él; es mejor deshacerse de él lo más rápido posible. –

+0

Argumentos contra la eliminación: http://stephenwalther.com/blog/archive/2008/08/20/asp-net-mvc-tip-34-dispose-of-your-datacontext-or-don-t.aspx –

0

Creo que quizás el verdadero problema es que User probablemente no sea el lugar correcto para una llamada de miembro de instancia GetUser.

+0

¿Qué quiere decir con eso? ¿Puedes explicar más? – EdenMachine

11

Como Rex M said, el contexto de datos está destinado a ser instanciado, utilizado y dispuesto para cada transacción lógica. Patrones como este a veces se llaman una "unidad de trabajo".

La forma más común (que yo sepa) de hacer esto es crear una instancia de su contexto de datos en un bloque en uso. No he utilizado VB desde hace tiempo, pero debería ser algo como esto:

Using dc As New MyDataContext() 
    user = (From u in dc.Users Where u.ID = UserID).Single() 
End Using 

Esto no sólo refuerza la mirada de una transacción/unidad de trabajo (a través de la forma física del código), pero garantiza la invocación de Dispose() en su contexto de datos cuando termina el bloque.

Ver this MSDN page:

En general, una instancia de DataContext está diseñado para una duración de una "unidad de trabajo", sin embargo su aplicación define ese término.Un DataContext es liviano y no es costoso para crear. Una aplicación LINQ to SQL típica crea instancias de DataContext en el ámbito del método o como un miembro de clases efímeras que representan un conjunto lógico de operaciones de bases de datos relacionadas .

0

Hay un par de formas diferentes en que podría hacer esto, creo que sería una buena práctica. Primero, podría usar un patrón Repositorio en el que consulte el Repositorio para un objeto, vaya a la base de datos, recupere el objeto, tal vez separándolo del contexto de datos o manteniendo el contexto de datos dependiendo de la implementación del Depósito. y te lo devuelve. Los métodos de fábrica para sus objetos estarían en el Repositorio, no en las entidades mismas. Probablemente usaría reflexiones y genéricos para minimizar el número de métodos que tiene que implementar y mantener su código SECO.

Por otro lado, y la forma en que se pretendía utilizar LINQtoSQL de forma nativa en mi humilde opinión, es crear el contexto de datos para cada conjunto de operaciones de base de datos que pretenda realizar. En esto, la creación del contexto de datos ocurre también fuera de la entidad, generalmente en la clase que está utilizando las entidades, no en la capa de datos en absoluto. También podría agregar métodos al contexto de datos: haga que su contexto de datos real sea abstracto y herede de él, usando la reflexión nuevamente, para realizar algunas de las funciones de recuperación comunes para que no tenga que repetirlas. Probablemente tengas que usar un patrón de base de datos como ActiveRecords donde las columnas de id siempre tienen el mismo nombre para que esto funcione.

Por otro lado, puede ver usando nHibernate o Castle's ActiveRecord en lugar de replicar cualquiera de los anteriores en su propia solución.

0

Puede ser más fácil si deja la clase de usuario solo y permite que el IDE maneje su creación.

A menudo prefiero tener una clase separada para manejar la recuperación de datos. Digamos que lo llamas el UserDataProvider y todas las llamadas para obtener una instancia de Usuario finalmente pasan por esta clase.

El constructor de UserDataProvider podría instanciar una instancia global del objeto de contexto de datos para su reutilización. Se vería algo como esto (en C# y el código no probado tan desnudo conmigo):

public class UserDataProvider 
{ 
    private UserDataContext _data = null; 

    public UserDataProvider() 
    { 
     _data = new UserDataContext(); 
    } 

    public User GetUser(int userID) 
    { 
     return _data.Users.FirstOrDefault(u => u.UserID == userID); 
    } 
} 

Alternativamente, es posible colocar la inicialización de una propiedad y el acceso que la propiedad para el uso contexto de datos.

public class UserDataProvider 
{ 
    private UserDataContext _dataContext; 

    private UserDataContext DataContext 
    { 
     get 
     { 
      if (_data == null) 
       _data = new UserDataContext(); 

      return _data; 
     } 
    } 

    public User GetUser(int userID) 
    { 
     return DataContext.Users.FirstOrDefault(u => u.UserID == userID); 
    } 
}