Este artículo proviene de un motor de traducción automática.

Patrones en la práctica

La unidad de modelo de trabajo Y persistencia Ignorance

Jeremy Miller

Contenido

La unidad de modelo de trabajo
Con la unidad de trabajo
Persistencia Ignorance
¿Puede ejecutar la lógica empresarial independientemente de la base de datos?
¿Puede diseñar el modelo de dominio independientemente del modelo de base de datos?
¿Cómo es la estrategia de persistencia afectan A la lógica empresarial?
Más unidades de trabajo

En el de 2009 abril emitir de MSDN Magazine (" Modelos de persistencia") Presentan algunos patrones comunes que se producirse al usar algún tipo de tecnología de asignación de objeto/relacional (o/administrador de recursos) para conservar los objetos de entidad de negocio. CREO que es improbable que usted o su grupo va a escribir su propio O o administrador de recursos tooling desde el principio, pero estos modelos son importantes para saber a eficazmente utilizar (o incluso sólo para elegir) herramientas existentes.

En este artículo, me gustaría continuar la discusión de patrones de persistencia con el patrón de diseño de unidad de trabajo y examine los problemas de persistencia ignorance. En la mayor parte de este artículo, va a utilizar un sistema de facturación genérico como el dominio del problema en el ejemplo se.

La unidad de modelo de trabajo

Uno de los patrones de diseño más comunes en desarrollo de software empresarial es la unidad de trabajo. Según Martin Fowler, el modelo de unidad de trabajo "mantiene una lista de objetos afectados por una transacción empresarial y coordina la escritura fuera de los cambios y la resolución de problemas de simultaneidad."

El modelo de unidad de trabajo no corresponde necesariamente algo que explícitamente crear usted mismo, pero el modelo muestra hasta en casi todas las herramienta de persistencia que Soy consciente de. La interfaz ITransaction en NHibernate, la clase DataContext en LINQ para SQL y la clase ObjectContext en Entity Framework son todos los ejemplos de una unidad de trabajo. Para dicho propósito, el conjunto de datos venerable puede utilizarse como una unidad de trabajo.

En otras ocasiones, es posible que desea escribir su propia interfaz de unidad de trabajo de específica de la aplicación o clase que ajusta la interna unidad de trabajo de la herramienta de persistencia. Esto puede hacerse de una serie de razones. Es posible que desea agregar tratamiento de registro, seguimiento o de error específica de la aplicación a la administración de transacciones. Quizás desee encapsular los detalles de la persistencia tooling del resto de la aplicación. Quizás desee Esta encapsulación adicional para facilitar su intercambiar fuera de las tecnologías de persistencia más adelante. O es posible que desea promocionar testability en su sistema. Muchas de las implementaciones de unidad de trabajo integradas de herramientas de persistencia comunes son difíciles de tratar en escenarios de pruebas de unidad automatizada.

Si desea crear su propia implementación de unidad de trabajo, tendría el probablemente aspecto similar a esta interfaz:

public interface IUnitOfWork {
  void MarkDirty(object entity);
  void MarkNew(object entity);
  void MarkDeleted(object entity);
  void Commit();
  void Rollback();
}

La clase de unidad de trabajo dispone de métodos para marcar las entidades como nuevos, modificados o eliminado. (En muchas implementaciones la llamada explícita a MarkDirty sería necesario porque la unidad de trabajo sí tiene alguna forma de determinar automáticamente qué entidades se han cambiado.) La unidad de trabajo también dispondrá de métodos para confirmar o distribuir todas de los cambios.

De forma, puede considerar la unidad de trabajo como un lugar para volcar el control de transacción todo el código. Las responsabilidades de la unidad de trabajo son los siguientes:

  • Administrar transacciones.
  • Orden de la base de datos inserta, elimina y se actualiza.
  • Impedir las actualizaciones duplicadas. Dentro de un solo uso de un objeto de unidad de trabajo, diferentes partes del código del pueden marcar el mismo objeto factura como modificados, pero la clase de la unidad de trabajo sólo emitirá un solo comando UPDATE a la base de datos.

El valor de utilizar un modelo de unidad de trabajo es liberar el resto de su código de estos problemas para que en caso contrario, puede concentrar en la lógica empresarial.

Con la unidad de trabajo

