質問

When working with database modeling tools that are capable of generating code, there are certain relationship types which are (almost?) never supported.

They include 1-to-1, many-to-many, and 0 or 1-to-0 or 1. 1:1, :, and 0..1:0..1.

The first two have easy solutions.

  1. 1-to-1 can be resolved by converting to 0..1-to-1 or 1-to-0..1, 0..1:1 or 1:0..1.

  2. Many-to-many can be resolved by using a table in the middle of the relationship and then either a 1:* and a :1 or a 0..1: and a *:0..1 or some similar combination. I think there are four possible combinations that resolve it.

However, I am stuck on 0..1-to-0..1. In fact, I have such a set of tables that seem to have this logical relationship.

In my case I have four tables. For the sake of argument, suppose they all have primary keys of type INT. The tables are People, Organizations, Customers, and Employees.

A word about the logic. Organizations can have People, they are called Contacts in the relationship. People can be either a Customer or an Employee or both.

Organizations <-> has Contacts <-> as People. This is a 0..1:* relationship. This means that a Person can exist with or without an Organization and that an Organization can have many People (or none).

An Employee must have a Person record, and that relationship also makes sense. It is a 0..1:1 relationship, where an Employee must have a Person, but a Person can have 0 or 1 Employee record.

But this one doesn't make sense because the entity inheritance flows in both directions, logically. In the case of People or Organizations to Customer. A Customer can be either an Organization or a Person, but not both, and the selection is made via a Type flag field. Just the same a Person is not necessarily a Customer, it may be an Employee or some other contact type later on. I can not require a Person to be a Customer and I can not require a Customer be a Person. Just the same I can not require an Organization to be a Customer and I can not require a Customer to be an Organization. So the disconnectedness of the inheritance is also necessary. In the case of both Customer:Person and Customer:Organization, they both need to implement a 0..1:0..1 and 0..1:0..1. But the language tools do not support it. Because they are strongly-typed languages, the entity inheritance can only flow in a single direction. Even in weakly-typed languages, you would still wind up in a situation of which came first: the chicken or the egg.

JavaScript is perhaps well-suited for this case since you can dynamically alter the structure of an object type, and you could always combine the two structures in either order even if you couldn't explicitly declare the object to exist in this manner.

But my tool for today is Microsoft LightSwitch, and it won't do this at all. I don't think a modern modeling tool exists that will and generate strongly-typed language code that will permit this relationship type.

Is there a trick that overcomes this relationship, 0..1:0..1, or is there something fundamental that I have yet to understand? I am left here to pick a side, and I don't know which side is winning: Customer or Person, Customer or Organization. But maybe there is something else I can do without compromising either case. Is there something about the model that is broken?

Thanks!

役に立ちましたか?

解決

The 0..1 model is usually an is-a relation. This maps to Inheritance in C#. In C# you cannot create classes that inherit from multiple other classes (only through interfaces)

Your model is purely modelled as a Relational Database, but it doesn't map to an object structure that doesn't have multiple inheritance. Define a model in C# that works (using inheritance and relations), then generate a Datamodel for it, since in this case C# is the limiting factor.

Remember that you can use Inheritance:

Customer
<--is-a- Corporate Customer --has-a-- Organization --has-many-|
<--is-a- Natural Customer   --has-a-- Person    <--is-a- Employee

In this case you won't be able to cast a Customer directly to a person or an organization, but you can get to the record that is linked to this class, which feels natural to me. But an Employee is always a Person (which makes sense).

If you want to you can inherit both Organization and Person from LegalEntity. Either in the model above (retaining the Natural/Corporate Customer),

Customer<T:LegalEntity> -----------has-a--------------- LegalEntity
 ^                                                              ^  
 |--is-a- Customer<Organization> (--has-a--) Organization -is-a-|  --has-many
 L--is-a- Natural<Person>        (--has-a--) Person -------is-a-|       |
                                               ^                        |
                                               L--is-a- Employee -------|

But you can also simplify the model further in that case:

Customer
  |--has-a LegalEntity <---is-a-- Organization --has-many-|
                         L-is-a-- Person    <--is-a- Employee

Or you can use Person as the basis, but that leads to a more ugly model:

Person
<- Employee ---- Organization  <- Corporate Customer
<- Natural Customer ----|              |
          |                            |
          L------------------------------->> ICustomer

In which case your Person can be either an Employee or a Natural Customer (but not both), plus you can't create a list of Customer that contains both Natural Customer and Corporate Customers, except through Interfaces, but Entity Framework doesn't always understand those. This model feels awkward, but seems closer to your current model.

The full fidelity model you want can't be built using .NET or Entity Framework.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top