[ vujkev @ 14.01.2014. 18:22 ] @
Da kažemo da imamo hipotetičku višeslojnu aplikaciju.

Kao datalayer imamo EF i tabele: Korisnici, Racuni i Vozila i odgovarajuće entitete u EF (kolone u pomenutim tabelama nisu bitne za ovo pitanje)
Svaki korisnik može da ima jedan ili više zapisa u tabelama Racuni i Vozila

Business layer treba da omogući da korisnik koji ima "admin" prava može da izvuče sve podatke iz svih tabela, dok "običan" korisnik može da izvuče samo svoje podatke iz tabele Korisnici i poslednjih 10 zapisa iz ostale dve tabele.
Iz EF-a mogu da izvučem određenog korisnika, ali kroz property te klase mogu da izvučem sve podatke iz ostale dve tabele što treba ograničiti za "običnog" korisnika.

Kako ovo napraviti?

ps. Relativno sam nov u EF, pa imajte razumevanja
[ Mikelly @ 14.01.2014. 19:47 ] @
Pisem napamet, mozda bude koja greska.

var db = new TvojaBaza();
IQueryable<Korisnik> data1 = null;
IQueryable<Racun> data2 = null;
IQueryable<Vozilo> data3 = null;

if(logovaniuser je admin)
{
data1 = db.Korisnici;
data2 = db.Racuni;
data3 = db.Vozila;
}
else
{
data1 = db.Korisnici.Where(k => k.IdKorisnik == IdLogovanogUsera);
data2 = db.Racuni.OrderByDescending(r => r.IdRacun).Take(10); // Ako ti je recimo kljuc relevantna informacija po kojoj trazis "zadnje" zapise
data3 = db.Vozila.OrderByDescending(v => v.Datum).Take(10); // Ako imas nekakav datum pa po njemu sortiras
}

Onda mozes neku dodatnu logiku nad data1,2,3. Npr:

data2 = data2.Where(r => r.Iznos > 1000);

i na kraju pustis sve na UI:

data1.ToList();
data2.ToList();
data3.ToList();

Valjda ce ti pomoci nesto.
[ ssi @ 20.01.2014. 09:56 ] @
Moze i lepše, ako imas slozeniji uslov, koristi Specification pattern

Ako zelis da napravis web aplikaciju, koja uz to ima ok arhitekturu, pogledaj ovo:

EFMVC - ASP.NET MVC 4, Entity Framework 5 Code First and Windows Azure

U pitanju je kostur koji se moze jako lepo upotrebiti. Ima tu i tamo po neki deo koji mi se nije dopao ali, ok je. Nemoj da te zbuni Azure, opcion je.

Ja sam recimo izmenio service layer.

Primenjene tehnologije:

Windows Azure SDK <- OPCIONO
ASP.NET MVC 4
ASP.NET Web API
Entity Framework Code First 5
Autofac
AutoMapper

NUnit
Moq

[ vujkev @ 20.01.2014. 11:37 ] @
Mikelly, tvoj odgovor mi deluje OK. Malo sam ga modifikovao pošto bi, u ovoj test aplikaciji, kroz klasu Korisnik mogli da pristupe svim podacima iz druge dve tabele.

U aplikaciji sam prvo iz generisanog EF modela izbacio ova dva navigaciona proprety-a
Zatim sam proširio klasu Korisnik gde sam ručno dodao ova dva propertiy-a kao
Code (csharp):

        public IQueryable<Racun> Racuni
        {
            get
            {
                using (MyDBEntities db = new MyDBEntities())
                {
                    If( ... potrebne provere da li je korisnik admin)
                    .....
                    return db.Racuni.Where(c => c.IDKorisnika== this.IDKorisnika)....<ostali uslovi>;
                    .....
                }
            }
        }

         public IQueryable<Vozilo> Vozila
        {
         .....
        }
 


Ovo radi kako treba i deluje mi najjednostavnije.
[ ssi @ 20.01.2014. 11:51 ] @
@vujkev, takve stvari treba da budu u business layer-u.
[ Mikelly @ 20.01.2014. 19:50 ] @
Pazi, ssi je tehnički u pravu.

Generalno bi trebalo logiku koja ti je sad u modelu (klasa Korisnik) trebalo da izmjestiš u Bussiness Layer (MVC Controller vjerovatno, ili nešto slično, ne znam je li ti to Web ili Desktop aplikacija).
Ali, ako si ti zadovoljan, nemoj da slušaš nas :)

Ono na šta treba da obratiš pažnju, i što mi se ne sviđa je što u extenziji entity-ja (koji već pripada nekom ObjectContext-u ili DBContextu, ti instanciraš još jedan Context, kako bi dobio povezane entitete).
Ti entiteti će pripadati tom novom Context-u, a Korisnik originalnom.

To ti može praviti probleme prilikom query-inga. Sad pišem napamet, ali mislim da će ti ovo prijavit runtime grešku:
Code:

          db.Korisnici.Where(k => k.Racuni.Any()).Count();


Tako da, ako želiš da ostaneš pri trenutnom rješenju, trebalo bi da uhvatiš Context samog "Korisnika", pa da kroz njega dobiješ povezane entitete. Na osnovu entiteta možeš da dobiješ Context u slučaju da entitet ima bar 1 definisanu relaciju, u tvom slučaju mi se čini da je to zadovoljeno. Evo funkcije za tu svrhu (ne pravi niti jedan hit prema bazi ovo je samo na osnovu edmx definicije):

Code:

        public static MyDBEntities GetContext(this IEntityWithRelationships entity)
        {
            if (entity == null) throw new ArgumentNullException("null");
            var relationshipManager = entity.RelationshipManager;
            var relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault();
            if (relatedEnd == null) throw new Exception("Ne postoje definisane relacije");
            var query = relatedEnd.CreateSourceQuery() as ObjectQuery;
            if (query == null) throw new Exception("Entitet je Detached");
            return query.Context as MyDBEntities;
        }


Onda je koristiš na sledeći način:

Code:

        public IQueryable<Racun> Racuni 
        {
            get
            {
                MyDBEntities db = (this as IEntityWithRelationships).GetContext();
                If( ... potrebne provere da li je korisnik admin)
                .....
                return db.Racuni.Where(c => c.IDKorisnika== this.IDKorisnika)....<ostali uslovi>;
                .....
            }
        }



Pozdrav.


[ vujkev @ 23.01.2014. 22:46 ] @
Hvala obojici na odgovorima

Aplikacija koju "pravim" ne postoji nego je sve u domenu "šta ako". Generalno me zanima kako bi to napravili na najbolji, najlakši i najbrži način, a da bude po nekim "pravilima". Moja ideja je da BL bude totalno nezavisan i da na njega može da se kači MVC, Desktop, WPF, WCF ... bilo šta.

Dakle ako dobro shvatam pravilo je da klase koje napravi EF ne treba da menjam na ovaj način, a uslove za ograničavanje vraćenih rezultata treba da stavim u BL. Pošto entity klase ne smem da menjam znači da u BL moram da:
- napravim identične kopije entity-a iz EF-a i da ih popunjavam kopiranjem vrednosti property-a iz EF entity-a (koristeći npr. AutoMapper).
- u klasu KorisnikBL (klasa Korisnik u Business layer-u) dodam property Racuni i Vozila i ograničim rezultate koje vraćaju na osnovu ulogovanog korisnika (manje/više kao što sam napisao)
i UI bi u tom slučaju koristio te nove klase, a ne EF entity-e.

Na koji problem mogu da naletim ukoliko npr. ostanem pri ranije pomenutom rešenju da proširim/promenim entity Korisnik?