webForumDet fria alternativet

Avgränsningar i sitt Repository.

.NET

7 svar · 474 visningar · startad av Gladh

Medlem sedan maj 20012 812 inlägg
Frågan#1

Jag har stött på ett litet problem som jag inte ser någon direkt lösning på och undrar om någon annan har tänkt i samma banor som jag.

Säg att jag skapar ett CustomerRepository. Till det så skapar jag ett interface och det interfacet har 2 metoder:

public interface ICustomerRepository {
   void Delete(Customer customer);
   Cusomer GetByIdentifier(Guid identifier);
}

Eftersom det skall rensas en hel del annan data (så som filer, anrop till andra databaser osv osv) när en kund tas bort så skapar jag en applikationservices som jag använder när jag tar bort en kund.

public class DeleteCustomerAppServices{
   public void DeleteCustomer(Customer customer){
     ...
   }
}

Här har jag nu fint samlat allt det som måste ske när man tar bort en kund. Mitt problem är nu att om det kommer en annan utvecklare som skall skapa ett webgränssnitt så har han ju möjligheten att från sin kod anropa Delete(customer) metoden i mitt ICustomerRepository och han är nöjd med det eftersom han tror att det är det enda som han behöver göra! Men om han gör det så kommer det ligga slask data/information kvar på andra ställen.

Så hur kan jag hindra utvecklaren från att använda Delete()-metoden i ICustomerRepositoryt och tvinga honom att använda min DeleteCustomerAppServices. Jag har lite svårt att se hur jag skall kunna begränsa metoderna i mitt interface och samtidigt ha de testbara från ett testprojekt. Alternativet är olika interface men det känns inte helt rätt det heller!

Någon som har haft liknande tankar!

- M

Medlem sedan aug. 20003 575 inlägg
#2

Antingen kan du ju använda dig av internal på repositoryt så att i den koden han sitter kan han inte komma åt repository alls. För att lösa testningen så fungerar ju InternalsVisibleTo(testprojekt).

Ett annat alternativ som jag ser är att ha all borttagningsfunktionalitet i Repository, det finns väl egentligen inget som begränsar att den både skulle kunna arbeta mot databas och filsystem, dock så skulle den ju fungera mer eller mindre exakt som din DeleteCustomerAppService dvs ta in en klass som arbetar mot din databas och en klass som arbetar mot filsystemet, så det kanske är lite annorlunda namngivningar som krävs här bara :S.

public CustomerRepository : ICustomerRepository
{
    public CustomerRepository(ICustomerDbRepository dbRepository, ICustomerFileRepository fileRepository).....
}

Men som sagt vet inte om något av det jag skrivit nu är exakt rätt bara funderingar.

Medlem sedan mars 20007 896 inlägg
#3

Menar du att din webutvecklare skriver egna implementationer av ICustomerRepository? Om han inte gör det kan du ju faktiskt skapa ett beroende i själva implementationen, som använder sig av din *AppService. Jag tror att Nickemannen menar något liknande, men att han tar emot parametrarna i metodanropet. Det är ju ingen nödvändighet att göra, då det kan hårdkodas in i implementationen. Hur som helst är det väl egentligen ingen jättehit att skapa beroenden, men om man ska tvinga på folk funktionalitet ser jag ingen annan direkt utväg.

Ett annat förfarande, när man tänker outside the box, är att faktiskt inte ta bort användaren - utan bara markera den som inaktiv/"död". Det kan givetvis få konsekvenser om samma användare vill återregistrera sig, men det är absolut inte olösliga problem.

Medlem sedan aug. 20003 575 inlägg
#4

SPiN skrev:

Menar du att din webutvecklare skriver egna implementationer av ICustomerRepository? Om han inte gör det kan du ju faktiskt skapa ett beroende i själva implementationen, som använder sig av din *AppService. Jag tror att Nickemannen menar något liknande, men att han tar emot parametrarna i metodanropet. Det är ju ingen nödvändighet att göra, då det kan hårdkodas in i implementationen. Hur som helst är det väl egentligen ingen jättehit att skapa beroenden, men om man ska tvinga på folk funktionalitet ser jag ingen annan direkt utväg.

