Create class based on roles - c#

I am developing a application for sports clubs administraion. And my problem is that I have one primary class Member which contains all the "default" information (name, surname, gender...) and two other classes Coach and Practitioner which inherit from Member. A coach has some specific properties (salary, trainings held in current month...) wheres a practitioner has some others (isCompetitor, category ...)
The problem is that a Practitoner can also be a Trainer as well as the other way around. How can I model this into something that is better then having two entries for the same person?
Edit: this is how it looks now
Class Member {}
Class Coach:Member {}
Class Practitioner:Member {}

You can create one class 'member' that contains a list of roles. Each role (coach and/or practitioner) inherit from a base class 'role' which contains all properties you now have in your member class. Coach and practitioner than have their own specific properties. So:
public class Member {
public IList<Role> Roles { get; private set; }
public Member(){
Roles = new List<Role>();
}
}
public class Role {
public string SomeGlobalProperty { get; set; }
}
public class Coach : Role {
public string SomeSpecificProperty { get; set; }
}
public class Practitioner : Role {
public string SomeSpecificProperty { get; set; }
}

If you're only looking at them in one way at a time - so as one of a group of practitioners, or as one of a group of trainers - then you can create them as the specific type of member they are being viewed as at a time. If required, you can add a boolean property "IsTrainer" to practitioner and "IsPractitioner" to trainer, to indicate that there is more info about that person elsewhere.
This presumes you're only looking at them in one way at a time, and not getting a page with all info about the person.

SImeple: Realize that you basiaclly need to read an intro book into OOP.
A Member is a Member (and even that is disputable - acutally it is a Party, regardless of what it does).
It has different roles which are basically a collection of roles, all with start and end date.
Party
CoachInformation
PractitionerInformation
etc.
I suggest reading "The Data Model Resource Book", volume 1 - they go into great detail about this standard problem and how most people get it wrong.

Related

How do I define a field ONCE, then use that definition in multiple entities?

