Pergunta

Eu comecei usando o Linq para SQL em um sistema (bit DDD like) que parece (excessivamente simplificado) como este:

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;
    }
}

Agora, eu tenho um problema. Quando tento usar SomeEntityRepository como este

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);
    }
 }

tudo funciona bem até que o programa chega ao último WriteLine, porque ele lança uma ObjectDisposedException, porque o DataContext não existe mais.

Eu vejo o problema real, mas como faço para resolver isso? Eu acho que existem várias soluções, mas nenhum daqueles que eu ter pensado até agora seria bom na minha situação.

  • Afaste-se o padrão de repositório e usando um novo DataContext para cada parte atômica de trabalho.
    • Eu realmente não gostaria de fazer isso. A razão é que eu não quero ser as aplicações que estar ciente do repositório. Outra é que eu não acho que fazendo coisas linq2sql COM visível seria bom.
    • Além disso, acho que fazendo context.SubmitChanges() provavelmente cometer muito mais do que eu pretendia.
  • Especificar DataLoadOptions para buscar elementos relacionados.
    • Como eu quero que a minha camada de lógica de negócios para apenas responder com algumas entidades, em alguns casos, eu não sei qual sub-propriedades que precisam para uso.
  • Desativar carregamento lento / atrasou o carregamento para todas as propriedades.
    • Não é uma opção, porque há a algumas mesas e eles estão fortemente ligados. Isso pode causar um monte de tráfego e base de dados carga desnecessária.
  • Alguns pós na internet, disse que o uso de .Single () deve ajudar.
    • Aparentemente, não ...

Existe alguma maneira de resolver esta miséria?

BTW: Decidimos usar Linq t0 SQL porque é uma solução ORM relativamente leve e incluído com o framework .NET e Visual Studio. Se o .NET Entity Framework se encaixaria melhor nesse padrão, pode ser uma opção para alternar a ele. (Nós não estamos tão longe na implementação, ainda.)

Foi útil?

Solução

Rick Strahl tem um artigo agradável sobre gerenciamento de ciclo de vida DataContext aqui: http: / /www.west-wind.com/weblog/posts/246222.aspx .

Basicamente, a abordagem ação atômica é bom na teoria, mas você vai precisar para manter o seu DataContext ao redor para ser capaz de acompanhar as mudanças (e buscar as crianças) em seus objetos de dados.

Veja também: instância / única de Linq para SQL DataContext LINQ to SQL? - onde o seu DataContext viver .

Outras dicas

Você tem que quer:

1) Deixe o aberto contexto, porque você ainda não decidiu completamente o que os dados serão ainda utilizados (aka, Lazy Loading).

ou 2) Puxe mais dados sobre a carga inicial se você sabe que vai precisar que outra propriedade.

Explaination deste último: aqui

Eu não tenho certeza que você tem que abandonar Repository se você ir com unidades atômicas de trabalho. Eu uso os dois, embora eu admita que jogar fora as verificações de simultaneidade otimista, uma vez que não funcionam em camadas de qualquer maneira (sem usar um timestamp ou alguma outra convenção necessário). O que eu acabar com é um repositório que usa um DataContext e joga fora quando ele é feito.

Esta é parte de um exemplo Silverlight independentes, mas as três primeiras partes mostrar como eu estou usando um padrão de repositório com um LINQ descartável ao contexto SQL, FWIW: http://www.dimebrain.com/2008/09/linq-wcf-silver.html

Especificando DataLoadOptions para buscar elementos relacionados. Como eu quero que a minha camada de lógica de negócios para apenas responder com algumas entidades, em alguns casos, eu não sei qual sub-propriedades que precisam para uso.

Se o chamador é concedido o acoplamento necessário usar a propriedade .Relation, em seguida, o chamador pode também especificar os 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;

Isto é o que eu faço, e até agora tem funcionado muito bem.

1) Faça o DataContext uma variável de membro em seu repositório. Sim, isso significa que você está repositório agora deve implementar IDisposable e não ser deixada em aberto ... talvez algo que você quer evitar ter que fazer, mas eu não tê-lo encontrado para ser inconveniente.

2) Adicionar alguns métodos para seu repositório como este:

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

Em seguida, a sua aparência de chamada como esta:

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

Você só precisa ter certeza de que quando seus sucessos repositório do db, ele usa as opções de carregamento de dados especificados nesses métodos auxiliares ... no meu caso "dlo" é mantido como uma variável de membro, e em seguida, defina a direita antes de bater db.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top