Una de las mejores maneras de utilizar el modelo de unidad de trabajo es permitir que las clases dispares y servicios a tomar parte en una sola transacción lógica. El punto clave aquí es que desea las clases dispares y servicios para permanecer ignorantes entre sí aunque pudiendo dar de alta en una sola transacción. Tradicionalmente, ha sido capaz de hacer esto mediante los coordinadores de transacción como MTS/COM + o el espacio de nombres más reciente de System.Transactions. Personalmente, yo prefiero utilizando el modelo de unidad de trabajo para permitir que las clases no relacionadas y servicios a tomar parte en una transacción lógica porque la considero que hace el código más explícitas, más fácil de entender y más sencillo a prueba de unidades.

Supongamos que el nuevo sistema facturación realiza acciones discretas en facturas existentes en diversos momentos en el ciclo de vida de factura. El negocio cambia estas acciones con bastante frecuencia y será con frecuencia desea agregar o quitar nuevas acciones de factura, por lo que vamos a aplicar la trama de comandos (consulte" Simplificar el diseño de sistemas distribuidos con el modelo de comandos, MSMQ y .NET") y crear una interfaz denominada IInvoiceCommand que representa una única acción discreto frente a una factura:

public interface IInvoiceCommand {
  void Execute(Invoice invoice, IUnitOfWork unitOfWork);
}

La interfaz de IInvoiceCommand tiene un método Execute simple que se llama para realizar algún tipo de acción mediante una factura y un objeto IUnitOfWork. Cualquier objeto IInvoiceCommand debe utilizar el argumento de IUnitOfWork para conservar los cambios volver a la base de datos dentro de esa transacción lógica.

Simple suficiente, pero este modelo de comandos más unidad de trabajo de trama no obtener interesante hasta que reunir varios objetos IInvoiceCommand (consulte la La figura 1 ).

La figura 1 con IInvoiceCommand

public class InvoiceCommandProcessor {
  private readonly IInvoiceCommand[] _commands;
  private readonly IUnitOfWorkFactory _unitOfWorkFactory;

  public InvoiceCommandProcessor(IInvoiceCommand[] commands, 
    IUnitOfWorkFactory unitOfWorkFactory) {

    _commands = commands;
    _unitOfWorkFactory = unitOfWorkFactory;
  }

  public void RunCommands(Invoice invoice) {
    IUnitOfWork unitOfWork = _unitOfWorkFactory.StartNew();

    try {
      // Each command will potentially add new objects
      // to the Unit of Work for insert, update, or delete
      foreach (IInvoiceCommand command in _commands) {
        command.Execute(invoice, unitOfWork);
      }

      unitOfWork.Commit();
    }
    catch (Exception) {
      unitOfWork.Rollback();
    }
  }
}

Con este método con la unidad de trabajo, puede Afortunadamente combinar y coincide con diferentes implementaciones de la IInvoiceCommand para agregar o quitar las reglas de negocio en el sistema de facturación manteniendo integridad transaccional.

Según mi experiencia, las personas de negocio parece interesa bastante Facturas no pagadas, en tiempo de ejecución, así que probablemente se va a tener que cree una nueva clase IInvoiceCommand que le alertan de agentes de la compañía cuando una factura se determina que en tiempo de ejecución. Éste es una posible implementación de esta regla:

public class LateInvoiceAlertCommand : IInvoiceCommand {
  public void Execute(Invoice invoice, IUnitOfWork unitOfWork) {
    bool isLate = isTheInvoiceLate(invoice);
    if (!isLate) return;

    AgentAlert alert = createLateAlertFor(invoice);
    unitOfWork.MarkNew(alert);
  }
}

La belleza de este diseño a mí es que la LateInvoiceAlertCommand se puede completamente desarrollado y probado independientemente de la base de datos u incluso los otros IInvoiceCommand objetos correspondientes a la misma transacción. En primer lugar, para probar la interacción de los objetos IInvoiceCommand con una unidad de trabajo, puede crear una implementación falsa de IUnitOfWork estrictamente para las pruebas para ser precisos, llamaría la StubUnitOfWork un auxiliar de registro:

public class StubUnitOfWork : IUnitOfWork {
  public bool WasCommitted;
  public bool WasRolledback;
  public void MarkDirty(object entity) {
    throw new System.NotImplementedException();
  }
  public ArrayList NewObjects = new ArrayList();
  public void MarkNew(object entity) {
    NewObjects.Add(entity);
  }
}

Ahora que tiene un interesante FALSO unidad de trabajo que se ejecuta independientemente de la base de datos, del techo de prueba para la LateInvoiceAlertCommand puede parecerse al código de La figura 2 .

