Fluent NHibernate Schema output with errors when using list - mysql

I have two tables which are Many-To-One mapped. However, it is important to maintain the order of the second table, so when I use automapping, Fluent automapper creates a bag. I changed this to force a list by using this command:
.Override(Of ingredients)(Function(map) map.HasMany(Function(x) x.PolygonData).AsList())
(VB.NET syntax)
So I say "AsList" and instead of using a bag, the mapping xml which gets generated contains a list now. Fine so far. However,
the statement generated cannot be handled by MySQL. I use MySQL55Dialect to create the statements and I use exactly that version. But it creates the following create:
create table `ingredients` (
Id INTEGER NOT NULL AUTO_INCREMENT,
Name FLOAT,
Amout FLOAT,
Soup_id INTEGER,
Index INTEGER,
primary key (Id)
)
It crashes because of the line "Index INTEGER," but I don't know what to do here. Any ideas?
Thanks!!
Best,
Chris

I would suspect that Index could be a keyword for MySQL. To avoid such conflict, we can define different Index column name (sorry for C# notation)
HasMany(x => x.PolygonData)
.AsList(idx => idx.Column("indexColumnName").Type<int>())

Related

Perl DBIx::Class encounterd Object Json

I'm new to Perl and DBIx::Class.
This is how I get my meaning_ids from the table translation where language = 5:
my $translations = $schema -> resultset('Translation')->search({ language => '5'});
After it I'm trying to push my data from the database into my array data:
while ( my $translation =$translations->next ) {
push #{ $data }, {
meaning_id => $translation-> meaning
};
}
$self->body(encode_json $data );
If I do it like this, I get the following error:
encountered object
'TranslationDB::Schema::Result::Language=HASH(0x9707158)', but neither
allow_blessed , convert_blessed nor allow_tags settings are enabled
(or TO_JSON/FREEZE method missing)
But if I do it like that:
while ( my $translation =$translations->next ) {
push #{ $data }, {
meaning_id => 0+ $translation-> meaning
};
}
$self->body(encode_json $data );
I don't get the error anymore, but the meaning is not the number out of the database. It's way too big (something like 17789000, but only numbers till 7000 are valid).
Is there an easy way to tell Perl that meaning_id is an INT and not a string?
It's a bit hard without knowing your schema classes, but #choroba is right. The error message says $translation->meaning is an instance of TranslationDB::Schema::Result::Language. That's explained in DBIx::Class::Manual::ResultClass on CPAN.
I believe there is a relationship to a table called meaning, and when you call $translation->meaning what you get is a new result class. Instead you need to call $translation->meaning_id. Actually that would only happen in a join, but your code doesn't look like it does that.
It seems $translation->meaning returns an object. Using 0+ just returns its address (that's why the numbers are so high).
It looks like there's a relationship between your translation and meaning tables. Probably, the translation table contains a foreign key to the meaning table. If you look in the Result class for your translation class then you will see that relationship defined - it will be called "meaning".
As you have that relationship, then DBIC has added a meaning method to your class which retrieves the meaning object that is associated with your translation.
But it appears that the foreign key column in your translation table is also called "meaning", so you expect calling the "meaning" method gives you the value of the foreign key rather than the associated object. Unfortunately it doesn't work like that. The relationship method overrides the column method.
This is a result of bad naming practices. I recommend that you call the primary key for every table id and the foreign key that links to another table <table_name>_id - so the column in your translation table would be called meaning_id. That way you can distinguish between the value of the key ($translation->meaning_id) and the associated meaning object ($translation->meaning).
A work-around you can use if you can't rename columns, is to use the get_column method - $translation->get_column('meaning').

Entity Framework related objects insertion with stored procedure and auto_increment field

I have a problem inserting a related row through Entity Framework 5. I'm using it with RIA Services and .NET Framework version 4.5. The database system is MySQL 5.6. The connector version is 6.6.5.
It raises a Foreign Key constraint exception.
I've chosen to simplify the model to expose my issue.
LDM
Provider(id, name, address)
Article(id, name, price)
LinkToProvider(provider_id, article_id, provider_price)
// Id's are auto_increment columns.
First I create a new instance of Article. I add an instance of LinkToProvider to the LinkProvider collection of the article. In this LinkToProvider object the product itself is referenced. An existing provider is also referenced.
Then I submit the changes.
Sample code from the DataViewModel
this.CurrentArticle = new Article();
...
this.CurrentArticle.LinkToProvider.Add(
new LinkToProvider { Article = this.CurrentArticle, Provider =
this.ProviderCollection.CurrentItem }
);
...
this.DomainContext.articles.Add(this.CurrentArticle);
this.DomainContext.SubmitChanges();
NOTE :
At the begining Entity Framework inserts the product well. Then it fails because it tries to insert a row in the LinkToPrivder table with an unkown product id like the following.
INSERT
INTO LinkToProvider
VALUES(5, 0, 1.2)
It puts 0 instead of the generated id.
But if I insert a product alone without any relations the product id is generated in the database correctly.
Any help will be much appreciated !
Thank you.
I found the answer.
You need to bind the result from the stored procedure to the id column in the edmx model
So I have to modify my stored procedure to add an instruction to show the last instered id for the article table on the standard output.
SELECT LAST_INSERT_ID() AS NewArticleId;
Then I added the binding with the name of the column name returned by the stored procedure. Here it's NewArticleId.
It's explained here : http://learnentityframework.com/LearnEntityFramework/tutorials/using-stored-procedures-for-insert-update-amp-delete-in-an-entity-data-model/.

EF 4.1 Table-per-Hierarchy

I'm trying to implement a simple TPH example from http://msdn.microsoft.com/en-us/library/dd793152.aspx. I have two tables:
PERSON
[PersonID] [int] IDENTITY(1,1) NOT NULL,
[PersonTypeID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
[HourlyRate] [int] NULL
PersonType
[PersonTypeID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL
In EF designer, I follow the tutorial and create a new Entity called Employee and specify Person as the base type. Then move the HourlyRate property to Employee. In the Mapping Details window, I map the entity to the Person table and it properly maps HourlyRate property to the correct DB field. Then I set Person to abstract.
If I build it now without specifying a condition and a discriminator in the Employee entity, it builds fine. If I follow the tutorial and specify HourlyRate as the condition and use "Is" "Not Null" as the discriminator, it builds fine.
But I want to use PersonTypeID as the discriminator and an Employee should have a PersonTypeID of 1. So I select PersonTypeID as the the condition field, "=" as the operator, and 1 as the value. When I build, VS tells me the it's successful but also has something in the Error window.
Error 3032: Problem in mapping fragments starting at line
798:Condition member 'Person.PersonTypeID' with a condition other than
'IsNull=False' is mapped. Either remove the condition on
Person.PersonTypeID or remove it from the mapping.
I read in another article that I need to delete the PersonType navigation property in the Person Entity. So I tried that but still got the same error.
I thought I was able to get this to work before on another project but I'm not sure what changed for this one. The only thing different that I can think of is that I recently updated to EF 4.1.
This is what I have set up in the designer
Any suggestions are greatly appreciated!
I figured it out. Adding the PersonType entity to the designer threw everything off. The key was to delete the PersonType navigation property as well as the PersonTypeID property. But since I included the PersonType entity, deleting PersonTypeID broke the foreign key constraint.
By not including PersonType entity, I can delete PersonTypeID and everything compiles successfully.

SQL Alchemy and generating ALTER TABLE statements

I want to programatically generate ALTER TABLE statements in SQL Alchemy to add a new column to a table. The column to be added should take its definition from an existing mapped class.
So, given an SQL Alchemy Column instance, can I generate the SQL schema definition(s) I would need for ALTER TABLE ... ADD COLUMN ... and CREATE INDEX ...?
I've played at a Python prompt and been able to see a human-readable description of the data I'm after:
>>> DBChain.__table__.c.rName
Column('rName', String(length=40, convert_unicode=False, assert_unicode=None, unicode_error=None, _warn_on_bytestring=False), table=<Chain>)
When I call engine.create_all() the debug log includes the SQL statements I'm looking to generate:
CREATE TABLE "Chain" (
...
"rName" VARCHAR(40),
...
)
CREATE INDEX "ix_Chain_rName" ON "Chain" ("rName")
I've heard of sqlalchemy-migrate, but that seems to be built around static changes and I'm looking to dynamically generate schema-changes.
(I'm not interested in defending this design, I'm just looking for a dialect-portable way to add a column to an existing table.)
After tracing engine.create_all() with a debugger I've discovered a possible answer:
>>> engine.dialect.ddl_compiler(
... engine.dialect,
... DBChain.__table__.c.rName ) \
... .get_column_specification(
... DBChain.__table__.c.rName )
'"rName" VARCHAR(40)'
The index can be created with:
sColumnElement = DBChain.__table__.c.rName
if sColumnElement.index:
sIndex = sa.schema.Index(
"ix_%s_%s" % (rTableName, sColumnElement.name),
sColumnElement,
unique=sColumnElement.unique)
sIndex.create(engine)

Errors creating generic relations using content types (object_pk)

I am working to use django's ContentType framework to create some generic relations for a my models; after looking at how the django developers do it at django.contrib.comments.models I thought I would imitate their approach/conventions:
from django.contrib.comments.models, line 21):
content_type = models.ForeignKey(ContentType,
verbose_name='content type',
related_name="content_type_set_for_%(class)s")
object_pk = models.TextField('object ID')
content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk")
That's taken from their source and, of course, their source works for me (I have comments with object_pk's stored just fine (integers, actually); however, I get an error during syncdb on table creation that ends:
_mysql_exceptions.OperationalError: (1170, "BLOB/TEXT column 'object_pk' used in key specification without a key length")
Any ideas why they can do it and I can't ?
After looking around, I noticed that the docs actually state:
Give your model a field that can store a primary-key value from the models you'll be relating to. (For most models, this means an IntegerField or PositiveIntegerField.)
This field must be of the same type as the primary key of the models that will be involved in the generic relation. For example, if you use IntegerField, you won't be able to form a generic relation with a model that uses a CharField as a primary key.
But why can they do it and not me ?!
Thanks.
PS: I even tried creating an AbstractBaseModel with these three fields, making it abstract=True and using that (in case that had something to do with it) ... same error.
After I typed out that really long question I looked at the mysql and realized that the error was stemming from:
class Meta:
unique_together = (("content_type", "object_pk"),)
Apparently, I can't have it both ways. Which leaves me torn. I'll have to open a new question about whether it is better to leave my object_pk options open (suppose I use a textfield as a primary key?) or better to enforce the unique_togetherness...