Can I create multiple identity tables in ASP.NET MVC? - asp.net-mvc-5

In my project, Admin adds Instructors, then each Instructor adds his students. When they are added, they'll receive an email asks them to complete registration .
I have the following classes in my project :
1-Student class
Student: int id, int Registry number, int grade, string password, string email, string name
2-Instructor class:
Instructor: int id, string name , string email , string password
3-My database context:
public class InstructorContext:DbContext
{
public InstructorContext() : base("InstructorContext")
{
}
public DbSet<Instructor> Instructors { get; set; }
public DbSet<Student> Students { get; set; }}
When a user loges in , I must determine whether he is an Admin or Instructor or Student. Do I have to use role-based authentication? I already have 2 separate classes for different roles. Is it possible for both of them to inherit from IdentityUser?

No, you cannot have multiple user tables with Identity, at least not technically. All the other core components of Identity (roles, claims, logins, etc.) are setup with foreign keys to one user table.
For your scenario here, you should use inheritance. For example:
public class ApplicationUser : IdentityUser
public class Instructor : ApplicationUser
public class Student : ApplicationUser
By default, Entity Framework will create the one table for ApplicationUser and add a Discriminator column to it. This column will have one of three possible values: "ApplicationUser", "Instructor", and "Student". When EF reads from this table, it will use this column to instantiate the right class. This is what's known as single-table inheritance (STI) or alternatively as table-per-hierarchy (TPH). The main downside to this approach is that all of the properties for all of the classes must be represented on the same table. If you're creating a new Student for example, the columns for an Instructor would still be on the record, only with nulls or defaults for those values. This also means that you can't enforce a property on something like Instructor be required at the database level, as that would prevent saving ApplicationUser and Student instances which are unable to provide those values. In other words, all your properties on your derived classes must be nullable. However, you can always still enforce something like a property being required for the purpose of a form using view models.
If you really want to have separate tables, you can somewhat achieve that goal by changing the inheritance strategy to what's called table-per-type (TPT). What this will do is keep the table for ApplicationUser, but add two additional tables, one each for Instructor and Student. However, all the core properties, foreign keys, etc. will be on the table for ApplicationUser, since that is where those are defined. The tables for Instructor and Student would house only properties that are defined on those classes (if any) and a foreign key to the table for ApplicationUser. When querying, EF will then do joins to bring in the data from all of these tables and instantiate the appropriate classes with the appropriate data. Some purists like this approach better as keeps the data normalized in the database. However, it's necessarily heavier on the query side because of the joins.
One last word of caution, as this trips people up constantly dealing with inheritance with Identity. The UserManager class is a generic class (UserManager<TUser>). The default instance in AccountController, for example, is an instance of UserManager<ApplicationUser>. As a result, if you use that instance, all users returned from queries will be ApplicationUser instances, regardless of the value of the Discriminator column. To get Instructor instances, you would need to instantiate UserManager<Instructor> and use that for your Instructor-related queries.
This is especially true with creating users for the first time. Consider the following:
var user = new Instructor();
UserManager.Create(user);
You might expect that the user would be saved with a discriminator value of "Instructor", but it will actually be saved with "ApplicationUser". This is because, again, UserManager is an instance of UserManager<ApplicationUser> and your Instructor is being upcasted. Again, as long as you remember to use the appropriate type of UserManager<TUser> you'll be fine.

Related

Split Model declaration among several app in Django

