Naming a multi-column constraint using JPA - sql-server-2008

The name attribute of #UniqueConstraint seems to have no effect.
#Entity
#Table(name = "TAG", uniqueConstraints = #UniqueConstraint(columnNames = {
"TAG_NAME", "USERS_ID" }, name="UQ_TAG_USER"))
public class Tag extends BaseEntity {
}
I'm usning SQL Server 2008, JPA 2.0 with Hibernate 3.6.
On the DB side an index, UQ__TAG__6EF57B66 is created instead of UQ_TAG_USER.
What am I missing? is there no way to enforce a given name from java side? and one must resort to editing schema files? we are a small shop without a DBA and I try to make do as much as I can by the help of hibernate schema facilities.

I assume you are using hibernate because you have it in the tags for this question. It's a bug/missing feature in hibernate:
https://hibernate.onjira.com/browse/HB-1245
It will simply ignore the unique constraint name when the dialect supports creating the constraint in the same statement as create table.
I've checked SqlServer and Oracle dialects and they both support this way of creating the constraint, that will cause the bug you are experiencing.
There are two ways to workaround this bug:
1. The quick way:
Just extend the dialect and return false for supportsUniqueConstraintInCreateAlterTable() method:
public static class SQLServerDialectImproved extends SQLServerDialect {
#Override
public boolean supportsUniqueConstraintInCreateAlterTable() {
return false;
}
}
And set this class as your dialect in hibernate.dialect property of the persistence unit configuration (persistence.xml).
2. The right way:
Fix the hibernate code and recompile:
The bug is at org.hibernate.mapping.UniqueKey class, the method sqlConstraintString() will return unique (TAG_NAME, USERS_ID) for all dialects, even if they support constraint UQ_TAG_USER unique (TAG_NAME, USERS_ID).
But that is probably a larger change (need to support all kinds of dialects, etc.)
Under the hood:
If you use the original dialect, it will cause the following sql statement to be executed to create the table (added id column):
create table TAG (
id bigint not null,
TAG_NAME varchar(255),
USERS_ID varchar(255),
primary key (id),
unique (TAG_NAME, USERS_ID)
)
And after you apply the fix as stated in first option the following sql statements will be executed:
create table TAG (
id numeric(19,0) not null,
TAG_NAME varchar(255),
USERS_ID varchar(255),
primary key (id)
)
create unique index UQ_TAG_USER on TAG (TAG_NAME, USERS_ID)
which include the creation of the unique constraint with the chosen name (UQ_TAG_USER) in a separate statement.

Related

Manually setting annotation on generated migration using EF and MySql

I have a property that is in my class that is not the primary key that I want to auto increment. The primary key is a GUID so I can still use the auto increment function on another column in the table. Also I can't change the primary key to int as the GUID key is defined in a base class. I can manually add the .Annotation("MySQL:AutoIncrement", true) to the property in the generated migration but I'm concern about editing the migration causing future issues. I found what would be the answer via the .AddAnnotation(,) method but it doesn't created the desired results.
Also [DatabaseGenerated(DatabaseGeneratedOption.Identity)] doesn't produce the desired result.
I was hoping this:
builder.Entity<Editor>().Property(p => p.CreatorId).ValueGeneratedOnAdd().Metadata.AfterSaveBehavior = PropertySaveBehavior.Throw;
builder.Entity<Editor>().Property(p => p.CreatorId).Metadata.AddAnnotation("MySQL:AutoIncrement", true);
Would make this:
migrationBuilder.CreateTable(
name: "editor",
columns: table => new
{
CreatorId = table.Column<int>(nullable: false).Annotation("MySQL:AutoIncrement", true)
...
MySql.Data.EntityFrameworkCore: 8.0.18.0
Microsoft.EntityFrameworkCore: 2.2.4
After using DotPeek to look at the code for MySql.Data.EntityFramework it seems to not be possible to reach the desired affect with fluentApi or attributes as it will only add the annotation if it's the primary key. Regardless of if it's possible in the database.

Fluent NHibernate Schema output with errors when using list

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>())

Taking a datetime field into primary key throws fatal error

I would like to use the combination of two foreign keys plus the datetime field as my combined primary key.
But I get a
Catchable Fatal Error: Object of class DateTime could not be converted
to string in
C:\development\xampp\htdocs\happyfaces\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php
line 1337
when I do so. As soon as I remove the id: true from my YML entity declaration everything works fine again.
What is the problem that occurs here? It seems to be rather a Symfony2 or a Doctrine2 bug to me, because the datetime is set fine in the database if I don't declare the datetime column to be part of the primary key.
Can anyone help or advise?
Its not possible and not recommended. For primary key focus on primitive data types such as Integer or String. The most RDMS System prefer Integer as primary key for maximum performance.
Take look: http://doctrine-orm.readthedocs.org/en/2.1/tutorials/composite-primary-keys.html
Maybe a workaround could work by adding a new Doctrine data type. With a __toString() function, but I think Doctrine will force you to use primitive data types only.
class Foo
{
private $bar = 'test';
public function __toString()
{
return $this->bar;
}
}
echo new Foo();
Your error means in general DateTime has no __toString() function or is not string compatible. I never tested it to use a custom data type as primary key. So you've to try it yourself.
Take a look: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/types.html
Another try is use String as Primary key and set your id with
$entity->setId(new \DateTime()->format('yyyy/mm/dd'));
Here is a similar question: Symfony/Doctrine: DateTime as primary key

Entity Framework setting Foreign Key reference to aspnet_users table w/o an entity class

I'm trying to add a foreign key reference to the aspnet_users table to my Users table, to simply extend the aspnet_users. I'm using EF and I don't want to create an aspnet_users entity class. Is there a way to use the fluent API to create a foreign key reference to a table the EF isn't currently tracking?
I know it's not fluent API, but I tried the following w/ obvious fail:
[ForeignKey("aspnet_users.UserId")]
Thanks.
This is not possible with fluent API either. You will have to execute the SQL manually to create the FK. If you are using database initializer then you can try something like this.
public class MyInitializer : CreateDatabaseIfNotExists<MyDbContext>
{
protected override void Seed(MyDbContext context)
{
//your logic here
context.Database.ExecuteSqlCommand("alter table MyTable
add constraint MyTable_MyColumn_FK FOREIGN KEY ( MyColumn ) references aspnet_users(UserId)");
}
}

How to create indexes on multiple columns

We have the following entity relationships where a User belongs to a particular Organization. My queries either look like "select * from User where org=:org" or "select * from User where org=:org and type=:type"
I have separate indexes on the User class. The first query will be fine, because of the Index on the foreign key element. Does the second query mandate a multi columnindex on org and type columns. If so how should I annotate to create one such index.
#Entity
class User {
...
#ManyToOne
#ForeignKey
#Index
Organization org;
#Index
Type type;
...
}
This is doable using the Hibernate specific #Table annotation. From the documentation:
2.4.1 Entity
...
#Table(appliesTo="tableName", indexes = { #Index( name="index1", columnNames={"column1", "column2"} ) } ) creates the defined indexes on the columns of table tableName. This can be applied on the primary table or any secondary table. The #Tables annotation allows your to apply indexes on different tables. This annotation is expected where #javax.persistence.Table or #javax.persistence.SecondaryTable(s) occurs.
Reference
Hibernate Annotations Reference Guide
2.4. Hibernate Annotation Extensions
As you can read in JSR-000338 Java Persistence 2.1 Proposed Final Draft Specification:
11.1.23 Index Annotation
The Index annotation is used in schema generation. Note that it is not necessary to specify an index for a primary key, as the primary key index will be created automatically, however, the Index annotation may be used to specify the ordering of the columns in the index for the primary key.
#Target({}) #Retention(RUNTIME)
public #interface Index {
String name() default "";
String columnList();
boolean unique() default false;
}
The syntax of the columnList element is a column_list, as follows:
column::= index_column [,index_column]*
index_column::= column_name [ASC | DESC]
The persistence provider must observe the specified ordering of the
columns.
If ASC or DESC is not specified, ASC (ascending order) is
assumed.
Usage example:
#Table(indexes = {
#Index(columnList = "org,type"),
#Index(columnList = "another_column")})
Yes, it is possible using JPA 2.1 as seen in the specification here:
http://download.oracle.com/otndocs/jcp/persistence-2_1-pfd-spec/index.html
on page 445 it states that
The Index annotation is used in schema generation
columnList (Required) The names of the columns to be included in the index.
An example of usage can be seen here:
http://java-persistence-performance.blogspot.co.uk/2013/03/but-what-if-im-not-querying-by-id.html
It seems that the syntax is the same or very similar to Hibernate.