Accept Interface into Collection (Covariance) troubles with nHibernate

后端 未结 1 970
鱼传尺愫
鱼传尺愫 2021-01-28 23:12

I am using Fluent nHibernate for my persistence layer in an ASP.NET MVC application, and I have come across a bit of a quandry.

I have a situation where I n

1条回答
  •  孤独总比滥情好
    2021-01-28 23:34

    Take a look at the chapter Inheritance mapping in the reference documentation. In the chapter Limitations you can see what's possible with which mapping strategy.

    You've chose one of the "table per concrete class" strategies, as far as I can see. You may need with inverse=true or to map it.

    If you want to avoid this, you need to map IRequirement as a base class into a table, then it is possible to have foreign keys to that table. Doing so you turn it into a "table per class-hierarchy" or "table per subclass" mapping. This is of course not possible if another base class is already mapped. E.g. SomeKindOfObject.


    Edit: some more information about with inverse=true and .

    When you use , the foreign key is actually in the requirement tables pointing back to the Item. This works well so far, NH unions all the requirement tables to find all the items in the list. Inverse is required because it forces you to have a reference from the requirement to the Item, which is used by NH to build the foreign key.

    is even more flexible. It stores the list in an additional link table. This table has three columns:

    • the foreign key to the Item,
    • the name of the actual requirement type (.NET type or entity name)
    • and the primary key of the requirement (which can't be a foreign key, because it could point to different tables).

    When NH reads this table, it knows from the type information (and the corresponding requirement mapping) in which other tables the requirements are. This is how any-types work.

    That it is actually a many-to-many relation shouldn't bother you, it only means that it stores the relation in an additional table which is technically able to link a requirement to more then one item.


    Edit 2: freaky results:

    You mapped 3 tables: IRequirement, ObjectThatImplementsRequirement, AnotherObjectThatHasRequirement. They are all completely independent. You are still on "table per concrete class with implicit polymorphism". You just added another table with containing IRequirements, which may also result in some ambiguity when NH tries to find the correct table.

    Of course you get 1, 1 as result. The have independent tables and therefore independent ids which both start with 1.

    The part that works: NHibernate is able to find all the objects implementing an interface in the whole database when you query for it. Try session.CreateQuery("from object") and you get the whole database.

    The part that doesn't work: On the other side, you can't get an object just by id and interface or object. So session.Get(1) doesn't work, because there are many objects with id 1. The same problem is with the list. And there are some more problems there, for instance the fact that with implicit polymorphism, there is no foreign key specified which points from every type implementing IRequirement to the Item.

    The any types: This is where the any type mapping comes in. Any types are stored with additional type information in the database and that's done by the mapping which stores the foreign key and type information in an additional table. With this additional type information NH is able to find the table where the record is stored in.

    The freaky results: Consider that NH needs to find both ways, from the object to a single table and from the record to a single class. So be careful when mapping both the interface and the concrete classes independently. It could happen that NH uses one or the other table depending on which way you access the data. This may have been the cause or your freaky results.

    The other solution: Using any of the other inheritance mapping strategies, you define a single table where NH can start reading and finding the type.

    The Id Scope: If you are using Int32 as id, you can create 1 record each second for 68 years until you run out of ids. If this is not enough, just switch to long, you'll get ... probably more then the database is able to store in the next few thousand years...

    0 讨论(0)
    提交回复
    热议问题