Related
I save my cookie as the following code:
public static void SetCookie(string key, string value, int expireDay = 1)
{
var cookie = new HttpCookie(key , value);
cookie.Expires = DateTime.Now.AddDays(expireDay);
HttpContext.Current.Response.Cookies.Add(cookie);
}
The cookie values when stored are as follows:
Read Cookie:
public static string GetCookie(string key)
{
string value = string.Empty;
var cookie = HttpContext.Current.Request.Cookies[key];
if (cookie != null)
{
if (string.IsNullOrWhiteSpace(cookie.Value))
{
return value;
}
value = cookie.Value;
}
return value;
}
The problem is that when reading the cookie, all the values are empty according to the image below:
The maximum size of a cookie is 4kb.
Actually you should read cookies from request header; not response!
The problem is here: HttpContext.Current.Response.Cookies.AllKeys.Contains(key).
You need to read it from the request. And write the changes to the response.
Here's a simpler working example, that simply prints "Hey!", and appends an exclamation on each GET:
public class IndexModel : PageModel
{
public string CookieValue = "Hey!";
private const string COOKIE_KEY = "HEY_COOKIE";
public void OnGet()
{
Request.Cookies.TryGetValue(COOKIE_KEY, out string? actualValue);
if (actualValue is not null) CookieValue = actualValue + "!";
// Only required since we're changing the cookie
// TODO: set the right cookie options
Response.Cookies.Append(COOKIE_KEY, CookieValue, new CookieOptions { });
}
}
#page
#model IndexModel
<h1>#Model.CookieValue</h1>
Also, while debugging things over HTTP, it's useful to also look at Chrome's network tab.
Your problem is that you used HttpContext.Current.Response. Instead of this, you should declare a parameter in the SetCookie method like this: HttpContext context, then in the controller, when you call the method, you have to send HttpContext controller property as an argument.
public static void SetCookie(HttpContext context, string key, string value, int expireDay = 1)
{
var cookie = new HttpCookie(key , value);
cookie.Expires = DateTime.Now.AddDays(expireDay);
context.Response.Cookies.Add(cookie);
}
In the controller:
SetCookie(HttpContext, yourKey,yourValue)
You also should change your GetCookie method like this:
public static string GetCookie(HttpContext context,string key)
{
string value = string.Empty;
var cookie = context.Request.Cookies[key];
if (cookie != null)
{
if (string.IsNullOrWhiteSpace(cookie.Value))
{
return value;
}
value = cookie.Value;
}
return value;
}
I'm working with some application designed using ASP.NET MVC.
Did spend lot of time trying to solve some problem, but do not have idea what to do to solve it.
As similar code shown below for big JSON will throw exception :
"Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
"
EXAMPLE :
$http.post('/API/PostData',aoData)...
where aoData equals 3K array of JSON, etc.
Added some solution suggested in many questions being asked on stackoverflow.
Did solve that problem just by :
Removing JsonValueProviderFactory from the ValueProviderFactories.Factories
And adding copy of the original class with simple modification such as :
EXAMPLE:
public sealed class LargeJsonValueProviderFactory : ValueProviderFactory
{
private static void AddToBackingStore(LargeJsonValueProviderFactory.EntryLimitedDictionary backingStore, string prefix, object value)
{
IDictionary<string, object> dictionary = value as IDictionary<string, object>;
if (dictionary != null)
{
foreach (KeyValuePair<string, object> keyValuePair in (IEnumerable<KeyValuePair<string, object>>) dictionary)
LargeJsonValueProviderFactory.AddToBackingStore(backingStore, LargeJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value);
}
else
{
IList list = value as IList;
if (list != null)
{
for (int index = 0; index < list.Count; ++index)
LargeJsonValueProviderFactory.AddToBackingStore(backingStore, LargeJsonValueProviderFactory.MakeArrayKey(prefix, index), list[index]);
}
else
backingStore.Add(prefix, value);
}
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return (object) null;
string end = new StreamReader(controllerContext.HttpContext.Request.InputStream).ReadToEnd();
if (string.IsNullOrEmpty(end))
return (object) null;
var serializer = new JavaScriptSerializer {MaxJsonLength = Int32.MaxValue};
return serializer.DeserializeObject(end);
}
/// <summary>Returns a JSON value-provider object for the specified controller context.</summary>
/// <returns>A JSON value-provider object for the specified controller context.</returns>
/// <param name="controllerContext">The controller context.</param>
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
object deserializedObject = LargeJsonValueProviderFactory.GetDeserializedObject(controllerContext);
if (deserializedObject == null)
return (IValueProvider) null;
Dictionary<string, object> dictionary = new Dictionary<string, object>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
LargeJsonValueProviderFactory.AddToBackingStore(new LargeJsonValueProviderFactory.EntryLimitedDictionary((IDictionary<string, object>) dictionary), string.Empty, deserializedObject);
return (IValueProvider) new DictionaryValueProvider<object>((IDictionary<string, object>) dictionary, CultureInfo.CurrentCulture);
}
private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString((IFormatProvider) CultureInfo.InvariantCulture) + "]";
}
private static string MakePropertyKey(string prefix, string propertyName)
{
if (!string.IsNullOrEmpty(prefix))
return prefix + "." + propertyName;
return propertyName;
}
private class EntryLimitedDictionary
{
private static int _maximumDepth = LargeJsonValueProviderFactory.EntryLimitedDictionary.GetMaximumDepth();
private readonly IDictionary<string, object> _innerDictionary;
private int _itemCount;
public EntryLimitedDictionary(IDictionary<string, object> innerDictionary)
{
this._innerDictionary = innerDictionary;
}
public void Add(string key, object value)
{
if (++this._itemCount > LargeJsonValueProviderFactory.EntryLimitedDictionary._maximumDepth)
throw new InvalidOperationException("JsonValueProviderFactory_RequestTooLarge");
this._innerDictionary.Add(key, value);
}
private static int GetMaximumDepth()
{
NameValueCollection appSettings = ConfigurationManager.AppSettings;
if (appSettings != null)
{
string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers");
int result;
if (values != null && values.Length > 0 && int.TryParse(values[0], out result))
return result;
}
return 1000;
}
}
}
And that solve the problem with maxJsonLength. Great! But...
If JSON contains property called ACTION, controller get data being changed. The ACTION property contains name of the controller's action instead of "MAR". The LargeJsonValueProviderFactory class does not change value of the ACION property. But if LargeJsonValueProviderFactory class shown above is not is use issue disappears.
EXAMPLE :
{
NR : 1200,
ACTION : "MAR",
.....
}
public ActionResult Save(PrsentationEntity aoData)
{
aoData.NR equals 1200 - OK
aoData.ACTION equals "Save" -Should be "MAR"
Do you have any ideas why I have that problem ?
Regards
Marcin
tl;dr
When configuring the application the original JsonValueProviderFactory should be replaced by the custom LargeJsonValueProviderFactory instead of added to the end of the collection.
Long version
You said you solved the problem by:
Removing JsonValueProviderFactory from the ValueProviderFactories.Factories
And adding copy of the original class with simple modification such as :
That's why the problem occurs.
The order of the factories on ValueProviderFactories.Factories does matter, but it's not generally discussed.
The original order is this:
private static readonly ValueProviderFactoryCollection _factories = new ValueProviderFactoryCollection()
{
new ChildActionValueProviderFactory(),
new FormValueProviderFactory(),
new JsonValueProviderFactory(),
new RouteDataValueProviderFactory(),
new QueryStringValueProviderFactory(),
new HttpFileCollectionValueProviderFactory(),
new JQueryFormValueProviderFactory()
};
If you just add your new provider to the end of the collection it won't be used if one of the other providers does the job (in this case it seems that RouteDataValueProviderFactory was used).
Say I have a field content that is a json. I would like to store it in database so that my domain class keeps only the 1 field only. (It's more of a brain task ;-)
class MyDomain{
def content
static constraints = {
content nullable: false, blank: false, sqlType: "text" // adapter from JSON to String??
}
def beforeInsert(){
content = content.toString()
}
def beforeUpdate(){
content = content.toString()
}
def afterInsert(){
content = JSON.parse(content) as JSON
}
def afterUpdate(){
content = JSON.parse(content) as JSON
}
def onLoad(){
content = JSON.parse(content) as JSON
}
}
I want my domain object to expose only content so I don't want to use another field like String contentAsText because it would be visible outside.
In the whole GORM documentation I haven't found a thing how to manage it. I've tried beforeValidate()/beforeInsert() and onLoad() methods but no luck...
How can I adapt the value before it gets persisted?
You can define a custom hibernate user-type for JSONElement as described here: https://stackoverflow.com/a/28655708/607038
In domain class constraints:
static constraints = {
content type: JSONObjectUserType
}
User Type Class:
import org.grails.web.json.JSONObject
import org.hibernate.HibernateException
import org.hibernate.engine.spi.SessionImplementor
import org.hibernate.type.StandardBasicTypes
import org.hibernate.usertype.EnhancedUserType
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.sql.SQLException
import java.sql.Types
class JSONObjectUserType implements EnhancedUserType, Serializable {
private static final int[] SQL_TYPES = [Types.VARCHAR]
#Override
public int[] sqlTypes() {
return SQL_TYPES
}
#Override
public Class returnedClass() {
return JSONObject.class
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true
}
if (x == null || y == null) {
return false
}
JSONObject zx = (JSONObject) x
JSONObject zy = (JSONObject) y
return zx.equals(zy)
}
#Override
public int hashCode(Object object) throws HibernateException {
return object.hashCode()
}
#Override
public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
throws HibernateException, SQLException {
Object jsonObject = StandardBasicTypes.STRING.nullSafeGet(resultSet, names, session, owner)
if (jsonObject == null) {
return null
}
return new JSONObject((String) jsonObject)
}
#Override
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session)
throws HibernateException, SQLException {
if (value == null) {
StandardBasicTypes.STRING.nullSafeSet(preparedStatement, null, index, session)
} else {
JSONObject jsonObject = (JSONObject) value
StandardBasicTypes.STRING.nullSafeSet(preparedStatement, jsonObject.toString(), index, session)
}
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value
}
#Override
public boolean isMutable() {
return false
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value
}
#Override
public Object assemble(Serializable cached, Object value) throws HibernateException {
return cached
}
#Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original
}
#Override
public String objectToSQLString(Object object) {
throw new UnsupportedOperationException()
}
#Override
public String toXMLString(Object object) {
return object.toString()
}
#Override
public Object fromXMLString(String string) {
return new JSONObject(string)
}
}
class MyDomain{
JSONElement content
static constraints = {
content nullable: false, blank: false, sqlType: "text" // adapter from Map to String??
}
def setContent(String textContent){
content = JSON.parse(textContent)
}
}
I had to do 2 things.
replace def content with JSON content so that it gets persisted, see Grails Domain Constructor is not Groovy Constructor
Convert a json string back to json via def setContent().
As content is JSONElement use JSONObject and JSONArray as concrete classes.
I'm stuck. I have an existing application with an extremely large database and extensive library of stored procedures and functions. All I want to do is use a DbContext to execute a stored procedure and return a set of data or map to one of the entities in the context. Is that something magical I haven't discovered on the net somewhere? Someone, anyone, please help. Here's what I've got so far (and it doesn't return anything, the result is -1):
var contacts = db.Database.ExecuteSqlCommand("Contact_Search #LastName, #FirstName",
new SqlParameter("#LastName", GetDataValue(args.LastName)),
new SqlParameter("#FirstName", GetDataValue(args.FirstName)));
Executing that returns -1. I also tried something to the effect of this with no success:
DbRawSqlQuery<Contact> data = db.Database.SqlQuery<Contact>
("EXEC Contact_Search #LastName, #FirstName",
GetDataValue(args.LastName),
GetDataValue(args.FirstName));
I understand that I could add an edmx and map to a stored procedure that way, but that is not the preferred method. Again, our database contains nearly 450 million records and a library of almost 3,000 stored procedures and functions. It would be a nightmare to maintain. Am I even starting in the right direction? Is Entity Framework the right choice?
Wow, it seems right after I give up, I somehow stumble upon the answer. I found a FANTASTIC post about executing stored procedures and after reading up, this was my solution:
var contacts = db.Database.SqlQuery<Contact>("Contact_Search #LastName, #FirstName",
So, many thanks to Anuraj for his excellent post! The key to my solution was to first use SqlQuery instead of ExecuteSqlCommand, and also to execute the method mapping to my entity model (Contact).
This code is better than SqlQuery() because SqlQuery() doesn't recognise the [Column] attribute.
Here it is on a silver platter.
public static class StoredProcedureExtensions {
/// <summary>
/// Execute Stored Procedure and return result in an enumerable object.
/// </summary>
/// <typeparam name="TEntity">Type of enumerable object class to return.</typeparam>
/// <param name="commandText">SQL query.</param>
/// <param name="parameters">SQL parameters.</param>
/// <param name="readOnly">Determines whether to attach and track changes for saving. Defaults to true and entities will not be tracked and thus a faster call.</param>
/// <returns>IEnumerable of entity type.</returns>
public static IEnumerable<TEntity> GetStoredProcedureResults<TEntity>(this DbContext dbContext, string query, Dictionary<string, object> parameters, bool readOnly = true) where TEntity : class, new()
{
SqlParameter[] sqlParameterArray = DbContextExtensions.DictionaryToSqlParameters(parameters);
return dbContext.GetStoredProcedureResults<TEntity>(query, sqlParameterArray, readOnly);
}
/// <summary>
/// Execute Stored Procedure and return result in an enumerable object.
/// </summary>
/// <typeparam name="TEntity">Type of enumerable object class to return.</typeparam>
/// <param name="commandText">SQL query.</param>
/// <param name="parameters">SQL parameters.</param>
/// <param name="readOnly">Determines whether to attach and track changes for saving. Defaults to true and entities will not be tracked and thus a faster call.</param>
/// <returns>IEnumerable of entity type.</returns>
public static IEnumerable<TEntity> GetStoredProcedureResults<TEntity>(this DbContext dbContext, string commandText, SqlParameter[] sqlParameterArray = null, bool readOnly = true) where TEntity : class, new()
{
string infoMsg = commandText;
try
{
//---- For a better error message
if (sqlParameterArray != null)
{
foreach (SqlParameter p in sqlParameterArray)
{
infoMsg += string.Format(" {0}={1}, ", p.ParameterName, p.Value == null ? "(null)" : p.Value.ToString());
}
infoMsg = infoMsg.Trim().TrimEnd(',');
}
///////////////////////////
var reader = GetReader(dbContext, commandText, sqlParameterArray, CommandType.StoredProcedure);
///////////////////////////
///////////////////////////
List<TEntity> results = GetListFromDataReader<TEntity>(reader);
///////////////////////////
if(readOnly == false)
{
DbSet entitySet = dbContext.Set<TEntity>(); // For attaching the entities so EF can track changes
results.ForEach(n => entitySet.Attach(n)); // Add tracking to each entity
}
reader.Close();
return results.AsEnumerable();
}
catch (Exception ex)
{
throw new Exception("An error occurred while executing GetStoredProcedureResults(). " + infoMsg + ". Check the inner exception for more details.\r\n" + ex.Message, ex);
}
}
//========================================= Private methods
#region Private Methods
private static DbDataReader GetReader(DbContext dbContext, string commandText, SqlParameter[] sqlParameterArray, CommandType commandType)
{
var command = dbContext.Database.Connection.CreateCommand();
command.CommandText = commandText;
command.CommandType = commandType;
if (sqlParameterArray != null) command.Parameters.AddRange(sqlParameterArray);
dbContext.Database.Connection.Open();
var reader = command.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
}
private static List<TEntity> GetListFromDataReader<TEntity>(DbDataReader reader) where TEntity : class, new()
{
PropertyInfo[] entityProperties = typeof(TEntity).GetProperties();
IEnumerable<string> readerColumnNames = (reader.GetSchemaTable().Select()).Select(r => r.ItemArray[0].ToString().ToUpper()); // uppercase reader column names.
List<MappingPropertyToColumn> propertyToColumnMappings = GetPropertyToColumnMappings<TEntity>(); // Maps the entity property names to the corresponding names of the columns in the reader
var entityList = new List<TEntity>(); // Fill this
while (reader.Read())
{
var element = Activator.CreateInstance<TEntity>();
foreach (var entityProperty in entityProperties)
{
MappingPropertyToColumn mapping = propertyToColumnMappings._Find(entityProperty.Name);
if (mapping == null) // This property has a [Not Mapped] attribute
{
continue; // Skip this one
}
var o = (object)reader[mapping.ColumnName]; // mapping must match all mapped properties to columns. If result set does not contain a column, then throw error like EF would.
bool hasValue = o.GetType() != typeof(DBNull);
if (mapping.IsEnum && hasValue) // Enum
{
entityProperty.SetValue(element, Enum.Parse(mapping.UnderlyingType, o.ToString()));
}
else
{
if (hasValue)
{
entityProperty.SetValue(element, ChangeType(o, entityProperty.PropertyType));
}
}
}
entityList.Add(element);
}
return entityList;
}
public static object ChangeType(object value, Type conversion)
{
var t = conversion;
if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
if (value == null)
{
return null;
}
t = Nullable.GetUnderlyingType(t);
}
return Convert.ChangeType(value, t);
}
private static List<MappingPropertyToColumn> GetPropertyToColumnMappings<TEntity>() where TEntity : new()
{
var type = typeof(TEntity);
List<MappingPropertyToColumn> databaseMappings = new List<MappingPropertyToColumn>();
foreach (var entityProperty in type.GetProperties())
{
bool isEnum = entityProperty.PropertyType.IsEnum;
// [Not Mapped] Not Mapped Attribute
var notMapped = entityProperty.GetCustomAttributes(false).FirstOrDefault(attribute => attribute is NotMappedAttribute);
if (notMapped != null) // This property has a [Not Mapped] attribute
{
continue; // Skip this property
}
// Determine if property is an enum
Type underlyingType = null;
if (entityProperty.PropertyType.IsGenericType && entityProperty.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
underlyingType = Nullable.GetUnderlyingType(entityProperty.PropertyType); ;
if (underlyingType != null && underlyingType.IsEnum)
{
isEnum = true;
}
}
// [Column("tbl_columnname")] Column Name Attribute for mapping
var columnMapping = entityProperty.GetCustomAttributes(false).FirstOrDefault(attribute => attribute is ColumnAttribute);
if (columnMapping != null)
{
databaseMappings.Add(new MappingPropertyToColumn { PropertyName = entityProperty.Name, ColumnName = ((ColumnAttribute)columnMapping).Name.ToUpper(), IsEnum = isEnum, UnderlyingType = underlyingType }); // SQL case insensitive
}
else
{
databaseMappings._AddProperty(entityProperty.Name, entityProperty.Name, isEnum); // C# case sensitive
}
}
return databaseMappings;
}
//====================================== Class for holding column mappings and other info for each property
private class MappingPropertyToColumn
{
private string _propertyName;
public string PropertyName
{
get { return _propertyName; }
set { _propertyName = value; }
}
private string _columnName;
public string ColumnName
{
get { return _columnName; }
set { _columnName = value; }
}
private bool _isNullableEnum;
public bool IsEnum
{
get { return _isNullableEnum; }
set { _isNullableEnum = value; }
}
private Type _underlyingType;
public Type UnderlyingType
{
get { return _underlyingType; }
set { _underlyingType = value; }
}
}
//======================================================= List<MappingPropertyToColumn> Extension methods
#region List<MappingPropertyToColumn> Extension methods
private static bool _ContainsKey<T>(this List<T> list, string key) where T : MappingPropertyToColumn
{
return list.Any(x => x.PropertyName == key);
}
private static MappingPropertyToColumn _Find<T>(this List<T> list, string key) where T : MappingPropertyToColumn
{
return list.Where(x => x.PropertyName == key).FirstOrDefault();
}
private static void _AddProperty<T>(this List<T> list, string propertyName, string columnName, bool isEnum, Type underlyingType = null) where T : MappingPropertyToColumn
{
list.Add((T)new MappingPropertyToColumn { PropertyName = propertyName, ColumnName = columnName, IsEnum = isEnum, UnderlyingType = underlyingType }); // C# case sensitive
}
#endregion
#endregion }
I'm using grails 2.3.4 and I have a domain class that embeds an object. The embedded object has a property called 'version' and it seems that this is conflicting with the 'version'-field automatically added to the database-table by GORM. The result is that the 'version'-field belonging to my embedded object isn't created in the database and as a consequence my application doesn't work properly.
My code looks like this:
class Thing {
String someText
EmbeddedThing embeddedThing
Date someDate
static embedded = ['embeddedThing']
static constraints = {
embeddedThing(unique: true)
}
}
class EmbeddedThing {
String textOfSomeSort
String version
String textOfSomeOtherSort
}
You might think that a quick fix is to rename the 'version'-property of the embedded object but the class belongs to an included sub-project (i.e. a JAR-file) that I'm not allowed to touch since other projects use it. So the solution needs to be done completely within my domain class, or at least in a manner that doesn't change the class of the embedded object.
version is a special column name, you should rename your version field within your EmbeddedThin class
I actually found a solution to this problem by using a Hibernate UserType to represent the EmbeddedThing-class.
My code now looks like this and works perfectly:
Thing.groovy:
import EmbeddedThingUserType
class Thing {
String someText
EmbeddedThing embeddedThing
Date someDate
static embedded = ['embeddedThing']
static mapping = {
version false
embeddedThing type: EmbeddedThingUserType, {
column name: "embedded_thing_text"
column name: "embedded_thing_version"
column name: "embedded_thing_other_text"
}
}
static constraints = {
embeddedThing(unique: true)
}
}
EmbeddedThing.groovy:
class EmbeddedThing {
String textOfSomeSort
String version
String textOfSomeOtherSort
}
EmbeddedThingUserType.groovy:
class EmbeddedThingUserType implements UserType {
int[] sqlTypes() {
return [StringType.INSTANCE.sqlType(),
StringType.INSTANCE.sqlType(),
StringType.INSTANCE.sqlType()]
}
Class returnedClass() {
return EmbeddedThing
}
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner)
throws HibernateException, SQLException {
if (resultSet && names) {
return new EmbeddedThing(
textOfSomeSort: resultSet?.getString(names[0] ?: '_missing_textOfSomeSort_'),
version: resultSet?.getString(names[1] ?: '_missing_version_'),
textOfSomeOtherSort: resultSet?.getString(names[2] ?: '_missing_textOfSomeOtherSort_'))
} else {
return null
}
}
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index)
throws HibernateException, SQLException {
if (value != null) {
preparedStatement.setString(index, value?.textOfSomeSort)
preparedStatement.setString(index + 1, value?.version)
preparedStatement.setString(index + 2, value?.textOfSomeOtherSort)
} else {
preparedStatement.setString(index, '_missing_textOfSomeSort_')
preparedStatement.setString(index + 1, '_missing_version_')
preparedStatement.setString(index + 2, '_missing_textOfSomeOtherSort_')
}
}
#Override
public boolean isMutable() {
return false
}
#Override
public boolean equals(Object x, Object y) throws HibernateException {
return x.equals(y)
}
#Override
public int hashCode(Object x) throws HibernateException {
assert (x != null)
return x.hashCode()
}
#Override
public Object deepCopy(Object value) throws HibernateException {
return value
}
#Override
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original
}
#Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value
}
#Override
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached
}
}
Config.groovy:
grails.gorm.default.mapping = {
'user-type'( type: EmbeddedThingUserType, class: EmbeddedThing)
}
Please try version false in your 'static mapping', for the 'EmbeddedThing' class.