La Figura 2 prueba accesorio de LateInvoiceAlertCommand

[TestFixture]
public class 
  when_creating_an_alert_for_an_invoice_that_is_more_than_45_days_old {

  private StubUnitOfWork theUnitOfWork;
  private Invoice theLateInvoice;

  [SetUp]
  public void SetUp() {
    // We're going to test against a "Fake" IUnitOfWork that 
    // just records what is done to it
    theUnitOfWork = new StubUnitOfWork();

    // If we have an Invoice that is older than 45 days and NOT completed
    theLateInvoice = new Invoice {InvoiceDate = 
      DateTime.Today.AddDays(-50), Completed = false};

      // Exercise the LateInvoiceAlertCommand against the test Invoice
      new LateInvoiceAlertCommand().Execute(theLateInvoice, theUnitOfWork);
  }

  [Test]
  public void 
    the_command_should_create_a_new_AgentAlert_with_the_UnitOfWork() {

    // just verify that there is a new AgentAlert object
    // registered with the Unit of Work
    theUnitOfWork.NewObjects[0].ShouldBeOfType<AgentAlert>();
  }

  [Test]
  public void the_new_AgentAlert_should_have_XXXXXXXXXXXXX() {
    var alert = theUnitOfWork.NewObjects[0].ShouldBeOfType<AgentAlert>();
    // verify the actual properties of the new AgentAlert object
    // for correctness
  }
}

Persistencia Ignorance

Al elegir o diseñar una solución de persistencia para uno de mis proyectos, Soy consciente del impacto de la infraestructura de persistencia en mi código de lógica empresarial, al menos en un sistema con una gran tratar de lógica de dominio empresarial. Lo ideal es que me gustaría diseñar, generar y probar la lógica de negocios relativamente independientemente de la base de datos y el código de infraestructura de persistencia. En concreto, se desea una solución que es compatible con la idea de persistencia ignorance u objetos de CLR anterior simple (POCOs).

En primer lugar, ¿qué es ignorance de persistencia, y donde hizo proceden? En su libro Applying Domain-Driven diseño y patrones: con ejemplos en C# y .NET (Pearson educación, Inc., 2006), Jimmy Nilsson define POCOs como "clases …ordinary en centrarse en el problema empresarial a mano sin agregar cosas por razones relacionadas con la infraestructura. ... Las clases deben centrase en el problema empresarial a mano. Nada más debe estar en las clases en el modelo de dominio."

Ahora, ¿por qué debería importa? Empecemos la explicación está muy claro que ignorance de persistencia es sólo un medio para distintos objetivos de diseño y no un objetivo final en y de sí mismo. Cuando evalúe una nueva herramienta de persistencia, estoy generalmente solicitando yo mismo las siguientes preguntas en orden descendente de importancia. Ignorance de persistencia no es completamente necesario para satisfacer estas preguntas, pero una solución basada en persistencia ignorance generalmente es mejor que las soluciones que requieren cuestiones de infraestructura va a incrustar en los objetos de negocio.

¿Puede ejecutar la lógica empresarial independientemente de la base de datos?

Esto es la pregunta más importante para mí. CREO que la que uno de los factores más importantes en el éxito de cualquier proyecto de software es la posibilidad de utilizar los ciclos de comentarios rápida. En otras palabras, desea acortar el tiempo y esfuerzo en entre codifica sólo algo nuevo "y " ha demostrado que el nuevo código funciona por lo que irán en a algo más "o" el nuevo código tiene un problema, por lo que solucionará ahora".

En mi carrera, han observado constantemente los equipos a ser más productivo en arquitecturas donde resulta fácil prueba unitaria o para simplemente incluso poner en práctica poco fragmentos de código nuevo sin ejecutar a través de la aplicación completa. Por el contrario, he encontrado las arquitecturas que tienen una estrecha ejecutan acoplamiento de tiempo entre la lógica empresarial y la infraestructura que ser muy difícil desarrollar en.

Vamos a deben reconsiderar el caso de la regla de negocio que se debe crear una alerta de agente de nuevo cuando se encuentra una factura abierta más de 45 días. En algún momento posterior, la organización puede decidir que se deben crear las alertas a los 30 días en su lugar. Para comprobar los cambios en la lógica de alerta de facturación, debe colocar en primer lugar el código en un estado que hace esta regla contra facturas abiertas y cerradas y las facturas anterior o posterior que el umbral de 30 días. Éste es el punto donde comienza la arquitectura que importa. ¿Puede recorrer derecha hacia arriba a la nueva facturación alerta lógica y unidad prueba una nueva regla de negocio o hacer tiene que saltar a través de técnicas hoops en primer lugar?

