Grails: domain properties are mandatory by default and Id is not generated - grails-domain-class

I am new to Grails. I installed Grails 2.4.4 version and Spring Tool Suite.
I created Grails project and domain ,controller classes. But i am getting all the fields as mandatory by default and "id" is not generated. Need some help.
Domain Class:
package org.example.pomorodo
class Task {
String summary
String details
Date dateCreated
Date deadLine
Long timeSpent=0L
static constraints = {
}
}
Controller Class:
package org.example.pomorodo
class TaskController {
static scaffold =Task
}

Do you mean you can't access the "id" property after saving your domain object with GORM? Or just that the generated code doesn't have an "id" property explicitly defined? If it's the latter, don't worry. The "id" property is automatically injected by metaprogramming black-magic by the framework. If it's the former, something else is wrong, as you should definitely have a valid "id" after saving a domain object.
On the mandatory fields: Use the constraints block to toggle fields to nullable = true. Example:
package org.example.pomorodo
class Task {
String summary
String details
Date dateCreated
Date deadLine
Long timeSpent=0L
static constraints = {
summary(nullable:true)
details(nullable:true)
}
}
You can also modify default constraints globally. See the constraints documentation for more details.

Recently I got a query regarding mapping a database table which do not have any id and version. For example the table have two varchar fields username and password nothing more than that.
Although it was something strange for me that table doesn’t have the id field. The good thing is that the username is a primary key in the table and this is not auto incremented user want to create it by his own method.
The good thing about grails is, in most of the cases you get your answer in the docs http://grails.org/doc/latest/ . So in this case we just need to change the id field in grails domain like this
class Test {
String username
String password
static mapping = {
id name: 'username'
version false
id generator: 'assigned'
}
static constraints = {
username(nullable: true)
}
}

Related

Servicestack Ormlite multi-column constraint fails where constraint includes Enum

I am using ServiceStack.Ormlite, and also make heavy use of the automatic handling of enums whereby they are stored in the db as strings but retrieved and parsed nicely back into Enums on retrieval, so I can do easy type-comparison - say, for a property "UserRole" in the db/table class "User" of enum type "UserRoleEnum" (just for demonstration).
This works great.. until I want to use the enum property to define a multi-column unique constraint
CompositeIndexAttribute(bool unique, params string[] fieldNames);
like:
[CompositeIndex(true, nameof(UserId), nameof(UserRole)]
public class User
{
public long UserId {get;set;}
public UserRoleEnum UserRole {get;set;
}
(as per :
How to Create Unique Constraint with Multiple Columns using ServiceStack.OrmLite? ).
At which time i get:
System.Data.SqlClient.SqlException
Column 'UserRole' in table 'User' is of a type that is invalid for use as a key column in an index.
I currently see options as:
a) Define UserRole as a string (isntead of UserRoleEnum ) in the table entity class and lose the Enum use.... having to manually test the value each time to confirm that the db value is one that i expect in my business logic later
b) Continue to use UserRoleEnum but lose the ability to declare multicolumn uniqueconstraints using the class attribute, and probably have to create these manually using a subsequent db migration script?
Is there any way to make the enums and the multicolumn constraint play nicely, out of the box?
This issue was because enum properties were using the default string definition fallback of VARCHAR(MAX) which SQL Server doesn't let you create indexes on whereas the column definition of a string property is VARCHAR(8000).
This issue is now resolved from this commit which now uses the VARCHAR(255) string definition of the EnumConverter Type Converter. This change is available from v4.5.5 that's now available on MyGet.
Otherwise you can also change the size of the column definition to match a string property by adding a [StringLength] attribute, e.g:
[CompositeIndex(true, nameof(UserId), nameof(UserRole))]
public class User
{
public long UserId { get; set; }
[StringLength(8000)]
public string UserRole { get; set; }
}

Why model validation is not working

I have following Model class that is used during the Web API Post. As you can see Id field is annotated as Required.
public class Model
{
[Required]
public Guid Id { get; set; }
}
The Post for API is as follows
[HttpPost]
public IActionResult Post([FromBody]Model value)
{
if (!ModelState.IsValid)
return BadRequest();
Model newModel = new Model() { Id = value.Id };
return Ok(newModel);
}
On a sunny day, this is what I see. All good
enter image description here
On a rainy day, when Id is not provided, I get following.
enter image description here
Given that in the second example, a Required field is not provided, shouldn't a BadRequest is returned rather than a 200 with invalid id guid with 00000000-0000-0000-0000-000000000000?
Using the Required annotation
In the Web API Docs, your issue is known as 'under-posting'.
The issue is that Guid has a default value, so when no value is provided, it is initialized with the default value... which then satisfies the Required constraint.
To prevent this, counter-intuitively you make the Guid nullable using Guid?.
Then if the value is not provided, the deserializer will set the value to null, which will cause the Required constraint to be violated.
If the value is provided, it will be set, and all will be well.
See https://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api for more details, there is an example of a similar issue for a decimal property.
The key distinction to understand is that Guid.Empty is really a valid Guid. The only way to distinguish between the user providing a Guid (which is empty) and not providing one at all is to make it nullable, so null = not provided, and Empty = the user provided the empty Guid.
Using a Custom Annotation
If you really don't want to make your Guid nullable, you need to consider what would you do for a 'normal' value type, e.g. an integer. Rather than making it required, you'd use a Range attribute and specify that it must be > 0.
Similarly for Guids, you'd ideally have an attribute that would simply test that it is != Guid.Empty
See https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation#custom-validation for guidance on creating a custom validation atribute.

