Pregunta

He comenzado a usar Linq to SQL en un sistema (similar a DDD) que se ve (demasiado simplificado) así:

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

Ahora, tengo un problema. Cuando trato de 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);
    }
 }

todo funciona bien hasta que el programa llega a la última línea de escritura, porque arroja una ObjectDisposedException , porque el DataContext ya no existe.

Veo el problema real, pero ¿cómo resuelvo esto? Supongo que hay varias soluciones, pero ninguna de las que he pensado hasta la fecha sería buena en mi situación.

  • Aléjese del patrón de repositorio y utilice un nuevo DataContext para cada parte atómica del trabajo.
    • Realmente no me gustaría hacer esto. Una razón es que no quiero que las aplicaciones sean conscientes del repositorio. Otra es que no creo que sea bueno hacer que linq2sql cosas COM sean visibles.
    • Además, creo que hacer context.SubmitChanges () probablemente comprometería mucho más de lo que pretendía.
  • Especificación de DataLoadOptions para recuperar elementos relacionados.
    • Como quiero que mi Business Logic Layer solo responda con algunas entidades en algunos casos, no sé qué subpropiedades necesitan usar.
  • Deshabilitar la carga diferida / carga diferida para todas las propiedades.
    • No es una opción, porque hay bastantes tablas y están muy vinculadas. Esto podría causar mucho tráfico innecesario y carga de base de datos.
  • Algunas publicaciones en Internet dicen que usar .Single () debería ayudar.
    • Aparentemente no ...

¿Hay alguna forma de resolver esta miseria?

Por cierto: decidimos usar Linq t0 SQL porque es una solución ORM relativamente liviana e incluida con .NET Framework y Visual Studio. Si .NET Entity Framework encajaría mejor en este patrón, puede ser una opción cambiar a él. (Todavía no estamos tan lejos en la implementación).

¿Fue útil?

Solución

Rick Strahl tiene un buen artículo sobre la gestión del ciclo de vida de DataContext aquí: http: / /www.west-wind.com/weblog/posts/246222.aspx .

Básicamente, el enfoque de acción atómica es bueno en teoría, pero necesitará mantener su DataContext para poder realizar un seguimiento de los cambios (y buscar hijos) en sus objetos de datos.

Consulte también: Instancia múltiple / única de Linq a SQL DataContext y LINQ to SQL: ¿dónde vive su DataContext? .

Otros consejos

Tienes que:

1) Deje el contexto abierto porque aún no ha decidido completamente qué datos se utilizarán todavía (también conocido como Carga diferida).

o 2) Obtenga más datos sobre la carga inicial si sabe que necesitará esa otra propiedad.

Explicación de lo último: aquí

No estoy seguro de que tengas que abandonar el repositorio si vas con unidades atómicas de trabajo. Utilizo ambos, aunque admito que descarto las comprobaciones de simultaneidad optimistas ya que de todos modos no funcionan en capas (sin usar una marca de tiempo o alguna otra convención requerida). Lo que termino con es un repositorio que usa un DataContext y lo tira cuando está hecho.

Esto es parte de un ejemplo de Silverlight no relacionado, pero las primeras tres partes muestran cómo estoy usando un patrón de Repositorio con un contexto desechable LINQ to SQL, FWIW: http://www.dimebrain.com/2008/09/linq-wcf-silver.html

  

Especificación de DataLoadOptions para recuperar elementos relacionados. Como quiero que mi Business Logic Layer solo responda con algunas entidades en algunos casos, no sé qué subpropiedades necesitan usar.

Si a la persona que llama se le concede el acoplamiento necesario para usar la propiedad .Relation, entonces la persona que llama también podría especificar 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;

Esto es lo que hago, y hasta ahora ha funcionado muy bien.

1) Convierta el DataContext en una variable miembro en su repositorio. Sí, esto significa que su repositorio ahora debe implementar IDisposable y no dejarse abierto ... tal vez algo que desee evitar tener que hacer, pero no he encontrado que sea un inconveniente.

2) Agregue algunos métodos a su repositorio como este:

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

Entonces, la persona que llama se ve así:

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

Solo necesita asegurarse de que cuando su repositorio llegue a la base de datos, utilice las opciones de carga de datos especificadas en esos métodos auxiliares ... en mi caso " dlo " se mantiene como una variable miembro y luego se establece justo antes de presionar la base de datos.

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