Project

General

Profile

Relation Missmatch when following dbo::tutorial7

Added by Christian Meyer almost 2 years ago

Hello =)
Following Tutorial7 to use another type as key results in the following error

Error: Wt::Dbo::id() called for class C with surrogate key: Wt::Dbo::dbo_traits::surrogateIdField() != 0
Relation mismatch for table 'ContactForm-Address':
no matching belongsTo() found in table 'ContactForm-Location' with name 'ContactForm-rel-Address_Location'

Tried with hasOne and hasMany, with no difference in Error...

Is that a Bug or a Feature?

I also tried to set the relation name the same as the table name, with no luck.

Following is the complete Set of Files that are related to the Missbehaving with excerpts of what I deem most important to diagnose if something is wrong.

Thank you

complete Address.h


Important Part in Address.h

Wt::Dbo::collection<Wt::Dbo::ptr<Location>> locationPtr;
// Wt::Dbo::weak_ptr<Location> locationPtr;

complete Address.cpp


Important in Address.cpp

Wt::Dbo::hasMany(a, locationPtr, Wt::Dbo::ManyToOne, "ContactForm-rel-Address_Location");
// Wt::Dbo::hasOne(a, locationPtr, "ContactForm-rel-Address_Location");

complete Location.h


Important in Location.h

Wt::Dbo::ptr<Address> addressPtr;

complete Location.cpp


Important in Location.cpp
traits definition

template <class Action>
void Location::persist(Action &a)
{
try{
Wt::Dbo::id(a, addressPtr, "ContactForm-rel-Address_Location", Wt::Dbo::OnDeleteCascade);
}
catch(std::exception &e)
{
Wt::log("error") << "Location Persist: id error";
std::cerr << e.what();
// >> Error: Wt::Dbo::id() called for class C with surrogate key: Wt::Dbo::dbo_traits::surrogateIdField() != 0
// >> Relation mismatch for table 'ContactForm-Address': 
// >> no matching belongsTo() found in table 'ContactForm-Location' with name 'ContactForm-rel-Address_Location'
}
}

Replies (6)

RE: Relation Missmatch when following dbo::tutorial7 - Added by Christian Meyer almost 2 years ago

I now used the example Code to test different things

a OneToOne Relation works in the examples

the name of the relation can be set to whatever...

I really don't understand why it would not work in my own case

If I try to Log the surrogateIdField in my case

    Wt::log("info") << "Location::surrogateIdField: "
        << Wt::Dbo::dbo_traits<Location>::surrogateIdField() << ";" ;

it throws basic_string::_M_construct null not valid which suggests it should work as intended ...

I also tried to set the versionField to something ridiculous to see if that works and logged it, and it does
in my own and in the examples

This Error shows when Calling id in Persist

Error: Wt::Dbo::id() called for class C with surrogate key: Wt::Dbo::dbo_traits::surrogateIdField() != 0

This Error Shows on createSchema

Relation mismatch for table 'ContactForm-Address':
no matching belongsTo() found in table 'ContactForm-Location' with name 'ContactForm-rel-Address_Location'

What am I missing?

RE: Relation Missmatch when following dbo::tutorial7 - Added by Matthias Van Ceulebroeck almost 2 years ago

Hello Christian,

the surrogateIdField and the Wt::Dbo::id are currently mutually exclusive.
The documentation does note that surrogateIdField is to be used for auto-increment primary keys only.

In case a custom Wt::Dbo::id is defined, the surrogateIdField should be empty (0 or nullptr).


I have tried your example, but this does not compile. It is important that the

struct Wt::Dbo::dbo_traits<ContactForm::Dbo::Location> : public Wt::Dbo::dbo_default_traits

is defined before any other instantiation of Wt::Dbo::ptr<ContactForm::Dbo::Location>. Otherwise this does set the default of id. I suspect this is the case for you, but I do not understand why the compiler doesn't error out on it.

So in short, I would move the dbo_traits struct to the location.h, and ensure that it is compiled before any other definition of Wt::Dbo::ptr<ContactForm::Dbo::Location>.

I hope this helps,
Matthias

RE: Relation Missmatch when following dbo::tutorial7 - Added by Christian Meyer almost 2 years ago

Hello Matthias,

Thank you for taking the time to check
I am aware of the mutually exclusivity, but only run into compiler errors, when the specialization is located in a .h file.