En términos de un ciclo de comentarios rápida, el extremo peor es un modelo en la lógica de negocios no puede funcionar sin la presencia de infraestructura. Por ejemplo, la primera propios O o administrador de recursos se ha creado forzado, puede escribir las clases de entidad como éste:

public class Invoice : MySpecialEntityType {
  private long _id;
  public Invoice(long id) {
    _id = id;
    // Read in the rest of the Invoice information 
    // from the database
    loadDataFromDatabase(id);
  }
  public Invoice() {
    // Hit the database 
    _id = fetchNextId();
  }
}

Con este diseño, literalmente, no se puede crear una clase de factura sin estar conectado a una base de datos. En el diseño original, no había forma sencilla para utilizar o ejercicio mis clases de entidad empresarial sin tener el motor de base de datos configurado correctamente y están disponible.

Es posible ciertamente escribir pruebas automáticas frente a código que se tiene acceso a la base de datos, pero normalmente requiere bastante más esfuerzo en tiempo de programador para configurar datos de prueba que para escribir pruebas automáticas con objetos que no dependen de una base de datos. Para configurar una factura en la base de datos simple, deberá competir con campos distintos de null y datos para satisfacer requisitos de integridad referencial que no pertenecen a la regla de negocio en cuestión.

¿En su lugar, sería mejor sólo decir "si tengo una factura abierta que es el 31 días, en." en el código y puede hacerse con él? Con ese fin, mover ¿la clase de factura a más de un enfoque de persistencia de ignorantes como éste:

// The Invoice class does NOT depend on 
// any sort of persistence infrastructure
public class Invoice {
  private long _id;

  public Invoice() { }

  public bool IsOpen { get; set; }
  public DateTime? InvoiceDate { get; set; }
}

Ahora, cuando desea probar la regla de alerta facturación en tiempo de ejecución, puede crear rápidamente una factura abierta que es el 31 días para el escenario pruebas con código sencillo en el techo de prueba como éste:

 [SetUp]
public void SetUp() {
  Invoice theLateInvoice = new Invoice() {
    InvoiceDate = DateTime.Today.AddDays(-31),
    IsOpen = true
  };
}

En este enfoque, ha separado el código de lógica de empresa para la regla de factura en tiempo de ejecución y la propia clase de factura fuera desde el código de persistencia. Como siempre y medida puede crear fácilmente datos de la factura en la memoria, puede rápida prueba unitaria las reglas de negocio.

Como un margen, al que está elegir una herramienta de persistencia existentes, tener cuidado de la forma en que se implementa carga diferida. Algunas herramientas implementará transparente carga lenta con el modelo proxy virtual para hacer carga diferida eficazmente invisible en las entidades empresariales a sí mismos. Otras herramientas dependen de las técnicas de generación de código que incrustar la compatibilidad de carga diferida directamente en las entidades empresariales y crear con eficacia un tiempo de ejecución estrecho acoplamiento desde las entidades a la infraestructura de persistencia.

Casi tan importante como el tiempo necesario para que los desarrolladores crear pruebas automáticas, es la velocidad con la que ejecución estas pruebas. Pruebas automáticas con acceso a datos o de acceso del servicio Web pueden ejecutar fácilmente una orden de magnitud o más lentamente de pruebas que ejecutar completamente dentro de un único valor de AppDomain. Esto puede no parecer un gran problema, pero como el tamaño del proyecto empieza a crecer a lo largo del tiempo, ejecución de baja velocidad pruebas automáticas pueden fácilmente exime de productividad de un equipo y incluso eliminar la utilidad de las pruebas automatizadas en primer lugar.

¿Puede diseñar el modelo de dominio independientemente del modelo de base de datos?

Ahora que ha desacoplado de la capa empresarial de la base de datos en tiempo de ejecución, estoy se enfrentan con el problema de si puede diseñar la estructura de objeto independientemente de que el esquema de la base de datos (y viceversa). Debe poder diseñar el modelo de objetos basándose en el comportamiento necesario de la lógica empresarial. La base de datos, por otro lado, se debe diseñar con eficacia de lectura y escritura de datos, así como exigir integridad referencial. (Por cierto, la integridad referencial es esencial para usar una herramienta O o administrador de recursos).

