Pregunta

Si tengo los objetos LINQ:

public class SampleDataContext : DataContext {
    public Table<Customer> Customers { get { return this.GetTable<Customer>(); } }
    public SampleDataContext( string connectionString ) : base( connectionString ) { }
}

[Table( Name="dbo.tblCustomers" )]
public class Customer {
    private Guid? customerID;
    [Column( Storage="customerID", DbType="uniqueidentifier NOT NULL", IsPrimaryKey=true )]
    public Guid? CustomerID {
        get { return this.customerID; }
        set { this.customerID = value; }
    }

    private string customerName;
    [Column( Storage = "customerName", DbType = "nvarchar(255) NOT NULL" )]
    public string CustomerName {
        get { return this.customerName; }
        set { this.customerName = value; }
    }
}

y en otro lugar de la aplicación:

public static void DoSomethingWithCustomer( Customer customer ) {
    // some operations
    // now, I want save changes to the database
}

¿cómo puedo obtener una instancia de DataContext que rastrea los cambios del " cliente " objeto?

Editar: por qué no quiero pasar el DataContext al método.

1) Pasar siempre 2 objetos en lugar de 1 es `` feo '' patrón para toda la aplicación.

  • Los métodos necesitarán el siguiente parámetro para cada objeto comercial.
  • La colección deberá cambiarse de " Lista " a " Lista > " ;.

Ambos puntos serán más difíciles de mantener: el desarrollador debe establecer siempre la instancia correcta de DataContext (fácil de crear un error), a pesar de que DataContext sabe que el objeto concreto está (o no) adjunto a otro DataContext.

2) Quiero que (la versión actual de la aplicación lo use) procesar " any " lógica de negocios en la colección de objetos que provienen de diferentes "lugares" (ventanas flotantes arrastrando y soltando, por ejemplo).

Currentyl utilizamos conjuntos de datos personalizados, por lo que la información sobre los cambios se encuentra en las filas de datos (DataRow = objeto comercial) y no fue un problema obtenerlo, o crear un clon y luego guardarlo en la base de datos.

¿Fue útil?

Solución

Kevin - Siento tu dolor ... cuando estás construyendo lógica empresarial alrededor de tus objetos comerciales, hay veces en que simplemente tienes para tener acceso al DataContext al que pertenece un objeto, ya que sin conocer el menú de DataContext que tiene que poner su código en lugares que reducen la facilidad de mantenimiento de su código.

Escribí el siguiente código (VB, me temo), que presenta una propiedad de contexto que se puede colocar en un objeto de datos, y luego se usa para devolver el DataContext (si lo hay) al que está conectado el objeto.

Private Const StandardChangeTrackerName As String = "System.Data.Linq.ChangeTracker+StandardChangeTracker"

Private _context As DataClasses1DataContext
Public Property Context() As DataClasses1DataContext
    Get
        Dim hasContext As Boolean = False
        Dim myType As Type = Me.GetType()
        Dim propertyChangingField As FieldInfo = myType.GetField("PropertyChangingEvent", BindingFlags.NonPublic Or BindingFlags.Instance)
        Dim propertyChangingDelegate As PropertyChangingEventHandler = propertyChangingField.GetValue(Me)
        Dim delegateType As Type = Nothing

        For Each thisDelegate In propertyChangingDelegate.GetInvocationList()
            delegateType = thisDelegate.Target.GetType()
            If delegateType.FullName.Equals(StandardChangeTrackerName) Then
                propertyChangingDelegate = thisDelegate
                hasContext = True
                Exit For
            End If
        Next

        If hasContext Then
            Dim targetField = propertyChangingDelegate.Target
            Dim servicesField As FieldInfo = targetField.GetType().GetField("services", BindingFlags.NonPublic Or BindingFlags.Instance)
            If servicesField IsNot Nothing Then

                Dim servicesObject = servicesField.GetValue(targetField)

                Dim contextField As FieldInfo = servicesObject.GetType.GetField("context", BindingFlags.NonPublic Or BindingFlags.Instance)

                _context = contextField.GetValue(servicesObject)

            End If
        End If

        Return _context
    End Get
    Set(ByVal value As DataClasses1DataContext)

        _context = value

    End Set

End Property

Aquí hay una versión de C #:

public DataContext GetMyDataContext()
{
    // Find the StandardChangeTracker listening to property changes on this object.
    // If no StandardChangeTracker is listening, then this object is probably not
    // attached to a data context.
    var eventField = this.GetType().GetField("PropertyChangingEvent", BindingFlags.NonPublic | BindingFlags.Instance);
    var eventDelegate = eventField.GetValue(this) as Delegate;
    if (eventDelegate == null)
        return null;
    eventDelegate = eventDelegate.GetInvocationList().FirstOrDefault(
        del => del.Target.GetType().FullName == "System.Data.Linq.ChangeTracker+StandardChangeTracker");
    if (eventDelegate == null)
        return null;

    // Dig through the objects to get the underlying DataContext.
    // If the following fails, then there was most likely an internal change
    // to the LINQ-to-SQL framework classes.
    var targetField = eventDelegate.Target;
    var servicesField = targetField.GetType().GetField("services", BindingFlags.NonPublic | BindingFlags.Instance);
    var servicesObject = servicesField.GetValue(targetField);
    var contextField = servicesObject.GetType().GetField("context", BindingFlags.NonPublic | BindingFlags.Instance);
    return (DataContext)contextField.GetValue(servicesObject);
}

Tenga en cuenta que el objeto solo puede ubicar su DataContext si actualmente está adjunto al contexto con ChangeTracking activado. Esta propiedad se basa en el hecho de que DataContext se ha suscrito al evento OnPropertyChanging del objeto para supervisar los cambios durante la vida útil del objeto.

Si esto fue útil, vote por favor esta publicación.

Para obtener más información sobre el uso de la reflexión para buscar controladores de eventos: http: //weblogs.asp. net / avnerk / archive / 2007/03/29 / reflecting-over-an-event.aspx http://www.bobpowell.net/eventsubscribers.htm

Otros consejos

Parte de la diversión de POCO es que no puedes estar seguro de que el objeto sabe quién lo está rastreando. Si el objeto tiene propiedades de datos / carga diferida, entonces podría ser capaz de rastrear el contexto a través de la reflexión, pero en realidad esto sería un desastre. Sería mucho más sencillo simplemente pasar el contexto de datos al código que lo necesita.

Lo más simple es pasar el DataContext a su método.

Sin embargo, también puede considerar cambiar su diseño para seguir la regla de que "un solo método debe tener un solo propósito", en cuyo caso no querría "Guardar" en el mismo método que " Modificar " ;.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top