¿Cómo diseño un DAL cuando tengo que lidiar con las relaciones?

7

Diga que estoy desarrollando un rastreador de errores, donde un ticket pertenece a como máximo un hito, y un hito puede tener muchos tickets. Cuando se elimina un hito (de la base de datos), todos los tickets asociados con ese hito deben tener su relación sin establecer (es decir, configurarse en null ). Esta es una relación simple.

Las clases son bastante simples y se asignan directamente a una base de datos:

public class Ticket {
    public ObjectId Id { get; set; }
    public string Title { get; set; }
    public ObjectId MilestoneId { get; set; }
}

public class Milestone {
    public ObjectId Id { get; set; }
    public string Title { get; set; }
}

Ahora viene la parte difícil: ¿dónde y cómo reinicio los campos MilestoneId ? Una posible solución es escribir una capa de acceso a datos mediante la creación de una clase gigante con todos los métodos de acceso a datos para todo tipo de objetos, en este caso, tickets e hitos. Otra solución posible es escribir varias clases (por ejemplo, TicketProvider y MilestoneProvider ), una para cada tipo de objeto, que proporcionen métodos de acceso a datos como Find , Save y Destroy .

Este último me atrae más porque no me gustan las clases monstruosas, pero hay una advertencia: el método que elimina los hitos tiene que restablecer el MilestoneId s de todos los tickets asociados a null . Esto significa que MilestoneProvider , que es responsable de manipular los hitos, de repente trata con los tickets.

¿Cómo se tratan las relaciones en las capas de acceso a datos y cómo puedo evitar la violación de SRP? ¿Debo poner todo el DAL en una clase, o debo separarlo y, de ser así, cómo puedo hacerlo mejor?

    
pregunta rightfold 27.12.2012 - 05:42

3 respuestas

2

Le sugeriría que encapsule esa lógica en el lugar donde realmente pueda eliminar el hito, ya que la eliminación de su ID de los tickets es un detalle de implementación de la lógica empresarial en el punto de eliminación. Lo importante es hacerlo en un solo lugar obvio en una transacción para que todo suceda o no pase nada.

Si está utilizando el patrón de repositorio, podría hacer algo en este sentido:

void Delete(int milestoneId)
{
    db.BeginTransaction();
    db.Execute("UPDATE Tickets SET MilestoneID = null WHERE MilestoneID = @p0", milestoneId);
    db.Execute("DELETE FROM Milestones WHERE MilestoneID = @p0", milestoneId);
    db.Commit();
}

Aquí está un poco sujeto a las preferencias personales, ya que podría argumentar que el MilestoneRepository no debería saber acerca de los Boletos, pero dependiendo de cuántos otros requisitos tenga a lo largo de estas líneas (por ejemplo, si no hay muchos) podría ser aceptable por ahora La otra opción es crear un servicio que tenga este conocimiento como este:

class MilestoneRepository
{
    void Delete(int milestoneId)
    {
        db.Execute("DELETE FROM Milestones WHERE MilestoneID = @p0", milestoneId);
    }
}

class TicketRepository
{
    void DetachAllFromMilestone(int milestoneId)
    {
        db.Execute("UPDATE Tickets SET MilestoneID = null WHERE MilestoneID = @p0", milestoneId);
    }
}

class MilestoneService
{
    void Delete(Milestone milestone)
    {
        unitOfWork.Begin(); // start transaction
        ticketRepository.DetachAllFromMilestone(milestone.Id);
        milestoneRepository.Delete(milestone.Id);
        unitOfWork.Complete(); // commit transaction
    }
}
    
respondido por el Trevor Pilley 27.12.2012 - 21:40
0

Como alternativa a hacerlo en el código de lógica de negocios de nivel medio, ofrezco un activador de Microsoft SQL Server:

CREATE TRIGGER dbo.DeleteMilestone
  ON dbo.Milestone
  INSTEAD OF DELETE
AS
  BEGIN TRANSACTION

  UPDATE t
  SET t.MilestoneId = NULL
  FROM dbo.Ticket t
  INNER JOIN DELETED d ON t.MilestoneId = d.Id;

  DELETE m
  FROM dbo.Milestone m
  INNER JOIN DELETED d ON m.Id = d.Id;

  COMMIT TRANSACTION
GO
    
respondido por el Jesse C. Slicer 27.12.2012 - 23:32
-4

Cree una propiedad de solo lectura en la clase principal, verifique si la identificación secundaria recuperada es nula den incrementarla o asignarla desde db.

    
respondido por el Jay Sampat 27.12.2012 - 17:37

Lea otras preguntas en las etiquetas