Para demostrar un escenario típico en el modelo de dominio puede difieren de la estructura de base de datos, vamos a cambiar el dominio de en el ejemplo se a un comercial del sistema de energía. Este sistema es responsable de seguimiento y precios de las cantidades de petroleum vendido, compraron y entregarán. En un sistema sencillo, un comercial puede incluir varios cantidades adquiridas y un registro de las cantidades de entrega. Le ofrecemos la rub, aunque: cantidad significa que la unidad de medida más el número de dichas unidades. Para este sistema comercial, supongamos que le registrar las cantidades en los tres unidades distintas:

public enum UnitOfMeasure {
  Barrels,
  Tons,
  MetricTonnes
}  

Si desea bloquear el modelo de dominio a la estructura plana del esquema de la base de datos, es posible que obtendrá las clases como éste:

public class FlatTradeDetail {
  public UnitOfMeasure PurchasedUnitOfMeasure {get;set;}
  public double PurchasedAmount {get;set;}
  public UnitOfMeasure DeliveredUnitOfMeasure { get; set; }
  public double DeliveredAmount { get; set; }
}

Aunque la estructura es adecuado para la estructura de la base de datos y cómodo para las soluciones que genera la estructura del código desde una base de datos existente, esta estructura no admite propio para llevar a cabo la lógica empresarial.

Una gran parte de la lógica empresarial de la energía comerciales del sistema requiere las cantidades para comparación, resta y agregan, pero debe suponga siempre que las unidades de medida son diferentes y realizar las conversiones de uno a otro antes de realizar cualquier comparación. De la dolorosa experiencia que puede indicar que utiliza la estructura sin formato genera directamente fuera de la base de datos de esquema realiza esta lógica laboriosa implementar.

En lugar de la estructura sin formato, vamos a implementar el modelo de dinero y crear una clase que modela el comportamiento de una cantidad, tal como se muestra en La figura 3 .

Cantidad de la figura 3

public class Quantity {
  private readonly UnitOfMeasure _uom;
  private readonly double _amount;

  public Quantity(UnitOfMeasure uom, double amount) {
    _uom = uom;
    _amount = amount;
  }

  public Quantity ConvertTo(UnitOfMeasure uom) {
    // return a new Quantity that represents
    // the equivalent amount in the new
    // Unit of Measure
  }

  public Quantity Subtract(Quantity other) {
    double newAmount = _amount - other.ConvertTo(_uom).Amount;
    return new Quantity(_uom, newAmount);
  }

  public UnitOfMeasure Uom {
    get { return _uom; }
  }

  public double Amount {
    get { return _amount; }
  }
}

Cuando se utiliza la clase de cantidad para el modelo y reutilizar el comportamiento común alrededor de la unidad de medida cantidades, la clase TradeDetail podría ser más parecidos a esto:

public class TradeDetail     {
  private Quantity _purchasedQuantity;
  private Quantity _deliveredQuantity;
  public Quantity Available() {
    return _purchasedQuantity.Subtract(_deliveredQuantity);
  }
  public bool CanDeliver(Quantity requested) {
    return Available().IsGreaterThan(requested);
  }
}

La clase de cantidad se definitivamente efectuar la lógica de TradeDetail más fácil de implementar, pero ahora se varía el modelo de objetos de la estructura de base de datos. Lo ideal es que sus herramientas de persistencia deben admitir este tipo de asignación.

El problema de tener varianza entre un modelo de objeto y un modelo de base de datos por lo general no surgir en sistemas con lógica empresarial sencilla. En esos sistemas, una arquitectura de registro Active que simplemente genera las clases de entidad de la estructura de base de datos puede ser la solución más sencilla. Como alternativa, puede utilizar una herramienta de asignador de base de datos que permite generar un esquema de base de datos de los objetos de entidad.

¿Cómo es la estrategia de persistencia afectan A la lógica empresarial?

No es un mundo perfecto. Las herramientas de persistencia tendrá algún tipo de su impacto en cómo forma las clases de entidad. Por ejemplo, mi equipo utiliza NHibernate para la persistencia. Debido a la forma en que NHibernate implementa las relaciones de propiedad de carga diferida, muchas de las propiedades de nuestras debe marcarse como virtual sólo para habilitar carga diferida como esta nueva propiedad de cliente en factura:

