简体   繁体   中英

Entity framework + mvc + code first + Inheritance table per Hierarchy, How to use heritage/polymorphism to avoid switch/if

I lack knowledge here, so I need help with this, cause I'm lost in concept I don't understand.
First, let me introduce you the context of the question.


We have equipments that are coming from others applications.
So, we designed a database class equipment.
Each applications will have his own equipment class that inherit base equipment class.
For example, application "AAA" will have his class "AAAEquipment" that inherit of "Equipment". Since, there won't be much applications, we have chosen model "Inheritance table per Hierarchy".

See following link for detail about TPH : http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph


Given an equipment, we need to retrieve detail.
Detail is stored in the foreign application.
No matter which application, the resulted detail has always the same structure.
However, the logic to retrieve the detail differ.
For example, "AAAEquipment" use a web service to so. Another could use something else.

In our web-application controller, when we want the detail for a given equipment, we now have a switch case on TypeOf(Equipment) to call the good webservice.

(based on my very poor knowledge on entity framework, codefirst and design pattern) (基于我对实体框架,代码优先和设计模式的知识非常差)
- Database class must remain "POCO", meaning containing only properties with no logic.
- Database project shouldn't have reference to others projects like web service and others stuffs. Others projects should reference Database project and not the other way around.


How can I use heritage to avoid having IF and SWITCH case in my controller to retrieve detail? What is the point of having concept like TPH if we can't have custom logic for each class of the hierarchy? Shouldn't it be

MyEquipment.GetDetail();

instead of

IF(MyEquipment is AAAEquipment)
{
    Call AAAWebService
}

I think I could get around using "extension methods" for all type of equipment, but I doesn't feel like this is the "Normal" way of handling this. I feel like polymorphisme power is crippled here.

Your help is appreciated, thanks!

If you want to abstract the detail away from your poco one could use dependency inversion. (Please note that although I am using constructor injection here. If you find it difficult with EF you can also use property injection)

public abstract  class Equipment
{
    public abstract Detail GetDetail();
}

public sealed class EquimpmentAA : Equipment
{
    private readonly IGetDetail _getDetail;
    public EquimpmentAA( IGetDetail getDetail)
    {
        _getDetail = getDetail;
    }


    public override Detail GetDetail()
    {
        return _getDetail.Get();
    }
}

public sealed class Detail 
{
   //Details
}

//Different implementations on how each class gets its detail
public interface IGetDetail
{
    Detail Get();
}

You are right that you would probably not want to make your pocos reliant on specific services and so on. This is not just for pocos, but all classes in general you would want your classes to not depend directly on lets say a wcf service. By using the dependency inversion principle it is therefore easy to decouple your code from these implementation details.

Using Dependency Injection would probably be a good decision to inject the different implementations within your code.

Database class must remain "POCO", meaning containing only properties with no logic.

That is not correct. There is nothing about EF that prevents POCO classes from containing other logic. While it is not good style to mix concerns in one object, there is no technical restriction.

A simple solution is to add a method to each subclass of Equipment that implements the detail of retrieving it's own details

abstract class Equipment
{
    public void GetDetail();
}

public class AAAEquipment
{
    public void GetDetail()
    {
        // Appropriate implementation to get details
    }
}

If you desire a more strict separation of concerns, you could provide a separate factory to get details for a properties-only POCO. To avoid the if/switch statements you could have an inheritance hierarchy for the factory that matches your equipment subclasses. You could also use Dependency Injection in place of a factory.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM