Domanda

Se ho gli oggetti 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; }
    }
}

e da qualche altra parte nell'applicazione:

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

come posso ottenere un'istanza di DataContext che tiene traccia delle modifiche del "cliente" obiettare?

Modifica: perché non voglio passare DataContext nel metodo.

1) Passare sempre 2 oggetti invece di 1 è "brutto" modello per l'intera applicazione.

  • I metodi avranno bisogno del prossimo parametro per ogni oggetto business.
  • La raccolta dovrà essere modificata da " Elenco " a " Elenca > " ;.

Entrambi i punti saranno più difficili da mantenere - lo sviluppatore deve sempre impostare l'istanza corretta di DataContext (facile da creare un bug), nonostante DataContext sappia che l'oggetto concreto è (o meno) collegato a un altro DataContext.

2) Voglio che (l'attuale versione dell'applicazione lo usi) elabori " qualsiasi " logica aziendale sulla raccolta di oggetti provenienti da diversi "luoghi" (finestre mobili trascinando & amp; rilascia ad esempio).

Currentyl usiamo DataSet personalizzati, quindi le informazioni sulle modifiche si trovano nelle righe di dati (DataRow = oggetto business) e non è stato un problema ottenerlo o creare un clone e quindi salvarlo nel database.

È stato utile?

Soluzione

Kevin - Sento il tuo dolore ... quando stai costruendo la logica di business attorno ai tuoi oggetti di business, ci sono momenti in cui hai solo per avere accesso al DataContext a cui appartiene un oggetto, dal momento che non conoscere i menu di DataContext che devono inserire il codice in luoghi che riducono la manutenibilità del codice.

Ho scritto il seguente codice (VB, temo), che presenta una proprietà Context che può essere posizionata su un oggetto dati, e quindi usato per restituire il DataContext (se presente) a cui è collegato l'oggetto.

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

Ecco una versione 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);
}

Prestare attenzione a notare che l'oggetto può individuare DataContext solo se è attualmente collegato al contesto con ChangeTracking attivato. Questa proprietà si basa sul fatto che DataContext ha sottoscritto l'evento OnPropertyChanging dell'oggetto per monitorare le modifiche durante la durata dell'oggetto.

Se questo è stato utile, per favore vota questo post.

Per ulteriori informazioni sull'uso di reflection per trovare i gestori di eventi: http: //weblogs.asp. net / avnerk / archive / 2007/03/29 / riflettendo-over-an-event.aspx http://www.bobpowell.net/eventsubscribers.htm

Altri suggerimenti

Parte del divertimento di POCO è che non puoi essere sicuro che l'oggetto conosce chi lo sta seguendo. Se l'oggetto ha proprietà sensibili ai dati / caricamento lento, allora potresti essere in grado di tracciare il contesto tramite la riflessione, ma in realtà questo sarebbe un casino. Sarebbe molto più semplice trasferire semplicemente il contesto dei dati al codice che ne ha bisogno.

La cosa più semplice da fare è passare DataContext nel tuo metodo.

Tuttavia, puoi anche considerare di cambiare il tuo design in modo da seguire la regola che "un singolo metodo dovrebbe avere un solo scopo", nel qual caso non vorrai "salvare" nello stesso metodo in cui " Modifica " ;.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top