Nested Properties with Inheritance - entity-framework

Online shop I am working on has entity Order that has member DeliveryDetails.
The purpose of DeliveryDetails is to contain data which is specific to delivery method selected by user (e.g. Shipping or Pick Up From Store), while some details are common for all methods (e.g. Firstname, Lastname, PhoneNumber). I was thinking about structure similar to the following using inheritance:
public class Order {
// ....other props...
public DeliveryMethodType DeliveryMethodType { get; set; }
public DeliveryDetailsBase DeliveryDetails { get; set; }
}
public class DeliveryDetailsBase
{
public int Id { get; set; }
public string CustomerId { get; set; }
public Order Order { get; set; }
public int OrderId { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string PhoneNumber { get; set; }
}
public class DeliveryDetailsShipping : DeliveryDetailsBase
{
public string Street { get; set; }
public string Building { get; set; }
public string Appartment { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public class DeliveryDetailsPickupFromStore : DeliveryDetailsBase
{
public string StoreCode { get; set; }
}
However, I can't figure out how to make DeliveryDetails prop be assigned to different type of delivery method details depending on what method customer selected and how to fit it in EntityFramework on ASP.Core.
Workarounds I have already tried:
-> (1). Creating "super class" contatining props for ALL delivery methods and populate in db only those that are needed for selected delivery method (selection via setting enum DeliveryMethodType). OUTCOME: works, but with 1 big and ugly table featuring multiple nulls.
-> (2). In Order, creating prop DeliveryDetails which in turn embraces DeliveryDetailsPickupFromStoreDATA & DeliveryDetailsShippingDATA. OUTCOME: works, but with several related tables and quite a lot of ugly code checking selected type from enum, instantiating specific subclass for chosen delivery method and setting to null other unused subclasses.
TO SUM UP: Is there any more elegant and feasible way to organize this?

Is there any more elegant and feasible way to organize this?
Keep it simple, and inheritance isn't usually simple. :)
As a general rule I opt for composition over inheritance. It's easier to work with. Given an order that needs to be delivered to an address or to a store:
public class Order
{
public DeliveryMethod DeliveryMethod { get; set; } = DeliveryMethod.None;
public virtual OrderDeliveryAddress { get; set; } // should never be null.
public virtual OrderDeliveryStore { get; set; } // not null if delivery mode = store.
}
public class Address
{
public string Street { get; set; }
public string Building { get; set; }
public string Appartment { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
public class OrderDeliveryAddress
{
public virtual Order Order { get; set; }
public virtual Address Address { get; set; }
}
public class Store
{
public int StoreId { get; set; }
public virtual Address { get; set; }
}
public class OrderDeliveryStore
{
public virtual Order Order { get; set; }
public virtual Store Store { get; set; }
}
Where DeliveryMethod is an Enum. { None = 0, ToAddress, ToStore }
When an order is placed the operator can choose to deliver it to an address, selecting the address of the customer, or entering a new address record; or they can deliver it to a store which can also set the OrderDeliveryAddress to the address of the store. You can establish checks in the database/system to ensure that the data integrity for the delivery method and referenced OrderDeliveryAddress/OrderDeliveryStore are in sync and raise any mismatches that might appear.
One consideration would be that when it comes to deliveries, you will probably want to clone a new Address record based on the customer address, or store address as applicable at the time of ordering rather than referencing their current address record by ID. The reason would be for historical integrity. An order will have been delivered to the address at that point in time, and if a customer address or store address changes in the future, past orders should still show the address that order was delivered.

EF Core has only implemented Table Per Hierarchy (TPH) inheritance.
Table Per Type (TPT) is still an open ticket (not implemented).
Table Per Concrete Type (TPC) is also still an open ticket (not implemented).
So, if TPH meets your requirements, you can follow this guide.
Basically, one table will be used and an extra column called Discriminator will be used to determine which implementation the record corresponds to.
If you are just getting started with Entity, my recommendation would be to not use inheritance and just use nullable columns for data that may or may not be needed depending on the type.

Related

How can I restrict the column to accept only value equal to First or Second column using EF core?

I have a table with that contain HostId, GuestId, and WinnerId column.
I want to restrict the WinnderId column to accept the value from HostId and GuestId column.
How can I achive this using Fluent Api or Attributes.
public class Game
{
public long Id { get; set; }
[Required]
public long TournamentId { get; set; }
public Tournament Tournament { get; set; }
public long HostId { get; set; }
public long GuestId { get; set; }
public loong WinnerId{ get; set; }
}
From a data integrity perspective anything you do will not be enforceable. Host, Guest, and Winner would have FKs back to a User/Client or whatever table but nothing would enforce that the Client reference to winner would have to match the Host or Guest. (I.e. nothing would stop the data from changing a Host or Guest ID after assigning a Winner, etc.)
Two options:
1- Change the data structure slightly:
public enum Winner
{
None = 0,
Host,
Guest
}
public class Game
{
public long Id { get; set; }
[Required]
public long TournamentId { get; set; }
public Tournament Tournament { get; set; }
public long HostId { get; set; }
public long GuestId { get; set; }
public Winner Winner { get; set; } = Winner.None;
}
This way you can assign a game with a Host and Guest then to assign the winner you just nominate and store a value indicating whether the host or guest won.
2- Use a more DDD approach to making updates:
public class Game
{
public long Id { get; set; }
[Required]
public long TournamentId { get; set; }
public Tournament Tournament { get; set; }
public long HostId { get; internal set; }
public long GuestId { get; internal set; }
public long WinnerId { get; internal set; }
public void AssignWinner(long winnerId)
{
if(winnerId != HostId && winnerId != GuestId)
throw new ArgumentException("The winner was not the host or guest.");
WinnerId = winnerId;
}
}
This could be done a number of ways, either passing the ID, or passing an enumeration like the first example and assigning the WinnerId based on the Host or Guest ID. Basically use deliberate actions on the domain to perform updates. This is a common approach to help ensure that updates to entities/data are always validated and "complete" when made rather than allowing updates piecemeal through property setters. This still doesn't protect the schema from allowing a WinnerID to point at something other than the Host or Guest, where-as the first structure change does.
If your database supports table constraints, you can add a constraint specifying WinnerId Is Null Or WinnerId = HostId Or WinnerId = GuestId. If your entity class inherits from IValidatableObject you can implement the same rule in the Validate method.

Advanced TPH Mapping to Legacy Database

I have been working on a project in which I am trying to mold entity framework to an existing FoxPro 2.x database in order to use the data while leaving the tables readable to a legacy application (more details on my previous question).
I've had pretty good luck configuring the DBContext to the physical data tables and I have most of my mapping set up. The legacy data structure has a Bills table with a unique primary Id key, but all the LineItems that can be posted to a bill are stored in a single Charges table without a simple primary key.
My question pertains to discriminator mapping in code-first EF. I am recreating the table as TPH in my data objects, so I have
public abstract class Posting
{
public System.DateTime? Post_Date { get; set; }
public string Bill_Num { get; set; }
public string Type { get; set; }
public string Pcode { get; set; }
public string Pdesc { get; set; }
public decimal? Custid { get; set; }
public string Createby { get; set; }
public System.DateTime? Createdt { get; set; }
public string Createtm { get; set; }
public string Modifyby { get; set; }
public System.DateTime? Modifydt { get; set; }
public string Modifytm { get; set; }
public string Linenote { get; set; }
public decimal? Version { get; set; }
public string Id { get; set; }
public string Batch { get; set; }
public virtual Billing Bill { get; set; }
}
public abstract class Charge : Posting
{
}
public class ServiceLine : Charge
{
public string Chargeid { get; set; }
public virtual ICollection<Payment> Payments { get; set; }
}
public class ChargeVoid : Charge
{
}
public abstract class Payment : Posting
{
}
public class PaymentLine : Payment
{
public string Postid { get; set; }
public string Svc_Code { get; set; }
public string Name { get; set; }
public string Checkno { get; set; }
public System.DateTime? Checkdate { get; set; }
}
public class PaymentVoid : Payment
{
}
where my mapping strategy so far is along these lines:
public class PostingMap : EntityTypeConfiguration<Posting>
{
public PostingMap()
{
// Primary Key
this.HasKey(t => new {t.Bill_Num, t.Post_Date, t.Pcode});
this.Map<Charge>(m => m.Requires("Type").HasValue("C"))
.ToTable("Charges");
this.Map<Payment>(m => m.Requires("Type").HasValue("P"))
.ToTable("Charges");
}
}
I have omitted some fields and mapping classes, but this is the core of it.
Every record has the C/P classification, so this makes everything in the table either a Charge or a Payment.
Every Posting is associated with a Bill via Bill_Num foreign key.
The ServiceLine object is only distinct from ChargeVoid objects (which are adjustment entries and no-value information entries associated with a bill) by having values for Pcode and Chargeid (which is just Bill_Num tagged with 01++). I have no idea how to model this.
It is very similar for the Payment hierarchy as well.
So with my current setup, I have Postings which doesn't have a unique key, Charges which has a subset of ServiceLines with values for Chargeid and Pcode and a subset with nulls, and Payments similar to Charges. PaymentLines are also many-to-one with ServiceLines by way of Pcode while PaymentVoids have Pcode = null.
Is there a way I can assign this complex mapping since I can't simply discriminate on !null? On top of that, will EF handle the key assignments once I get the inheritance set up, or am I going to have issues there as well?
Also, if there is a better way to break this object inheritance down, I am all ears.

what is the advantages of nested classes if not getting a collection of them?

I have seen some examples that go like this:
public class Customer
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
And I can't still figure out what advantages has over the following:
public class Customer
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Street { get; set; }
public string City { get; set; }
}
Any ideas about it?
Cheers.
Your class is not nested, it just uses composition. Composition is composing a class from one or more other classes. It's advantage is reuse of course.
You can use your Address class in another class or method and you also encapsulate all the logic and data that must be in the Address class.
If you want nested classes then you can write it as:
public class Apple
{
public int Mass;
public Worm MyWorm;
public class Worm
{
public string Name;
}
}
The example you showed is not a nested class, but a property making use of another class through composition.
The main advantage in your example is that the Address is a separate
entity (refactored out) and may be used to indicate different classifications of
address for a given Customer e.g a Customer may have a Home
Address, a Business Address and a Corporate Address which all
will be of type Address class.
Achieving above type of classification without having a separate Address class would be difficult otherwise and that's the one reason Address is taken out as a separate class.
As an illustration, your Customer class can be modified as below to show one of the advantages:
public class Customer
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Address HomeAddress { get; set; }
public Address BusinessAddress { get; set; }
public Address CorporateAddress { get; set; }
}
Now, as per above example if your Address entity later requires ZipCode also, then you don't need to add 3 zipcodes (1 for Home, 1 for Business and 1 for Corporate); you just add the ZipCode property to the Address class and the 3 properties in Customer class make use of the new property without modifying the Customer class.

EF 5 Code First using Inheritence in the class

I am getting Error when trying to run this code.
Unable to determine the principal end of an association between the
types 'AddressBook.DAL.Models.User' and 'AddressBook.DAL.Models.User'.
The principal end of this association must be explicitly configured
using either the relationship fluent API or data annotations.
The objective is that i am creating baseClass that has commonfield for all the tables.
IF i don't use base class everything works fine.
namespace AddressBook.DAL.Models
{
public class BaseTable
{
[Required]
public DateTime DateCreated { get; set; }
[Required]
public DateTime DateLastUpdatedOn { get; set; }
[Required]
public virtual int CreatedByUserId { get; set; }
[ForeignKey("CreatedByUserId")]
public virtual User CreatedByUser { get; set; }
[Required]
public virtual int UpdatedByUserId { get; set; }
[ForeignKey("UpdatedByUserId")]
public virtual User UpdatedByUser { get; set; }
[Required]
public RowStatus RowStatus { get; set; }
}
public enum RowStatus
{
NewlyCreated,
Modified,
Deleted
}
}
namespace AddressBook.DAL.Models
{
public class User : BaseTable
{
[Key]
public int UserID { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string Password { get; set; }
}
}
You need to provide mapping information to EF. The following article describes code-first strategies for different EF entity inheritance models (table-per-type, table-per-hierarchy, etc.). Not all the scenarios are directly what you are doing here, but pay attention to the mapping code because that's what you need to consider (and it's good info in case you want to use inheritance for other scenarios). Note that inheritance does have limitations and costs when it comes to ORMs, particularly with polymorphic associations (which makes the TPC scenario somewhat difficult to manage). http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx
The other way EF can handle this kind of scenario is by aggregating a complex type into a "fake" compositional relationship. In other words, even though your audit fields are part of some transactional entity table, you can split them out into a common complex type which can be associated to any other entity that contains those same fields. The difference here is that you'd actually be encapsulting those fields into another type. So for example, if you moved your audit fields into an "Audit" complext type, you would have something like:
User.Audit.DateCreated
instead of
User.DateCreated
In any case, you still need to provide the appropriate mapping information.
This article here explains how to do this: http://weblogs.asp.net/manavi/archive/2010/12/11/entity-association-mapping-with-code-first-part-1-one-to-one-associations.aspx

DBContext simplest way to update foreign key

var orgAcc = db_.Accounts.Find(account.Id);
db_.Entry(orgAcc).CurrentValues.SetValues(account);
orgAcc.Company = db_.Companys.Find(account.Company.Id);
db_.SaveChanges();
Is this the simplest way to update an entity's association ?
public class ChartofAccount: MasterData
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(6)]
public string Code { get; set; }
public virtual Company Company { get; set; }
[Required]
public string AccountName { get; set; }
[Required]
[StringLength(3)]
public string AccountCurrency { get; set; }
public virtual AccountCatagory Category1 { get; set; }
public virtual AccountCatagory Category2 { get; set; }
public string Reference { get; set; }
public bool HasTransaction { get; set; }
}
The way SetValues works is to do a property-by-property compare, and for each property from the left-hand object that is also in the argument, that has a matching type, it will update the left-hand object with the value from the argument.
I presume account.Company is a different type of object to orgAcc.Company, such as something that has come in from an MVC controller argument (ie account and it's referenced objects are not EF entities). In this case your approach seems a sound way of doing it.
That being said, orgAcc probably has a Company property, and a CompanyId property, in order to support the EF relationships, so, if your account object followed the same pattern, ie storing a CompanyId field directly, rather than having to navigate through the company, then SetValues could automatically update the CompanyId field, which should update the foreign key when you save changes. This way you could also avoid the step that specifically assigns the orgAcc.Company field.