Domanda

Ho iniziato a usare Linq to SQL in un sistema (simile a DDD bit) che sembra (eccessivamente semplificato) in questo modo:

public class SomeEntity // Imagine this is a fully mapped linq2sql class.
{
    public Guid SomeEntityId { get; set; }
    public AnotherEntity Relation { get; set; }
}

public class AnotherEntity // Imagine this is a fully mapped linq2sql class.
{
    public Guid AnotherEntityId { get; set; }
}

public interface IRepository<TId, TEntity>
{
    Entity Get(TId id);
}

public class SomeEntityRepository : IRepository<Guid, SomeEntity>
{
    public SomeEntity Get(Guid id)
    {
        SomeEntity someEntity = null;
        using (DataContext context = new DataContext())
        {
            someEntity = (
                from e in context.SomeEntity
                where e.SomeEntityId == id
                select e).SingleOrDefault<SomeEntity>();
        }

        return someEntity;
    }
}

Ora ho un problema. Quando provo ad usare SomeEntityRepository in questo modo

public static class Program
{
    public static void Main(string[] args)
    {
        IRepository<Guid, SomeEntity> someEntityRepository = new SomeEntityRepository();
        SomeEntity someEntity = someEntityRepository.Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));
        Console.WriteLine(someEntity.SomeEntityId);
        Console.WriteLine(someEntity.Relation.AnotherEntityId);
    }
 }

tutto funziona bene fino a quando il programma non arriva all'ultima WriteLine, perché genera un ObjectDisposedException , perché DataContext non esiste più.

Vedo il problema reale, ma come posso risolverlo? Immagino che ci siano diverse soluzioni, ma nessuna di quelle a cui ho pensato finora sarebbe buona nella mia situazione.

  • Allontanati dal modello di repository e utilizza un nuovo DataContext per ogni parte atomica del lavoro.
    • Non vorrei davvero farlo. Un motivo è che non voglio essere le applicazioni a conoscenza del repository. Un altro è che non credo che rendere visibile COM di linq2sql sarebbe positivo.
    • Inoltre, penso che fare context.SubmitChanges () probabilmente impegnerebbe molto più di quanto volessi.
  • Specifica di DataLoadOptions per recuperare gli elementi correlati.
    • Poiché desidero che il mio livello di logica aziendale risponda solo con alcune entità in alcuni casi, non so quali sotto-proprietà devono utilizzare.
  • Disabilitazione del caricamento lento / caricamento ritardato per tutte le proprietà.
    • Non è un'opzione, perché ci sono alcune tabelle e sono fortemente collegate. Ciò potrebbe causare un sacco di traffico non necessario e caricamento del database.
  • Alcuni post su Internet affermano che l'uso di .Single () dovrebbe aiutare.
    • Apparentemente non ...

C'è un modo per risolvere questa miseria?

A proposito: abbiamo deciso di usare Linq t0 SQL perché è una soluzione ORM relativamente leggera e inclusa con .NET framework e Visual Studio. Se .NET Entity Framework si adatterà meglio a questo modello, potrebbe essere un'opzione per passare ad esso. (Non siamo ancora così lontani nell'attuazione.)

È stato utile?

Soluzione

Rick Strahl ha un bell'articolo sulla gestione del ciclo di vita di DataContext qui: http: / /www.west-wind.com/weblog/posts/246222.aspx .

Fondamentalmente, l'approccio dell'azione atomica è buono in teoria, ma dovrai tenere il tuo DataContext in giro per poter tracciare le modifiche (e recuperare i bambini) nei tuoi oggetti dati.

Vedi anche: Istanza multipla / singola di Linq to SQL DataContext e LINQ to SQL - dove risiede il tuo DataContext? .

Altri suggerimenti

Devi:

1) Lascia il contesto aperto perché non hai ancora deciso completamente quali dati verranno ancora utilizzati (aka, Lazy Loading).

o 2) Estrarre più dati sul caricamento iniziale se si sa che sarà necessaria quell'altra proprietà.

Spiegazione di quest'ultimo: qui

Non sono sicuro che devi abbandonare Repository se vai con unità di lavoro atomiche. Uso entrambi, anche se ammetto di buttare fuori i controlli di concorrenza ottimisti poiché non funzionano comunque a strati (senza usare un timestamp o qualche altra convenzione richiesta). Quello che finisco con è un repository che utilizza un DataContext e lo getta via quando ha finito.

Questo fa parte di un esempio di Silverlight non correlato, ma le prime tre parti mostrano come sto usando un modello di repository con un contesto LINQ to SQL usa e getta, FWIW: http://www.dimebrain.com/2008/09/linq-wcf-silver.html

  

Specifica di DataLoadOptions per recuperare gli elementi correlati. Poiché desidero che il mio livello di logica aziendale risponda solo con alcune entità in alcuni casi, non so quali sotto-proprietà debbano utilizzare.

Se al chiamante viene concesso l'accoppiamento necessario per utilizzare la proprietà .Relation, il chiamante potrebbe anche specificare DataLoadOptions.

DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Entity>(e => e.Relation);
SomeEntity someEntity = someEntityRepository
  .Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"),
  loadOptions);

//

using (DataContext context = new DataContext())
{
  context.LoadOptions = loadOptions;

Questo è quello che faccio, e finora ha funzionato davvero bene.

1) Rendi DataContext una variabile membro nel tuo repository. Sì, questo significa che il tuo repository ora dovrebbe implementare IDisposable e non essere lasciato aperto ... forse qualcosa che vuoi evitare di dover fare, ma non ho trovato che sia scomodo.

2) Aggiungi alcuni metodi al tuo repository in questo modo:

public SomeEntityRepository WithSomethingElseTheCallerMightNeed()
{
 dlo.LoadWith<SomeEntity>(se => se.RelatedEntities);
 return this; //so you can do method chaining
}

Quindi, il tuo chiamante assomiglia a questo:

SomeEntity someEntity = someEntityRepository.WithSomethingElseTheCallerMightNeed().Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));

Devi solo assicurarti che quando il tuo repository colpisce il db, utilizza le opzioni di caricamento dei dati specificate in quei metodi di supporto ... nel mio caso " dlo " viene mantenuto come una variabile membro e quindi impostato subito prima di colpire il db.

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