.net - tabla - Configuración de claves externas en Linq a SQL
foreign key mysql ejemplo (3)
Es bien sabido que no puede establecer ID de clave externa directamente en Linq a SQL si las entidades ya se han cargado. Sin embargo, puede buscar la entidad por su clave externa y luego establecer la entidad como la entidad extranjera que usa la relación de entidad. (He sacado la enumeración aquí y usé valores enteros para simplificar). es decir, si tengo una entidad de Nombramiento cargada y una Entidad de Estado de Aprobación asociada, no puedo hacer esto: -
ExistingAppointment.AppointmentStatusID = 7
Pero puedo hacer esto:
ExistingAppointment.AppointmentStatus = (From appstat In db.AppointmentStatus _
Where appstat.StatusID = 7 _
Select appstat).Single
Tengo este tipo de cosas ensuciar mi código y me gustaría refactorizar. Asi que...
Obviamente podría usar un método auxiliar en un módulo como este:
Module Helper
Public Shared Function GetAppointmentStatus(ByVal AppStatusID As Integer) As AppointmentStatus
GetAppointmentStatus = (From appstat In db.AppointmentStatus _
Where appstat.AppointmentStatusID = AppStatus _
Select appstat).Single
End Function
End Module
Incluso podría convertir esto en un método de extensión, como este.
Imports System.Runtime.CompilerServices
Module Helper
Extension()> _
Public Shared Function GetAppointmentStatus(ByVal db as DataClassesDataContext, ByVal AppStatusID As Integer) As AppointmentStatus
GetAppointmentStatus = (From appstat In db.AppointmentStatus _
Where appstat.AppointmentStatusID = AppStatusID _
Select appstat).Single
End Function
End Module
También podría poner esto en la clase parcial de Linq a SQL, así.
Partial Public Class DataClassesDataContext
Public Function GetAppointmentStatus(ByVal AppStatusID As Integer) As AppointmentStatus
GetAppointmentStatus = (From appstat In Me.AppointmentStatus _
Where appstat.AppointmentStatusID = AppStatusID _
Select appstat).Single
End Function
End Class
Además, podría poner el código en la clase parcial Entidad de cita de Linq a SQL como esta:
Partial Public Class Appointment
Public Function GetAppointmentStatus(ByVal db as DataClassesDataContext, ByVal AppStatusID As Integer) As AppointmentStatus
GetAppointmentStatus = (From appstat In db.AppointmentStatus _
Where appstat.AppointmentStatusID = AppStatusID _
Select appstat).Single
End Function
End Class
¿Qué debería hacer y por qué, o hay una mejor alternativa?
Normalmente el setter de AppointmentStatusId se ve así: (Código en C # pero debería ser fácil de obtener)
[Column(Storage="_AppointmentStatusId", DbType="Int")]
public System.Nullable<int> AppointmentStatusId
{
get
{
return this._AppointmentStatusId;
}
set
{
if ((this._AppointmentStatusId != value))
{
if (this._AppointmentStatus.HasLoadedOrAssignedValue)
{
throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
}
this.OnCapabilityIdChanging(value);
this.SendPropertyChanging();
this._AppointmentStatusId = value;
this.SendPropertyChanged("AppointmentStatusId");
this.OnCapabilityIdChanged();
}
}
}
Entonces, si yo fuera usted, agregaría un método SetAppointmentStatusId (int statusId) al archivo parcial que viene con el generado por el diseñador, y agregaré más cuando sea necesario para otras propiedades. Incluso puede optar por que el establecimiento de la propiedad sea privado (del diseñador seleccione la propiedad y presione F4 para la ventana de propiedades VS para cambiar la accesibilidad).
En este método escribiría un código idéntico al del colocador, excepto que NO incluye esta parte:
if (this._AppointmentStatus.HasLoadedOrAssignedValue)
{
throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
}
Hay dos escuelas principales de pensamiento sobre esto:
Coloque la lógica en el
DataContext
(clase parcial o clase real si codifica suDataContext
a mano). La razón detrás de esto es que suDataContext
ya conoce todas sus diferentes entidades, por lo que no está creando ningún acoplamiento adicional y no está conduciendo a la saturación de clases.La desventaja, por supuesto, es que si tienes unos pocos cientos de estos métodos API (y probablemente lo harás), entonces tu
DataContext
comenzará a convertirse rápidamente en una bola de lodo, rellenada con cada API de consulta aleatoria que cualquier programador decida lanzar pulg. Puede intentar limpiar esto separando funciones relacionadas en diferentes instancias de la misma clase parcial deDataContext
, pero eso es realmente solo una mejora cosmética.Coloque la lógica en una clase de repositorio, es decir, un
AppointmentRepository
. Dos ventajas de este enfoque son (a) la posibilidad de utilizar la inyección de dependencia en el repositorio y un marco de IoC, en caso de que decida cambiar su modelo de datos, y (b) el hecho de que se apega al Principio de Responsabilidad Individual - de hecho, tiene sentido que el método esté donde está.Las principales desventajas de poner estos en repositorios son: (a) Pueden estar duplicando una lógica muy similar que ya está en su
DataContext
como Procedimientos almacenados; (b) tienen una forma de crear dolores de cabeza cuando se trata de la gestión de transacciones (si también las usa para guardar); y (c) cuando comienza a tener muchas consultas personalizadas que devuelven DTO especialmente diseñados para operaciones o informes específicos, le quedan las dos opciones desagradables de crear un repositorio para cada DTO o crear un maestro repositorio de "utilidad" para todos los DTO o algún grupo de ellos relacionado de forma vaga. Ambos terminan siendo un diseño bastante pobre.
Esas son las compensaciones; solo tú puedes decidir cuál es mejor para tus propios fines.
Definitivamente desaconsejaría el método de extensión de método, ya que los métodos de extensión son difíciles de descubrir (no se puede simplemente escribir el método y que Intellisense elija la referencia relevante), y tampoco son necesarios cuando se tiene la capacidad. para modificar o extender directamente (a través de parciales) la clase original.
También desaconsejaría extender la clase de Appointment
; Una de las razones por las que utilizamos herramientas como Linq To SQL es que podemos tratar con entidades de POCO que no necesitan saber nada sobre su origen. Por esta razón, personalmente estoy en contra del acoplamiento de las clases de entidad a su DataContext
, la dependencia debe ser solo de una sola dirección.
Normalmente coloco estos métodos en la clase parcial para el DataContext, en la teoría de que estos métodos son similares a los procedimientos almacenados en cierto sentido, y los procedimientos almacenados se manifiestan como métodos en el DataContext.
Cualquiera que sea la forma en que decida continuar, definitivamente vale la pena refactorizar para que tenga esta consulta en un solo lugar y no se repita. Esto también le deja la opción de reemplazar el método simple que describió por uno más sofisticado que almacena en caché una versión compilada de la consulta y la reutiliza, sin tener que actualizar todas las personas que llaman del método.