I am working and building my website with Django and I am facing this logical issue.
My project is made by several app.
I would like to declare in each one of these a "piece" of a bigger model that will be represented in one single table-
Example:
model Person
model DetailsPerson
As each single app specifies a specific part of the person, my idea was to decentralize the declaration of DetailsPerson model so that they figure in one single table but each app enlarge the fields the app needs to work.
Is this possible?
EDIT 25/11/2021: here is a graphical representation of how I would like my models be working like
I would like to declaire, "to detail" the table Person adding in various app the fields the app itself introduce. In this way I can have a single table with various fields, introduced time by time as I create new apps into my project.
Is this possible? My aim is to keep only one table.
I tried with Nechoj's first solution but declairing Person(models.Model) and then in another app PsysicalModel(Person) adding field_1 and field_2 and then makemigrations and migrate doesn't fill my table with field_1 and field_2 but leaves the table with only id_person, birthdate and city.
Class Inheritance
You can use class inheritance, like
class Person(models.Model):
(fields)
# in other file, import this class an inherit
class PersonWithDetails(Person):
(add. fields)
EDIT: According to the docs on multitable inheritance this will create an additional table for PersonWithDetails that holds the additional fields. However, to the user it appears as if all data is stored in a single table. For example, filterand update queries work as expected:
PersonWithDetails.objects.filter(<some criteria>)
will return instances that contain all fields (both from Person and PersonWithDetails) as if all fields where stored in a single table PersonWithDetails. Furthermore, it is possible to select all persons irrespective of their details:
Person.objects.all()
will return all Person instances, including those that have been created as PersonWithDetails. If you have a Person instance p at hand, then you can check whether a special attribute is present and then know, whether this instance is also a PersonWithDetails:
if p.personwithdetails is not None:
p.personwithdetails.field_1
This example show how to acces fields of the PersinWithDetails if the instance at hand is Person.
OneToOneField
Another option is to use one-to-one relations.
class Person(models.Model):
(fields)
# in other file, import this class and do
class DetailsPerson(models.Model):
person = models.OneToOneField(Person, on_delete=models.CASCADE)
(additional fields)
In case of adding details to a Person class, I would prefer the second option.
ForeignKey
And if you want to have several different Detail classes to one Person, use ForeignKey:
class DetailsPerson1(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
(additional fields)
class DetailsPerson2(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
(additional fields)

Aggregate or entity without business attributes

Regarding below excerpt, concerning cqrs and ddd, from Patterns, Principles, and Practices of Domain-Driven Design by Nick Tune, Scott Millett
Does it mean that domain model on command side can omit most of business attributes ?
How would it look like for eg Customer Entity?
Could Customer entity omit FirstName, Surname etc?
If so, where would these business attributes be? Only in read model in CustomerEntity?
Or maybe apart from CustomerEntity containing all business attributes there would also be CustomerAggregate wrapping CustomerEntity with 1:1 relation, and command object would operate on CustomerAggregate? (seems strange to me).
What does it mean "Customer entity desn't make sense"?
The text you pointed means that you do not have to model a reusable Entity for your whole system or even for your whole bounded context (Do not model reusable real life things). Doing this is a bad design.
You have to model an Aggregate that performs an action. You feed the Aggregate with only, and just only, the data needed to perform that action and the aggregate response, the changes the domain suffered, is what you have to persist.
Why Entities and V.O.'s then?
To model consistency, encapsulation and decoupling is the basic part but these are implementation details. For DDD what matters is that are different roles (or concepts).
When feeding the aggregate (constructor, function call parameters, etc) the aggregate has to know if it is working with entities and/or with V.O. to build its response.
If the domain action means a change in an attribute of a entity (something with unique identification in your whole system) the response of the aggregate (once all rules and invariants has been checked) should include the new attribute value and the identification of that entity that allows persist the changes.
So, by default, every aggregate has its own entity with the unique identification and the attributes needed for the aggregate action.
One aggregate could have a Customer entity with ID and its Name.
Another aggregate could have a Customer entity with ID and its Karma points.
So every aggregate has its own inner Customer entity to work with. When you feed an aggregate you pass Customer data (i.e. ID and name or ID and Karma points) and the aggregate treats that info as a entity (It is a matter of implementation details if there is a struct, class, etc internally to the aggregate to represent the entity).
One important thing: If you just need to deal with entities ID's then treat it as a V.O. (CustomerIdentityVO) because the ID is immutable and, probably, in that action you just need to write this CustomerIdentityVO in some field in persistence, not change any Customer attribute.
This is the standard vision. Once you start to identify common structures relevant to several aggregates or one aggregate that can perform several actions with the same data fed you start to refactoring, reusing, etc. It just a matter of good OOP design and SOLID principles.
Please, note that I am trying to be higly above of implementation details. I know that you almost always will have unwanted artifacts that depends of programing paradigm type, chosen programing language, etc. but this approach helps a lot avoiding the worse artifact you could have.
Recommended readings:
http://blog.sapiensworks.com/post/2016/07/29/DDD-Entities-Value-Objects-Explained
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2
https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3
and
https://blog.sapiensworks.com/post/2016/08/19/DDD-Application-Services-Explained
for a complete puzzle vision.
If you are using Event Sourcing then it's true that you can model aggregates without adding attributes that they don't need for implementing the business logic.
Here's an example:
class Customer {
public Guid ID { get; private set; }
public Customer(Guid id, firstName, lastName, ...) {
ID = id;
this.AddEvent(new CustomerCreatedEvent(id, firstName, ....);
}
public void ChangeName(firstName, lastName) {
this.AddEvent(new CustomerRenamedEvent(this.ID, firstName, lastName),
}
}
Custom only has ID attribute because it needs it to add it to every event that it generates. FirstName and LastName are omitted as they are not needed even when ChangeName method is called. It only records an event that this happened. If your logic requires the FirstName then you can add it. You can omit any properties that you don't need.
Your Repository in this case will save only the events and won't care about the values of the attributes of the Customer.
On the Read side you will probably need these properties as you will display them to your users.
If your aggregates are not event sourced, then you probably will need more attributes on your aggregate to implement it's logic and they will be saved to the database.
Here's an example:
class Customer {
public Guid ID { get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
public void ChangeName(firstName, lastName) {
FirstName = firstName;
LastName = lastName;
}
}
In this case your Repository will need these properties as it will generate a query to update the database with the new values.
Not sure what "Customer entity doesn't make sense" means.

Domain object with aggregate fields

I have domain object like this:
class Customer
{
string FirstName {get;set;}
string LastName {get;set;}
DateTime DateOfBirth {get;set;}
}
Product team told me: We have to get customer by ID. Customer has information like FirstName, LastName, DateOfBirth, Age and blank fields. Age and blank fields can be calculated.
There is no application, just API. Who consumes this API doesn't matter.
Q: If I follow Domain Driven Design how domain class Customer looks? Where I put fields like Age and list of blank fields (for every Customer)? How business logic class looks like?
I think you have an anaemic model going here. The age should be implemented completely in the Customer class. So that to access the value, you do, customer.age. The blankfields might be a concept that needs it's own entity/domain, because a "Customer" cannot have a "blankfield"; the language doesn't fit/make sense. If you need the "blank fields" to exist as part of a customer object though, consider using a value object inside the customer object as well.
You don't need the service doing all that you have it doing. The only reason the service might be involved in this is if there's no way you can have your entity doing the work because of an external dependency or possibly complexity.
So, your service constructs your database from your persisted data and that's the end of it's involvement. In fact, you should probably be using a repository for re-constituting your object (instead of a service).

DDD class design dilemma with Value Objects with DB id and Entities

This is a long question so i am gonna go straight to the point. This is pseudo code for better illustration of the problem
DB Structure
User (UserID, Name, LastName)
Address(AddressID, UserID, Street, City, State, ZipCode) =>Many to One User relationship
Phone (PhoneID, UserID, Number, IsPrimary) =>Many to One User relationship
Domain Classes
class User:IEntity
{
public string Name {get;set;}
public string LastName {get;set;}
public ContactInfo{get;set;}
}
class Phone: IValueObject or IEntity? will see later.
{
public int id; // persistence ID, not domain ID
public string Number {get;set;}
}
class Address: IValueObject or IEntity? will see later.
{
public string Line1 {get;set;}
public string City {get;set;}
public string State {get;set;}
public string ZipCode {get;set;}
}
class ContactInfo: IValueObject or IEntity? will see later.
{
List<Address> Addresses {get;set;}
List<Phone> PhoneNumbers {get;set;}
}
So, so far we have a very basic representation of this domain and its models.
My question is the following. Let's say that i want to Update one of the addreses or fix the area code for one of the numbers because of misspelling wnen it was initially typed in.
If i follow Evan's bible about DDD, Value Objects should be immutable. Meaning, no changes to its properties or fields after it was created.
If that's the case, then i guess, none of my classes are a ValueObject, since i can't just recreate the whole ContactInfo class just because one portion of the string in the phone number is wrong. So, i guess that makes all my classes Entities?
Keep in mind that i have a "persistence id" for each of this classes since they are stored in a database.
Let's say that i decide to make Phone a value object, since it's easy to recreate in the constructor
public Phone(string newNumber)
so, it would be something like adding a method to User (agg root) AND contactinfo? (Demeter Law)
like...
User....
public void UpdatePrimaryPhoneNumber(string number)
{
this.ContactInfo.UpdatePrimaryPhoneNumber(number);
}
ContactInfo....
public void UpdatePrimaryPhoneNumber(string number)
{
var oldPhone = Phones.Where(p=>p.IsPrimary).Single();
var newPhone = new Phone(number, oldPhone.persistenceid???-> this is not part of the domain)
oldPhone = newPhone;
}
but i still have to deal with persistence id... grrrrr. what a headache.
Sometimes i feel when i read those blogs that most "ddd experts" that value objects are overused or i would say misused.
What would be the best solution to this scenario?
Thank you
If i follow Evan's bible about DDD, Value Objects should be immutable.
Meaning, no changes to its properties or fields after it was created.
If that's the case, then i guess, none of my classes are a
ValueObject, since i can't just recreate the whole ContactInfo class
just because one portion of the string in the phone number is wrong.
So, i guess that makes all my classes Entities?
While the VO itself may be immutable, a VO doesn't exist on its own - it is always part of an aggregate. Therefore, a VO can be immutable, but the object which references that VO doesn't have to be. What helped me understand VOs is to compare them to something like a primitive Int32 value. The value of each individual integer is immutable - a 5 is always a 5. But anywhere you have an Int32 you can set another value there.
For you domain, what that means is that you can have an immutable address VO, but a given use entity can reference any instance of an address VO. This is what will allow corrections and any other changes to be made. You don't change the individual fields on the address VO - you replace it with a whole new VO instance.
Next, "Persistence ids" shouldn't be expressed in anywhere in domain code. They exist solely to satisfy the needs of the relational databases and NoSQL databases don't require them at all.
The primary phone scenario should look more like this:
public void UpdatePrimaryPhoneNumber(string number)
{
var existingPrimaryNumber = this.Phones.FirstOrDefault(x => x.IsPrimary == true);
if (existingPrimaryNumber != null)
this.Phones.Remove(existingPrimaryNumber);
this.Phones.Add(new Phone(phoneNumber: number, isPrimary = true));
}
This method encapsulates the idea of updating an existing primary phone number. The fact that phone number VOs are immutable means that you have to remove an existing value and replace it with a new one. What usually happens on the database end, especially with ORMs like NHibernate, is it will issue a SQL delete and a subsequent insert to effectively replace all phone numbers. This is OK since the ID of the VOs doesn't matter.
An Entity has a rather unique and individual life-cycle. It has meaning when it stands alone.
The classic example of Order/OrderItem may help with this.
If an OrderItem becomes an Entity it would have a life-cycle of its own. However, this doesn't make too much sense since it is part of an Order. This always seems obvious when looking at an order but less so when looking at your own classes because there can be some references between classes. For instance, an OrderItem represents some Product that we are selling. A Product has a life-cycle of its own. We can have an independent list of Products. How we model the link between an OrderItem and the Product is probably another discussion but I would denormalize the Product data I require into the OrderItem and store the original Product.Id also.
So is the Address class an Entity or a Value Object? This is always an interesting one in that we have that favourite of answers: it depends.
It will be context-specific. But ask yourself whether you have (or need) an independent list of Addresss and then only have a need for the link to that Address in your User. If this is the case then it is an Entity. If, however, your Address makes sense only when it is part of your User then it is a Value Object.
The fact that a Value Object is immutable does not mean you need to replace more than just the specific Value Object. I don't know if I would have a ContactInfo class in your current design since it only wraps the two collections (Address/PhoneNumber) but I would keep it if there is more to it (probably is). So simply replace the relevant PhoneNumber. If you have something like primary/secondary then it is as simple as:
AR.ReplacePrimaryPhoneNumber(new PhoneNumber('...'))
If it is a list of arbitrary numbers then a Remove/Add would be appropriate.
Now for the persistence Id. You do not need one. When you have a primary/secondary scenario you know what your use case is and you can execute the relevant queries in your DB (to update the primary PhoneNumber, for instance). If you have an arbitrary list you may go for add all new numbers in my list and delete those numbers from the DB not in my list; else just delete all the numbers and add everything you have. If this seems like a lot of heavy movement: it is. Event sourcing would move a lot of this to in-memory processing and it is something I will be pushing for seriously going forward.
I hope this all makes sense. Getting away from focusing on the data side of things is rather difficult but necessary. Focus on the domain as though you have no database. When you find friction then do your utmost to not pull database thinking into your domain but try to think about ways you could keep your domain clean and still use your DB of choice.
I would create a class PhoneNumber which contains the String number of the current Phone class and use that as a Value object within your Phone class:
class Phone implements IEntity
{
public int id; // persistence ID, not domain ID
public PhoneNumber number {get;set;}
}
class PhoneNumber implements IValueObject
{
public String number {get;set;};
}
Later when your code evolves you will need (for example) phone number validation and you can put it in the PhoneNumber class. This class can then be reused over the whole application at different places.
The Address is in my opinion a Value object which you can treat like a whole. Although you could model Street, City, etc... which are normally entities, but this is probably over-modelling. No part of the address can change, the whole object is always replaced when changing after initial creation.
The User class is within this example with these boundaries an Aggregate root (and thus also an Entity).
The ContactInfo class is not a ValueObject (not immutable) and not an Entity (no real identity) but an Aggregate. It contains multiple classes which should be seen as a whole.
More info on http://martinfowler.com/bliki/DDD_Aggregate.html
Usually whenever a persistence id is there you should be thinking of an Entity.
If however you would want to add the persistence id's, I would start splitting like the Phone and PhoneNumber class. For example Address (Entity containing id) and AddressValue containing all the other fields (and logic about address values).
This should also solve the headache about managing the persistence identities, since you replace the whole value object and the persistence identity stays the same in case of the updatePrimaryPhoneNumber.

many to many relationship in ddd

I have two entities Publisher and SocialAccount. SocialAccount contains multiple accounts like
Twitter, Facebook, etc.
1 publisher can attach to many social accounts and 1 social account contains multiple publishers, this social account is also connected with another entity's campaign. I mean both are an independent entities
When creating a publisher instance it is not necessary that it should subscribe to a social account, it can subscribe to it at a later stage.
I need to subscribe publisher to 1 or multiple social accounts. how do I do that
How can I convert m to m relationship into 1 to many relationship, between publisher and social account? I am not sure because I read in many places that we should avoid M to M relationship between entities.
Let me expand on Don's answer, as I think he is leading you on the right track.
M-to-N relationships are natural, useful, and can be handled in DDD. If you require an M-to-N relationship, you don't need to try and convert it to an (or more likely multiple) M-to-1 relationship(s). Udi Dahan's acticle gives a nice example of how to handle an M-to-N relationship between entities.
First, determine which entity should contain a list of IDs of the other. Udi uses the example of job postings (Job) and job posting boards (JobBoard). Since a job can exist without a job board and a job board cannot exist without jobs, JobBoard is chosen as the aggregate root and will contain a List<Job>. This might seem like an M-to-1 relationship, but, as each Job can be in the list for multiple JobBoards, it is really M-to-N.
In your case of SocialAccount and Publisher, I recommend something like this in C#:
public class Publisher
{
public int ID {get; private set;}
private readonly IList<int> _AssignedSocialAccounts = new List<int>();
public IEnumerable<int> AssignedSocialAccounts { get { return this._AssignedSocialAccounts; } }
public Publisher(int ID) //Pass required fields to the constructor.
{
this.ID = ID;
}
public AssignSocialAccount(int SocialAccountID)
{
if(!this._AssignedSocialAccounts.Contains(SocialAccountID))
this._AssignedSocialAccounts.Add(SocialAccountID);
}
}
public class SocialAccount
{
public int ID {get; private set;}
public SocialAccount(int ID) //Pass required fields to the constructor.
{
this.ID = ID;
}
}
(This example uses domain encapsulation similar to Jimmy Bogard's Wicked Domain Models.)
Note that I chose Publisher to be the aggregate root since a SocialAccount can exist on its own, but a Publisher has no meaning without the existence of a SocialAccount.
Also note that I am passing around unique IDs, not references to the objects themselves. This is a common approach in DDD and allows for the lazy loading of related entities, although the tradeoff is you have to call the repository to get the entities when you want to access them.
This approach also means that you do not have all SocialAccounts as a single enumeration. They are split up between the various Publishers. To get a list of all SocialAccounts will require a separate query.

Resources