Search code examples
c#asp.net-mvcentity-frameworkef-code-firstscaffolding

How to model this entity


I am creating an application for a shop, where clients are divided into two groups: receivers and payers.

1) Many receivers can be related to one same payer. 2) Payer can be receiver itself, thus he is related to one receiver only

My code so far look like this:

public class Receiver
{
    [Key]
    public int ReceiverId { get; set; }
    public string Name { get; set; }
    [Required]
    public int PayerId { get; set; }
    public virtual Payer Payer { get; set; }
}

public class Payer
{
    [Key]
    public int PayerId { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Receiver> Receivers { get; set; }
}

However I need to let the user create a new payer that is also a receiver at the same time, so the Receivers collection will have only one element. To do this I want to use a checkbox, which will be translated to a new column in the database (IsAlsoReceiver).

I am using MVC scaffolding for creating views, and it created two views for adding Receiver and another for adding Payer. When a user needs a Payer that is also a receiver he has to add entities in both views; can that be simplified in this scenario?

I am asking for a smart way to do so.


Solution

  • I think you are missing an abstraction layer. When you build a project of a certain size (a size of which I think you have reached) you need each component (data layer, logic layer and views) to see different models.

    The Data Access Layer (DAL) has Domain Models

    The Logic Layer or API has Data Transfer Objects

    The Views have View Models

    To make it easy to build and to understand I'm just using Domain Models and View Models.

    For your current problem I would build it like so:

    //this is the view model
    //The user sees this model
    public class Person {
        public string Name { get; set; }
        public bool IsReceiver { get; set; }
        public bool IsPayer { get; set; }
    }
    //these are the domain models
    //The database uses these models
    public class Receiver {
        [Key]
        public int ReceiverId { get; set; }
        public string Name { get; set; }
        [Required]
        public int PayerId { get; set; }
        public virtual Payer Payer { get; set; }
    }
    public class Payer {
        [Key]
        public int PayerId { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Receiver> Receivers { get; set; }
    }
    
    public class AccountController {
    
        //create a view for the Person View Model
        //this is your abstraction
        public void SignUp(Person p) {
            //create models for the repository
            Payer payer = new Payer() {
                Name = p.Name
            };
            Receiver receiver = new Reciever() {
                Name = p.Name
            };
    
            //if the payer is his own receiver:
            Receiver.Payer = payer;
    
            //if the payer is his own receiver:
            Payer.Receivers.Add(receiver);
    
    
            //create for each depending upon some condition
            //I've just allowed the user to select whether he is a payer
            //based upon a checkbox on the form I suppose
            if (p.IsPayer) {
                db.Payers.Add(payer);
            }
            if (p.IsReceiver) {
                db.Receivers.Add(receiver);
            }
    
            db.SaveChanges();
        }
    }