I am using class inheritance to add a set of basic fields that all my entities must include. When I do this, EF Core honors any data annotations that exist in the base class, such as [TimeStamp], on the class that is inheriting from it:
public class SomeClass : BaseEntity
{
public string SomeEntityField { get; set; }
}
public class BaseEntity
{
public int Id { get; set; }
public DateTimeOffset UpdatedDate { get; set; }
public DateTimeOffset CreatedDate { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
The above is great when I want to add all inherited fields.
But, what if I wanted to to be able to create a field definition ONCE, and then use that definition in just a few other entities whilst also inheriting from the base class (above) at the same time?
Lets suppose I have this entity, ItemType:
public class ItemType : BaseEntity
{
[StringLength(28)]
public string ItemTypeId { get; set; }
...
I'd like to be able to define the field ItemTypeId in one place, and then use it on multiple entities including the above table WITHOUT having to manually add/maintain the annotation(s) in all those entities. For example, if I need to make the field wider like [StringLength(50)], I adjust it in one place and then all associated fields are updated on the next migration since they all "read" from the same definition. I've tried
using interfaces, but data annotations on interfaces are not honored by EF.
multiple inheritance, but that can't be used because I may need multiple "one-off" fields (and interfaces don't work as per #1)
According to CS1721 nothing will work (ok, with the exception of the single base class itself).
I think ideally I'd like to be able to define the entity fields in CommonFieldType as in the code below, and then have target entities inherit from them, but unfortunately that can't work for the reasons above.
namespace RDCApp.Shared.CommonFieldType
{
public abstract class ItemTypeIdCFT
{
[StringLength(28)]
public string ItemTypeId { get; set; }
}
public abstract class AnotherCFT
{
[StringLength(100)]
public string AnotherField { get; set; }
}
...
I can't be the only person who needs/would like this so is there another way?
I am aware that the Fluent API could be used, but my project is so invested in data annotations that using that (as well as) feels wrong, and means I have 2 places to look in and define field attributes against. Defining against the POCOs directly just feels right to me!
EDIT
To qualify what "feels right to me" means: my VS solution includes both the server (ASP.NET Core) and client side (Blazor WASM) projects. Both tiers can 'see' the entities/POCOs in a shared project and both tiers need to know what the annotations are to perform validation. This means I only need to define validation/attributes once and in turn both tiers have sight of that.
For me, Fluent is not a suitable option - though if this were a typical server side only App I'd shoot for Fluent.
You could define an interface and a generic fluent api helper method to define the fields.
public interface IHasItemType{
int ItemTypeId { get; set; }
}
public void DefineItemType<T> (EntityTypeBuilder<T> builder) where T:IHasItemType{
builder.Property(i => i.ItemTypeId) ...
}
Or you could apply conventions in OnModelCreating
foreach (var table in modelBuilder.Model.GetEntityTypes())
{
foreach (var column in table.GetProperties())
{
// ...
}
}
Fluent API was not suitable for my project need.
Custom annotations would work great for validation logic on both tiers, but unfortunatley DB schema definitions like [StringLength(30)] can't work (or at least I couldn't get to that).
So I landed on a workaround and although I'm not in love with it, it is serviceable for my specific need:
First, I define a particular fields attributes as constants:
public class FieldAttributeValues
{
public const string InventSerialIdComment = "Unique Id of the asset";
public const int InventSerialIdStringLength = 25;
public const bool InventSerialIdRequired = true;
...
}
Then, those constants can be used inside data annotations, for example:
public class SpecAttribute : BaseEntity
{
[Required(AllowEmptyStrings = FieldAttributeValues.InventSerialIdRequired)]
[StringLength(FieldAttributeValues.InventSerialIdStringLength)]
[Comment(FieldAttributeValues.InventSerialIdComment)]
public string InventSerialId { get; set; }
...
}
The downside to this approach is that the developer has to consciously check the FieldAttributeValues class for defined values for a particular field (sort of a manual convention process I guess).
The upshot is that the developer isn't implicity forced to use all of the attributes or even the attribute values as defined, since not all entities will always require the same setup across the patch - i.e. [Required(true)] might generally hold true for most entities, but not some other edge case entity.

Can i use the same properties for different classes?

I'm supposed to find the classes and their responsibilities from the problem statement.
The bank offers the following type of accounts to its customers: savings account, checking account, and money market account. customers are allowed to withdraw (decrease) and deposit (increase) money into those accounts.
my question is:
Can I create 3 different classes that use the same 2 properties (increase and decrease)? Also, would it work for the above scenario. Thanks in advance.
Why not? You could create one parent class with that properties and get inherited by child classes. Also you can create interface and implement custom logic for each class you want to have such property.
public class Parent
{
public int Increase { get; set; }
public int Decrease { get; set; }
}
public class Child1 : Parent
{
}
public class Child2 : Parent
{
}

How to pass different class objects in another class and expect they will be treated similarly?

First of all, it was difficult to find a proper title for my question... sorry in advance for this.
I am facing an issue with C# .NET. I'll try to simplify it with a temporary example.
I have three classes:
book
movie_dvd
game_dvd
each of them have the same base properties such: id and name. We can however suppose they have other different properties and different methods to be the same class. They can of course be children of a parent class to make it better.
Then I create List of each of these classes to define my collection of books, movies and games. Their id property is of course matched with the key of the List, and as I insert each item in the List I give them an appropriate name (their title).
I have a main winForm with 3 buttons: “Show Books Collection”, “Show Movies Collection” and “Show Games Collection”. The user can click one of them, and then another window appear and show the passed collection inside a ListBox (or whatever).
Now here's my problem.
Right now I'm creating three separate (but almost identical) WinForms to display the content of each collection (books, movies, games), which I think is greatly overdoing things. What I would really like to do is create a single window to display the content of any of these collections. The problem is that if I pass a book object/class inside the parameters of the new winForm, on the other side it expects to be a book object.
How can I use a single Winform to display the title of each of these differnt objects without duplicating the WinForm code over and over?
If your form displays the 'common stuff' between the 3 classes - ID, Title, reviews, etc - than you have two choices:
Design a base class that contains these common attributes that each of the other classes can derive from, each possibly overloading and/or modifying the functionality of the base. The form accepts lists of the base class.
Design an interface that defines the base properties and have each of your classes implement it. The form accepts lists of objects that implement the interface.
Both of these solutions are somewhat future-proof too - you can define a 4th kind of thing that inherits or implements accordingly and your form will be none the wiser!
I like #2 better becuase it is great for testing - you can mock up any class that implements your interface and pass it to your form to test it out. No need to test with known-book/dvd/game data!
I'm not a fan of the casting-solutions becuase they're brittle, and tough to extend.
If each of these objects will have the same properties (e.g. Title) then you create a base class with those properties. You could then create more specific properties in the derived classes.
public abstract class MediaBase
{
public String Title { get; set; }
public Int32 Id { get; set; }
}
public sealed class Book : MediaBase
{
public String Author { get; set; }
public Int32 Pages { get; set; }
}
public sealed class MovieDvd : MediaBase
{
public String Director { get; set; }
public Int32 Length { get; set; }
}
public sealed class GameDvd : MediaBase
{
public Int32 NumberOfPlayers { get; set; }
}
Or you could pass the parameters as objects and then cast them back into their actual type.
if (parameter is book)
{
book theBook = ((book)parameter);
}
else if (parameter is movie_dvd)
{
movie_dvd movieDvd = ((movie_dvd)parameter);
}
else if (parameter is game_dvd)
{
game_dvd gameDvd = ((game_dvd)parameter);
}

Modelling "I'm a * but I'm also a **"

In [this post], I'm struggling to implement a State Pattern as #jonp suggests. I don't quite get how to use what's he's posted but it leads to the thought that maybe I'm trying to fit a square peg into a round hole. So my question:
If I have a visitor to my site that can play multiple roles i.e. a User could be a Vendor, an Employer, an Advertiser, OR all of the above, should I be using inheritance? I've declared:
class Vendor : User {}
class Advertiser : User {}
et cetera, but when a user is both a vendor and an employer then instances of different classes really point to the same underlying object... I'm not sure this can work. How do I model it?
* update *
thanks everyone (you all get a point (it's all I can give)). I've been pulling my hair out over deep-copies with EF, downcasting and the state pattern for the last several days. The role approach makes much more sense.
This sounds like a situation to which the attribute pattern (or so I call it) would be very appropriate. It's a much more loosely-coupled approach than simple inheritance that can be used to specify multiple "behaviours" or in your case kinds of User. It's really nothing more complicated than an object having tags of another kind of object.
The easiest way to implement it would be to have a concrete User class, with a read-only property IList<UserRole> (internally this can be a List<T> field perhaps). Your UserRole class would then be abstract, and VendorRole/AdvertiserRole/etc. would derive from it, allowing you to tag on an arbitrary number of different roles (even ones of the same type) onto a given user. These roles can in addition define their own custom behaviours, utility methods, etc.
In addition, you could define a GetRole<TRole> method on your User class to facilitate access to roles of a specific type (assuming each User only has a single Role of a specific subtype).
Side note: you may also consider the decorator patern, which is closely related to the above mentioned pattern -- though personally I feel it is overkill here, and really adds nothing in terms of flexibility or power. It often just obscures what you're trying to do; though feel free to investigate anyway.
You should favor Composition over Inheritance if the different roles have to contain different logic that would be implemented using polymorphism and abstract methods, for example:
public class User
{
public Role Role { get; set; }
}
public abstract class Role
{
abstract void DoRoleSpecificStuff();
}
public class Vendor : Role
{
public void DoRoleSpecificStuff()
{
/* ... */
}
}
public class Employer : Role
{
public void DoRoleSpecificStuff()
{
/* ... */
}
}
public class Advertiser : Role
{
public void DoRoleSpecificStuff()
{
/* ... */
}
}
If a User can have multiple Roles, consider using a Roles collection property:
public IEnumerable<Role> Roles { get; set; }
Otherwise, an enumeration using the [Flags] attribute could be fine, too, depending on whether you need to be able to assign multiple Roles:
public class User
{
public Roles Roles { get; set; }
}
[Flags]
public enum Roles
{
Advertiser = 0x0,
Employer = 0x1,
Vendor = 0x2
}
You would assign a combination of different roles as follows:
User user = new User
{
Roles = Roles.Advertiser | Roles.Vendor;
};
That would make the User both an Advertiser and a Vendor, but not an Employer.
“I'm a * but I'm also a **” is known as Multiple Inheritance. C# does not support this, so you shouldn't be considering it.
It's indeed composition over inheritance here, but it's more like this if a single user can have multiple roles.
If there are relatively few roles, a 'parking lot' analogous to an outer join result may work. In this pattern, no Role base class is required.
class User
{
// all of these may be null if not applicable
VendorRole VendorRole { get; set; }
EmployeeRole EmployeeRole { get; set; }
AdvertiserRole AdvertiserRole { get; set; }
}
If a user may have multiple instances of a single role, a collection pops up:
class User
{
// all of these may be null if not applicable
VendorRole VendorRole { get; set; }
EmployeeRole EmployeeRole { get; set; }
ICollection<AdvertiserRole> AdvertiserRoles { get; }
}
Alternatively, if there may be a messy pile of roles, if roles get added dynamically, or what have you, you'll need a collection and a base type. If Entity Framework is involved, though, dynamically added roles seem unlikely to me.
class User
{
ICollection<Role> Roles;
}

building flexible and reusable class hierarchy

Let's review some entities:
Company;
Collaborator;
Chief;
Subordinate workers.
There are some rules:
Collaborator could be one of these: Sales, Manager,
Employee;
Sales and Manager could have subordinate workers (of any type decribed in the 1st rule);
Sales, Manager, Employee could have chief;
Each role has its own Salary
calculation method.
So the target is to create flexible & reusable class hierarchy.
First thing that confuses me is "can have" phrase. Should it be implemented as a composition? If it is said "can have as many" should it be a composition with list of objects?
Should I create abstract class Collaborator and then inherit from it 3 other types or there is more smart way?
What is the best way to tie all the entities together and have good reusable assembly?
"Can have" and the fact that its followed by "workers", tells me this is a "has a" relationship (composition) with a 0 to many relationship (so a list as you mention that could be empty)
An abstract class Collaborator seems reasonable.
Can have is represented in UML as (0..*) which means either 0 or more, yes composition with a list of objects would be good, use collections not an array.
Collaborator is an Abstract class since there will be no instances of Collaborator itself. Inheriting the 3 types of Collaborator is the best way I guess.
I have to add that, if you only have one company in your project, you need to implement the Singleton design pattern.
About the Salary use virtual method and override it.
I hope this is not your homework ;)
I find the question poorly formulated, the design can change severly by just adding small extra information.
Based on what you wrote, I might consider creating the following classes ('-' means extends):
Company
AbstractCollaborator (Chief member, CalculateSalary() { return base + AdditionalSalary() }, abstract AdditionalSalary())
- Chief
- AbstractLeader ( List subordinates )
-- Sales
-- Manager
- Employee
Chief would have no chief set for itself. I would try to prevent using virtual functions, and try using abstract functions instead.
Another option would be to simply using one class. It's all nice and well that only Sales or Manager can have subordinates, but in a real world situation it might be necessary for anyone to have subordinates. The function of any type of employee could simply be specified by a enum value instead.
It all depends greatly at where you are going with this ...
I guess the answer to this question is subjective and would change depending on your needs but this is how I would implement it:
public class Company {
public List<Collaborator> Collaborators { get; set; }
}
public abstract class Collaborator {
public Collaborator(Company company) {
company.Collaborators.Add(this);
}
public virtual Decimal Salary(object value);
public Company Company { get; set; }
}
public class Sales : Collaborator {
public override Decimal Salary(object value) {}
public List<Collaborator> Subordinates { get; set; }
public Collaborator Chief { get; set }
}
public class Manager : Collaborator {
public override Decimal Salary(object value) {}
public List<Collaborator> Subordinates { get; set; }
public Collaborator Chief { get; set }
}
public class Employee : Collaborator {
public override Decimal Salary(object value) {}
public Collaborator Chief { get; set }
}
This code has not been tested.

Categories