How can I configure Grails id columns to use UUID on Oracle?

I'd like to use a 128-bit UUID rather than Long for the id field on all of my Grails domains. I'd rather not have to specify all of the mapping information on every domain. Is there a simple way to achieve this in a generic/global way? I'm using Grails 2.3.x, the Hibernate 3.6.10.2 plugin, the Database Migration Plugin 1.3.8, and Oracle 11g (11.2.0.2.0).
There seem to be a number of questions related to this, but none provide complete, accurate, and up-to-date answers that actually work.
Related Questions
What's the best way to define custom id generation as default in Grails?
grails using uuid as id and mapping to to binary column
Configuring Grails/Hibernate/Postgres for UUID
Problems mapping UUID in JPA/hibernate
Custom 16 digit ID Generator in Grails Domain
Using UUID and RAW(16)
If you want to use a UUID in your Grails domain and a RAW(16) in your database, you'll need to add the following.
For every domain, specify the id field. Here's an example using ExampleDomain.groovy
class ExampleDomain {
UUID id
}
Add the following mapping to Config.groovy
grails.gorm.default.mapping = {
id(generator: "uuid2", type: "uuid-binary", length: 16)
}
For details on the three values I've selected, please see these links.
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/mapping.html#d0e5294
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/types.html#types-basic-value-uuid
How should I store a GUID in Oracle?
Add a custom dialect to your data source entry in Datasource.groovy. If you are using Hibernate 4.0.0.CR5 or higher, you can skip this step.
dataSource {
// Other configuration values removed for brevity
dialect = com.example.hibernate.dialect.BinaryAwareOracle10gDialect
}
Implement the custom dialect you referenced in step #3. Here is BinaryAwareOracle10gDialect implemented in Java. If you are using Hibernate 4.0.0.CR5 or higher, you can skip this step.
package com.example.hibernate.dialect;
import java.sql.Types;
import org.hibernate.dialect.Oracle10gDialect;
public class BinaryAwareOracle10gDialect extends Oracle10gDialect {
#Override
protected void registerLargeObjectTypeMappings() {
super.registerLargeObjectTypeMappings();
registerColumnType(Types.BINARY, 2000, "raw($l)");
registerColumnType(Types.BINARY, "long raw");
}
}
For more information about this change, please see the related Hibernate defect https://hibernate.atlassian.net/browse/HHH-6188.
Using UUID and VARCHAR2(36)
If you want to use a UUID in your Grails domain and a VARCHAR2(36) in your database, you'll need to add the following.
For every domain, specify the id field. Here's an example using ExampleDomain.groovy.
class ExampleDomain {
UUID id
}
Add the following mapping to Config.groovy
grails.gorm.default.mapping = {
id(generator: "uuid2", type: "uuid-char", length: 36)
}
For details on the three values, please see the links in step #2 from the previous section.
I think there is a easy way:
String id = UUID.randomUUID().toString()
static mapping = {
id generator:'assigned'
}

How to Authenticate using MVC5RC/RTW with existing database

I originally asked this question when Identity was in beta. The classes and interfaces have changed considerably since then and it appears the RTW version has some modifications again over the RC version. In principle I need to achieve the following.
authenticate the local login against my usertable tblMembers which contains the userid field and password which are the two items I need to authenticate.
have access to my tblMember record/class via the Controller.User property (Prior to MVC5 identity I had achieved this using the membership provider methods.) regardless of if the user logged in via the localuser method or via one of the other OAuth providers (Twitter, Google etc).
Ability to display my own custom username despite the login method. Local users login with a userid 1234567 and a password, ideally I would like to display "John Smith (1234567)" regardless of the authentication method (local/Twitter etc)
Initially I'm unsure as to what my memberclass should be inheriting from It appears from the
aspIdentitySample project that I should be using IdentityUser?
public partial class tblMember
{
public int id { get; set; }
public string membership_id { get; set; }
public string password { get; set; }
....other fields
}
Are there any new or updated examples of integrating your existing database/user tables with the ASP.NET Identity system?
I am also adding the identity tables to my database. If you create a new web project in visual studio 2013 you will see that now in RTM everything works better than RC plus you will see the
following table
public class ApplicationUser : IdentityUser
{
}
So Instead of ApplicationUser you can call your table tblMembers
public class tblMembers : IdentityUser
{
}
your table tblMembers will inherit Id Username Password security stamp and a discriminator column saying this is a tblMemeber
without making custom classes for authentication the easiest thing to do would be just to make the username the combination of your old usernames and userids. Then store the users real name or old username without the user id in a separate column.
have the users register with the built in user login and they can go to manage account and click use another service to log in. This will link the Google account to their regular account, so no matter which one they use it will log them in to the same account. If you have users with connected table information, I suggest you seed your table with all the users with something similar to the register method found in the template.Then just match the new combined username and Id to the old ones and populate data where needed in sql management studio.
Again a lot of issues in RC with extending IdentityUsers have been fixed. Microsoft is already adding more features to the identity user store and this tutorial http://www.windowsazure.com/en-us/develop/net/tutorials/web-site-with-sql-database/ is supposed to be updated soon. I plan on making my own walk through when i'm done changing my database but for now I hope my suggestions even though they are a simpler solution than you might want to implement.
You can do this easily by modifying the IdentityModel.cs as per the below:
Override OnModelCreating in your DbContext then add the following, this will change AspNetUser table to "Users" you can also change the field names the default Id column will become User_Id.
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
or simply the below if you want to keep all the standard column names:
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo")
Full example below (this should be in your IdentityModel.cs file) i changed my ApplicationUser class to be called User.
public class User : IdentityUser
{
public string PasswordOld { get; set; }
public DateTime DateCreated { get; set; }
public bool Activated { get; set; }
public bool UserRole { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<User>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
modelBuilder.Entity<User>()
.ToTable("Users", "dbo").Property(p => p.Id).HasColumnName("User_Id");
}
}
Please note i have not managed to get this working if the current table exists.
Also note whatever columns you do not map the default ones will be created.
Hope that helps.
I'm starting to think (partially due to the lack of information in this area), that it may be easier to user the default identity classes, but to provide referential integrity to my own user table from the AspNetUsers table.
If i add a custom linking field into the AspNetUsers table is it possible to access my tables from the Controllers.User property? i.e. Controller.User.tblMember.Orders?

Can't Persist Field to Aspnet_Users via NHibernate/ActiveRecord

I'm using ActiveRecord with NHibernate on the backend. I've set up a mapping for Users; I can create/retrieve/register users without any issues.
I now want to add an association called Role to my users (many users per role). I've created the appropriate Role class, tables, data, etc. and everything seems to be working on that end as well.
The problem is that when I save a user and associate a Role, that association does not persist to the database.
I've added a RoleId (int16) column to the aspnet_Users table to match the Role table's Id (int16) column. I've tried using Save and SaveAndFlush without success.
Here's some code:
Role superUser = Role.First(r => r.name == "Super User");
User me = User.First(r => r.UserName == myUserName);
me.Role = superUser;
me.Save(); // Or: SaveAndFlush
When debugging, I can see the association on the objects when they're saved (i.e. me.Role is not null and has the right attributes/properties/etc.) However, when I look at the database, the RoleId value for that user is still NULL. (SaveAndFlush doesn't make a difference.)
What am I missing?
I've read somewhere on SO that extending the users table is usually done by adding another table and linking the two by a foreign key; I assume the classes would then use inheritance by composition for the new ExtendedUser class. Assuming I don't want to go that route, why isn't this working? Is it because of the specific ASP.NET MVC stored procedures et. all?
Some relevant mapping:
[ActiveRecord("aspnet_Users", Mutable = false)]
public class User : ActiveRecordLinqBase<User>
{
[PrimaryKey(PrimaryKeyType.Assigned)]
public Guid UserId { get; set; }
// ...
[BelongsTo("RoleId", Cascade = CascadeEnum.SaveUpdate)]
public Role Role { get; set; }
}
[ActiveRecord]
public class Role : ActiveRecordLinqBase<Role>
{
[PrimaryKey]
public int Id { get; set; }
// ...
[HasMany(Inverse = true)]
public IList<User> Users { get; set; }
[Property]
public string Name { get; set; }
}
Edit: mutable="false" - this clearly stands that entity is read only, which is the source of your problem.
Immutable classes, mutable="false", may not be updated or deleted by the application. This allows NHibernate to make some minor
performance optimizations.
Also:
I believe that you need to have cascading defined. You are not saving just the entity itself but also reference to other entity. Use attributes, fluent config or hbml to define this the way you need. Here are the cascading options:
Here is what each cascade option means:
none - do not do any cascades, let the users handles them by
themselves.
save-update - when the object is saved/updated, check the assoications and save/update any object that require it (including
save/update the assoications in many-to-many scenario).
delete - when the object is deleted, delete all the objects in the assoication.
delete-orphan - when the object is deleted, delete all the objects in the assoication. In addition to that, when an object is
removed from the assoication and not assoicated with another object
(orphaned), also delete it.
all - when an object is save/update/delete, check the assoications and save/update/delete all the objects found.
all-delete-orphan - when an object is save/update/delete, check the assoications and save/update/delete all the objects found. In additional to that, when an object is removed from the assoication and not assoicated with another object (orphaned), also delete it.
You may want to read this article.

Resources