michasaucer
michasaucer

Reputation: 5228

Entity Framework Core model with abstract class

I have a question

I make a Code First Database In ASP .NET Core 2.1 and Entity Framework 2.1.1. For now, im in a planning step and i have one question. I want to have a list of instance of abstract worker's class with method, that will work difrently. My code:

I have a Farm:

public class Farm
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual List<Farmer> Farmers { get; set; } //my problem
        public virtual List<Driver> Drivers { get; set; } //starts here!
    }

In Farm instance i have Workers. I made an abstract class for it:

public abstract class Worker
{
    [Key]
    public int Id { get; set; }

    [ForeignKey("Farm")]
    public int FarmId { get; set; }
    public Farm Farm { get; set; }

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public float UsdPerHour { get; set; }
    public int HoursPerDay { get; set; }
    public int DaysOfWork { get; set; }

    public abstract float CountSalary();
}

Worker can be a Driver or a Farmer:

public class Farmer : Worker
{
    public float UsdPerHour = 9;
    public int HoursPerDay = 8;
    public int DaysOfWork = 20; 
    // CountSalary() here, but in diffrent way!
}

public class Driver : Worker
{
    public float UsdPerHour = 10;
    public int HoursPerDay = 7;
    public int DaysOfWork = 18;
    // CountSalary() here, but in diffrent way!
}

And my FarmDbContext:

public class FarmDbContext : DbContext
{
    public FarmDbContext(DbContextOptions<FarmDbContext> options) : base(options) { }

    public DbSet<Farm> Farms { get; set; }
    //public DbSet<Worker> Workers { get; set; }
    public DbSet<Farmer> Farmers { get; set; } // What to do here?
    public DbSet<Driver> Drivers { get; set; } // Let Farmers and Drivers
                                               // Or Workers?
}

In My farm i have two kinds of workers. For each "Position" i want to count salary in diffrent way.

What i want to do in code:

var Workers = List<Worker>
Workers.Add(New Driver());
Workers.Add(new Farmer()): 

foreach(object o in Workers)
   int salary = o.CountSalary()

// i know that code is wrong, but i describe the way that i want to achive my goal

Could you explain me, how to plan my DbContext to achive, what i want to? Farmer and Driver need to have hard-coded values of propertys. When i let DbContext like above in my code, i get two tables, dbo.Drivers and dbo.Farmers. If it will work in a way that i explained above? Is it possible in EF to block that hardcoded value in database and have it in every record of data i tables?

Upvotes: 0

Views: 3581

Answers (1)

Sasan
Sasan

Reputation: 4220

Your Farmer and Driver classes have no new properties, just some constants for calculations. That is not the Model/Database layer's concern, it's the Services layer job.

My Suggestion:

public enum WorkerType
{
  Farmer,
  Driver
}

Worker Class:

public class Worker
{
  [Key]
  public int Id { get; set; }

  [ForeignKey("Farm")]
  public int FarmId { get; set; }
  public Farm Farm { get; set; }

  public string FirstName { get; set; }
  public string LastName { get; set; }
  public WorkerType WorkerType {get; set; } // assuming a worker can only be a Farmer or a Driver
}

DbContext:

public class FarmDbContext : DbContext
{
    public FarmDbContext(DbContextOptions<FarmDbContext> options) : base(options) { }

    public DbSet<Farm> Farms { get; set; }
    public DbSet<Worker> Workers { get; set; }
}

And then you can have a service or extension method that calculates the salary, for example:

public static class WorkerExtensions
{
  public static float Salary(this Worker worker)
  {
    switch(worker.WorkerType)
    {
      case WorkerType.Farmer:
        //calculate and return

      case WorkerType.Driver:
        //calculate and return

      default:
        return -1;
    }
  }
}

Now you can get workers salary:

foreach(var worker in Workers)
   var salary = worker.Salary();

The problem here is that every time your calculation constants change you need to change code and rebuild/republish. For that you can create a wage info table in your database and get those informations from there, and you can change them whenever you want.

Upvotes: 1

Related Questions