views:

23

answers:

1

Consider, for example:

public interface IStaff
{
    FullName name { get; set; }
    EMailAddress email_address { get; set; }
    SocialInsuranceId ssn { get; set; }
    PositiveInt age { get; set; }
    Address home_address { get; set; }
}

For some users, the viewmodel will only require name and email_address. Others may have a viewmodel that includes those properties plus ssn, age and home_address. Let's say there is also a statistician, whose view gets age and home_address.

Now, I could split this out into IStaffBasic, IStaffDetails, and IStaffStats with interface inheritance to limit the API in a given viewmodel to the appropriate properties.

However, when this entity is retrieved from the data service across the wire, it will still include the additional details, which must not occur.

So, would it be better to
(A) create wholly different entity types for each of these versions, somewhat polluting the service layer API with many additional near-duplicate query operations for each type, or
(B) always return a Staff entity, but (1) return them from the service with excluded properties set to null based on the authorization check at the service and (2) use limited interfaces within the viewmodels as described above, or
(C) use the very elegant pattern or solution that I haven't considered, but about which you're going to tell me.

Option A seems cleaner at the viewmodel level, but the service API is going to be nasty. Option B seems to add complexity to entity handling on the server, but better adherence to the open-closed principle.

Thoughts?

+1  A: 

Projection is the way to go - combine options A and B.

Your ORM should only interact with a single entity type, Staff, so you only have to maintain (and extend) a single set of mappings, queries, and so forth.

However, you'll also create different classes suitable for each security scenario (IStaffBasic, IStaffDetails, etc.), project the Staff instances into those, and return the projected objects over the wire:

Some ORMs support projection as a framework feature, but if need be, you can do it manually in your service layer.

Jeff Sternal
Thanks for the edit -- that clarified it for me.
Jay