Question

Si j'ai les objets 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; }
    }
}

et ailleurs dans l'application:

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

Comment puis-je obtenir une instance de DataContext qui enregistre les modifications du "client"? objet?

Edition: Pourquoi je ne souhaite pas transmettre le DataContext à la méthode.

1) Passer toujours 2 objets au lieu de 1 est "laid" motif pour toute l'application.

  • Les méthodes auront besoin du paramètre suivant pour chaque objet métier.
  • La collection a besoin d'être modifiée depuis "Liste". pour "Lister >".

Les deux points seront plus difficiles à maintenir - le développeur doit définir à chaque fois l'instance correcte de DataContext (facile de créer un bogue), bien que DataContext sache que l'objet concret est (ou non) associé à un autre DataContext.

2) Je souhaite (la version actuelle de l’application l’utiliser) traiter "tout". la logique métier sur la collection d'objets provenant de différents "lieux" (fenêtres flottantes par glisser-déposer par exemple).

Currentyl utilise des ensembles de données personnalisés, de sorte que les informations relatives aux modifications figurent dans les lignes de données (DataRow = objet métier) et ne posent aucun problème pour les obtenir ou pour créer un clone, puis l'enregistrer dans la base de données.

Était-ce utile?

La solution

Kevin - Je ressens votre douleur… Lorsque vous construisez une logique métier autour de vos objets métier, il arrive parfois que vous ayez accès au DataContext auquel un objet appartient, car ne sachant pas que DataContext est contraint de placer votre code dans des emplacements réduisant sa maintenabilité.

J'ai écrit le code suivant (VB, je le crains), qui présente une propriété Context qui peut être placée sur un objet de données, puis utilisé pour renvoyer le DataContext (le cas échéant) auquel l'objet est attaché.

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

Voici une version 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);
}

Notez que l'objet ne peut localiser son DataContext que s'il est actuellement lié au contexte avec ChangeTracking activé. Cette propriété repose sur le fait que le DataContext s'est abonné à l'événement OnPropertyChanging de l'objet pour surveiller les modifications sur la durée de vie de l'objet.

Si cela vous a été utile, votez pour cet article, s'il vous plaît.

Pour plus d'informations sur l'utilisation de la réflexion pour rechercher des gestionnaires d'événements: http: //weblogs.asp. net / avnerk / archive / 2007/03/29 / reflectant sur un événement.aspx http://www.bobpowell.net/eventsubscribers.htm

Autres conseils

Une partie du plaisir de POCO est que vous ne pouvez pas être sûr que l'objet sait qui le suit. Si l'objet possède des propriétés de données / de chargement paresseux, vous pourrez pouvoir tracer le contexte par réflexion, mais en réalité ce serait un désordre. Il serait beaucoup plus simple de simplement passer le contexte de données au code qui en a besoin.

Le plus simple est de passer le DataContext à votre méthode.

Cependant, vous pouvez également envisager de modifier votre conception afin de respecter la règle selon laquelle "une seule méthode ne doit avoir qu'un seul objectif", auquel cas vous ne souhaitez pas "Enregistrer". de la même manière que vous "modifiez".

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top