Ett annat förfarande, när man tänker outside the box, är att faktiskt inte ta bort användaren - utan bara markera den som inaktiv/"död". Det kan givetvis få konsekvenser om samma användare vill återregistrera sig, men det är absolut inte olösliga problem.

Nja jag menade mer att man skickar in implemmentationen för att ta bort användaren från databasen samt filsystemet till konstruktorn inte metoden :).

Medlem sedan maj 20012 812 inlägg
#5

nickemannen skrev:

Antingen kan du ju använda dig av internal på repositoryt så att i den koden han sitter kan han inte komma åt repository alls. För att lösa testningen så fungerar ju InternalsVisibleTo(testprojekt).

Nja jag kan inte sätta Internal i Repositoryt eftersom det ligger i ett eget assembly, det skulle vara om man lyckas sätta det på metoden i interfacet, har aldrig testat men spontant känns det som det inte borde gå....

spin skrev:

Menar du att din webutvecklare skriver egna implementationer av ICustomerRepository

Nej då, han (han finns inte, det är ett påhittat exempel) använder sig av Interfacet som finns, men eftersom interfacet är en referens till mitt repository så kan han ta bort användaren i databasen utan att ta bort data som har referenser till denna användare.

spin skrev:

Ett annat förfarande, när man tänker outside the box, är att faktiskt inte ta bort användaren - utan bara markera den som inaktiv/"död". Det kan givetvis få konsekvenser om samma användare vill återregistrera sig, men det är absolut inte olösliga problem.

Nja.. säga att användaren har en massa stora filer som bara ligger och tar plats, om användaren försvinner så kan man ju ta bort dessa filer och därmed skapas uttrymme... elleså måste man köra en del logik kod om man tar bort användaren och den koden bör ligga i domänen och inte i repositoryt.

Så det jag vill egentligen är att ha 2 vyer på mitt interface.

När jag är i min AppServices så skall interfacet se ut så här.

public interface ICustomerRepository {
   void Delete(Customer customer);
   Cusomer GetByIdentifier(Guid identifier);
}

och om jag är någon annanstans i koden så skall interfacet se ut så här:

public interface ICustomerRepository {
   Cusomer GetByIdentifier(Guid identifier);
}

Vilket så fall tvingar andra utvecklare att ställa sig frågan, hur tar jag bort en Kund? Och där med leta upp min AppServices som finns. För annars är risken att de bara använder sig av ICustomerRepository.Delete() och så blir det inte riktigt bra i slutändan.

Det går ju att lösa med 2 olika interface men det är inte heller riktigt vad jag vill...

- M

Medlem sedan maj 20012 812 inlägg
#6

Kom och tänka på en sak!

Borde det inte gå kontroller imin Delete metod i Repositoryt vilken metod som exekverar min Delete-metod. Och om det inte är rätt metod som kastas ett fel som säger att denna metod endast får kallas från följande metod.

Kanske till och med lösa det med något snyggt attribute istället för kod i min Delete-metod.

Frågan är bara hur jag skall lyckas exekverar kontrollen av attributet innan min metod exekveras utan att lägga till kod i min egen metod !?!?!?!?!

Skall nog funderar vidare på det, inte så snyggt som att metoden inte är tillgängligt utan för mitt "scope-område" men det tror jag kommer kräva 2 olika interface och frågan vad som blir lättast att underhålla i längden. Kanske 2 interface blir bäst ändå.... arrghhh...

- M

Medlem sedan aug. 20003 575 inlägg
#7

Du skulle ju kunna kolla stacken, men nej jag tror inte heller på den lösningen :(

Medlem sedan dec. 19996 522 inlägg
#8

Tycker inte det låter som en bra idé att kolla av vilken metod som anropar, antingen tror jag på ytterligare en abstraktionsnivå med ytterligare ett interface som ärver från ditt ICustomerRepository.

Alternativt ett AOP-approach (med attribut på interfacet) som med interceptors kollar av någon bra context-container för vem det är som anropar. Men jag har svårt att se en bra container, om det inte finns ibyggt i något AOP-ramverk.

255 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
122 ms — deklarationer (db)
0 ms — hämta statistik (cache)
126 ms — hämta tråd, inlägg och bilagor (db)
127 ms — ändringar (db)