2009-03-12 6 views
0

Ich erweitere (nicht sicher, ob es das richtige Wort hier ist) eine partielle Cart-Klasse, die im Linq to SQL-Datenbankmodell generiert wurde.Geschäftslogik im Konstruktor - C#/Linq zu Sql

Die Geschäftslogik ist, dass es nur einen Warenkorb pro Kunde geben kann. Wenn ein Kunde keinen Einkaufswagen hat, sollte er erstellt werden. Wenn ein Kunde einen Einkaufswagen hat, sollte er zurückgegeben werden.

Hier ist, was ich tue:

public partial class Cart 
{ 
    //the rest of the Cart class is in the .dbml file created by L2S 
    public Cart(int userId) 
    { 
     Cart c = GetCurrentCart(userId); 
     this.CartId = c.CartId ; 
     this.UserId = c.UserId; 
    } 

    public Cart GetCurrentCart(int userId) 
    { 
     Cart currentCart = new Cart(); 

     // if cart exists - get it from DB 
     //if not - create it, save in DB, and get if right out 
     //all of this is done with Linq to SQL 

     return currentCart; 
    } 
} 

eine Methode aus dem Konstruktor aufrufen scheint einfach nicht richtig. Durchsetze ich die Geschäftslogik richtig?

Antwort

8

Ich würde fragen, warum die "Cart" -Klasse ist so schlau. In Domain Driven Design Bedingungen klingt es wie der Benutzer "besitzt" den Warenkorb. Also warum nicht etwas wie:

var user = // Load a user 
var cart = user.Cart; 

In diesem Fall könnte Ihr Warenkorb Getter träge laden/initialisieren den Warenkorb.

+0

guten Punkt. ist irgendetwas mit meinem Code falsch, abgesehen davon, dass es nicht DDD geschrieben wird? –

+0

Ich denke, es ist interessant, dass Sie selbst mit dem Code, den Sie gepostet haben, unsicher waren, ob Datenbanksuchen im Konstruktor richtig ist. Obwohl es nicht das schlimmste Verbrechen ist, ist es ein bisschen ein Code-Geruch. Ich denke, das ist ein Fall, in dem deine Instinkte gut waren. –

+0

Mit Code-Geruch, ich meine, es ist etwas, was Sie wahrscheinlich vermeiden möchten (wie Ihre Instinkte vorgeschlagen haben). Es ist also eine gute Idee, nach einem alternativen Design zu suchen (eines, das technisch sauberer ist, und das für die Problemdomäne mehr Sinn macht). –

5

Ich stimme mit Paul Stovell, es klingt wie Benutzer sollte den Warenkorb besitzen. Aber zu dem Zeitpunkt, an dem Ihr Konstruktor aufgerufen wird, haben Sie bereits eine neue Instanz von Cart. Mit C# können Sie den vom Konstruktor zurückgegebenen Verweis nicht ändern. Daher sollten Clients der Cart-Klasse, die den Konstruktor verwenden, eine statische Factory-Methode aufrufen (ich habe keine Erfahrung mit Linq in SQL). Dies funktioniert möglicherweise nicht direkt).

Ihre GetCurrentCart-Methode ist fast das; Sie müssen es nur statisch markieren. Darüber hinaus sollten Sie den Einkaufswagen-Konstruktor nur für das Erstellen eines neuen Einkaufswagens verantwortlich machen und es privat machen, damit Clients GetCurrentCart verwenden müssen. Eine Implementierung könnte etwa so aussehen:

public partial class Cart 
{ 
     // Make a new cart 
     private Cart(int userId, int cartId) 
     { 
      this.CartId = userId; 
      this.UserId = cartId; 
     } 

     private static Dictionary<int, Cart> CurrentCarts = new Dictionary<int, Cart>(); 

     public static Cart GetCurrentCart(int userId) 
     { 
      // TODO: Use a proper caching mechanism that will at least 
      //  remove old carts from the dictionary. 
      Cart cart; 
      if (CurrentCarts.TryGetValue(userId, out cart)) 
      { 
       return cart; 
      } 

      cart = /* try get cart from DB */; 
      if (cart == null) 
      { 
       // Make a new cart 
       cart = new Cart(userId, GenerateCartId()); 
      } 

      CurrentCarts[userId] = cart; 

      return cart; 
     } 
} 
+0

Warum Wörterbuch? Benutzer kann nur EINEN Einkaufswagen haben –

+0

Beachten Sie, dass der Schlüssel für das Wörterbuch die userId ist, daher kann pro Benutzer nur ein Warenkorb vorhanden sein. Das Wörterbuch ermöglicht es GetCurrentCart, exakt dieselbe Instanz des Einkaufswagens zurückzugeben, die für den vorherigen Aufruf mit derselben Benutzer-ID zurückgegeben wurde. – Dave