Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework inheritance

SQL Layer:

I have a table

enter image description here

Entity Framwork Layer:

I have the following rule: all Offers, which have State is null, are Outstanding offers, State is true are Accepted offers, State is false are Declined offers. Also, part of fields used only for Outstanding, part - only for Accepted etc... I use Database first approach, so, I updated EF model from DB and renamed Offer entity to OfferBase and created 3 child classes:

enter image description here

it works fine for add/select entities/records. Right now I want to "move" offer from outstanding to accept offer, so, I need to set Status=true (from Status is null) for appropriate record. But how to do it by Entity Framework? If I try to select outstanding offer as Accept offer I get an null reference (and clearly why)

// record with ID=1 exists, but State is null, so, EF can not find this record and offer will be null after the following string
var offer = (from i in _db.OfferBases.OfType<EFModels.OfferAccepted>() where i.ID == 1 select i).FirstOrDefault();

if I try to select as OfferBase entity I get the following error:

Unable to cast object of type 'System.Data.Entity.DynamicProxies.OfferOutstanding_9DD3E4A5D716F158C6875FA0EDF5D0E52150A406416D4D641148F9AFE2B5A16A' to type 'VTS.EFModels.OfferAccepted'.

    var offerB = (from i in _db.OfferBases where i.ID == 1 select i).FirstOrDefault();
    var offer = (EFModels.OfferAccepted)offerB;

ADDED NOTES ABOUT ARCHITECTURE:

I have 3 types of Offer entity. There are: AcceptOffer, DeclineOffer and OutstandingOffer.

AcceptOffer:

  • UserID
  • ContactID
  • Notes
  • FirstContactDate
  • LastContactDate
  • [... and 5-10 the unique fields...]

DeclineOffer:

  • UserID
  • ContactID
  • Notes
  • [... and 5-10 the unique fields...]

OutstandingOffer:

  • UserID
  • ContactID
  • FirstContactDate
  • LastContactDate
  • [... and 5-10 the unique fields...]

How to do it correctly? Of course, I can select a record, remove from DB and add new with appropriate state value, but how to do it normally?

like image 754
Oleg Sh Avatar asked Jan 09 '23 18:01

Oleg Sh


1 Answers

You can't change the type of an object once it's created. Your object model seems wrong. Either you delete the outstanding offer and create an accepted offer from it (looks like what you are currently doing) but you may lose relations as you created a new object with a new identity (you can also copy them before removing the old object). Or you want to keep the same object and change its state.

If you want to keep the same identity then preffer composition over inheritance.

Your code could look like this :

public class Offer
{
  public int Id { get; set; }
  public virtual OfferState State { get; set }
}

public class OfferState
{
  public int OfferId { get; set; }
  public string Notes { get; set; }
}

public class AcceptedOfferState : OfferState
{
  public DateTimeOffset AcceptDate { get; set; }
}

public class DeclinedOfferState : OfferState
{
  public DateTimeOffset DeclinedDate { get; set; }
}

If you still want to change the type of the object and keep its identity then you may use stored procedures ; as stated by Noam Ben-Ami (PM owner for EF) : Changing the type of an entity.

like image 191
Guillaume Avatar answered Jan 17 '23 12:01

Guillaume