I did try to put the template specialization into Location.h but then I get the same Compiler Error as in (this forum entry)[[https://redmine.emweb.be/boards/2/topics/18347]] so I moved it after a long try and error conquest.

Craziest thing is, when I try to isolate and include the Dbo classes in an example app, it works as expected.
Apparantly this gets messed up in an entirely different area than the DBO defnitions.

On the other hand, if there are other Classes that need specialization, how would I go about that?
How can I guarantee the order of Compilation?

Can I have your compiler errors for reference? Maybe there is an edge case somewhere in there...

Thank you

RE: Relation Missmatch when following dbo::tutorial7 - Added by Matthias Van Ceulebroeck almost 2 years ago

Ah, I do see that I did one thing slightly differently, and that is adding DBO_EXTERN_TEMPLATES(ContactForm::Dbo::Location) at the bottom of the location.h header. If I remove that, this WILL compile.

That is because the macro DBO_EXTERN_TEMPLATES will perform:

extern template class Wt::Dbo::ptr<C>;
extern template class Wt::Dbo::Dbo<C>;

Which generates the blocking default for the surrogateIdField.

My apologies, I put it there as a force of habit.
I also would not advise that you go counter this flow, since it defines as early as possible that the class will be a Dbo class. So I do believe that declaring it in the headers is the safest way around this.

My location.h now looks like this:

location.h

If I move the dbo_traits definition to the implementation, it will compile without the macro, but this leads to another issue. If I ask typeid(location.id()).name() where location is an instance of ContactForm::Dbo::Location, it returns x. Whereas it should return a (garbled) form of Wt::Dbo::ptr<ContactForm::Dbo::Address> (N2Wt3Dbo3ptrIN11ContactForm3Dbo7AddressEEE in my case). As such, I would not move this to the implementation.

On the other hand, if there are other Classes that need specialization, how would I go about that?
How can I guarantee the order of Compilation?

The order of compilation is not really something you should try to change (except for very large projects). Rather, try to observe the forward declaration pattern as much as possible. If you ensure that headers are very clean, and not link to each other, to avoid classes being declared earlier than you would expect them to be.

Can I have your compiler errors for reference

Here is the relevant part, but as I said above, I doubt there's an edge case, rather I included a macro out of habit you didn't.

/home/matthias/Documents/wt-support/forum/18360/location.cpp:9:12: error: specialization of Wt::Dbo::dbo_traits<ContactForm::Dbo::Location> after instantiation
    9 |     struct dbo_traits<ContactForm::Dbo::Location> : public dbo_default_traits
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/matthias/Documents/wt-support/forum/18360/location.cpp:9:12: error: redefinition of struct Wt::Dbo::dbo_traits<ContactForm::Dbo::Location>
In file included from /home/matthias/Documents/wt/src/Wt/Dbo/Types.h:10,
                 from /home/matthias/Documents/wt/src/Wt/Dbo/Dbo.h:10,
                 from /home/matthias/Documents/wt-support/forum/18360/location.h:3,
                 from /home/matthias/Documents/wt-support/forum/18360/location.cpp:1:

As a small nitpick, can I suggest you use #include <Wt::Dbo::Types.h>, which includes almost everything you could need in a Dbo class.

I hope this helps!

Best,
Matthias

RE: Relation Missmatch when following dbo::tutorial7 - Added by Christian Meyer almost 2 years ago

Thank you for your time Matthias

I finally had some sort of success ... but limited to a case that I don't want to use

I use static libraries to modularize specific parts of my program

One Part is the SessionModule, that takes care of the Database and changes to the db Structure etc.
The Next part is the ContactForm Module, with the Dbo Classes and Widgets related to that. As well as others that are self contained within their modules.

When I used the Dbo classes of ContactForm in an example function and included those files directly into the executable, the mapping works, even for the Module as a static library

as soon as the classes are not compiled into the executable itself, the error shows up at runtime.

whenever i put the template specialization in the header file, I can't get it to compile at all and have no idea as to how to solve that particular problem, unless putting the specialization in the cpp file.

But I would consider this case closed for now, Wt works, just not the way I use it =)

If you have an idea as to how to search for more information (keywords, directions to look into) I'd be grateful.

[SOLVED]: Relation Missmatch when following dbo::tutorial7 - Added by Christian Meyer almost 2 years ago

Solved this finally, even with my configuration of using it contained within a static library.

I moved the template specialization into a new header file: Location-traits.h and include this where a Wt::Dbo::ptr<Location> or weak_ptr is defined. Namely in Address.h

Also included the DBO_EXTERN_TEMPLATES(ContactForm::Dbo::Location) Makro in Location.h again.

This seemed to have done the trick. It compiles, and the most important part: It works as expected now!

Thank you for the input and pointers

    (1-6/6)