public class Invoice {
  public virtual Customer Customer { get; set; }
}

La propiedad de cliente se marca como virtual por ninguna otra razón que habilitar NHibernate crear un proxy dinámico para el objeto factura que proporciona una propiedad carga diferida de cliente

Marcar los miembros como virtual estrictamente para admitir la carga diferida es una molestia, pero hay peor posibles problemas. Los números de aumento de los equipos están usando diseño controlado por dominio (DDD). Uno de las estrategias comunes de DDD es crear clases de modelo que no pueden colocarse en un estado no válido de dominio. Las clases de modelo de dominio a sí mismos jealously también podrían protegerse los datos internos a aplicar reglas de negocio internamente. Para activar esta filosofía de diseño, una clase de facturas podría ser más parecidos a Figura 4 .

Clase de factura del modelo de dominio de la figura 4

public class Invoice {
  private readonly DateTime _invoiceDate;
  private readonly Customer _customer;
  private bool _isOpen;

  // An Invoice must always have an Invoice Date and
  // a Customer, so there is NO default constructor
  // with no arguments
  public Invoice(DateTime invoiceDate, Customer customer) {
    _invoiceDate = invoiceDate;
    _customer = customer;
  }

  public void AddDetail(InvoiceDetailMessage detail) {
    // determines whether or not, and how, a
    // new Invoice Detail should be created 
    // and added to this Invoice
  }

  public CloseInvoiceResponse Close(CloseInvoiceRequest request) {
    // Invoice itself will determine if the correct
    // conditions are met to close itself.
    // The _isOpen field can only be set by
    // Invoice itself
  }

  public bool IsOpen {
    get {
      return _isOpen;
    }
  }

  public DateTime InvoiceDate {
    get { return _invoiceDate; }
  }

  public Customer Customer {
    get { return _customer; }
  }
}

No es este método para elaborar un modelo de dominio aplicable a cada tipo de aplicación, pero si elige este estilo de arquitectura afectarán a la elección de herramientas de persistencia.

La versión de factura en la figura 4 tiene la función sólo un constructor que aplica la regla que no se puede crear ninguna factura sin una fecha de factura y un cliente. Tecnologías de persistencia muchas, si no la mayor parte, requieren una función de constructor sin argumentos.

Además, esta versión de la clase factura jealously protege campos internos como _isOpen sin las propiedades públicas establecedor. De nuevo, muchas herramientas de persistencia pueden trabajar sólo con las propiedades públicas. Si desea utilizar el estilo DDD más estricto de entidades, será necesario investigar si sus herramientas de persistencia pueden admitan la asignación de campos, propiedades privadas o las funciones de constructor con los argumentos.

Más unidades de trabajo

Hay algunos otros importantes problemas con el modelo de unidad de trabajo que vale la pena considerar. Si interesa utilizando el modelo de unidad de trabajo explícitamente en la aplicación, se deben investigados estos problemas en el contexto de la aplicación:

  • La división de la responsabilidad entre los repositorios y la unidad de trabajo. Es posible que diga que todos los leen ocurra repositorios y escribe a través de la unidad de trabajo. También puede utilizar una implementación de unidad de trabajo que obligue a realizar lecturas y las consultas a través de la unidad de trabajo para que el estado cambiar seguimiento más fácil.
  • Cómo proporcionar la unidad de trabajo correcto y los ayudantes de asignación de identidad subyacentes a las diversas clases participando en una transacción lógica. Muchas personas utilizan un contenedor de la inversión de control para adjuntar correctamente la unidad de trabajo para el HttpContext actual, el subproceso o otra estrategia de ámbito.

Persistencia ignorance es algo controvertido en la comunidad de .NET y su importancia es dudosas mucho. En este momento, persistencia ignorance no se admite también en la persistencia tooling disponible en Microsoft .NET Framework o en el ecosistema de .NET extendido. NHibernate es la herramienta una que viene más cercano, pero incluso con NHibernate tendrá que poner en peligro el modelo de dominio un poco para habilitar la persistencia.

Envíe sus preguntas y comentarios ammpatt@Microsoft.com.

Jeremy Miller , un MVP de Microsoft para C#, también es autor de la abrir de origenStructureMapherramienta para inyección de dependencia con .NET y la próximaStoryTellerherramienta para probar FIT supercharged en. NET. Visite su blog "Los desarrolladores de árbol de sombra" forma parte del sitio CodeBetter.