Can I rename GORM's "version" field? (Grails 2.2 + GORM MongoDB) - mongodb

I've got a domain object that already has a property called versions, so I'd like to give a different name to the built-in version property (used in GORM for optimistic locking). For instance, I'd like to call it updateCount instead.
Note that I do want the semantics of optimistic locking; I just want to give the field another name. Here's what I've naively tried (and it didn't work):
class Item {
ObjectId id
static hasMany = [versions: ItemVersion]
static mapping = {
table 'item'
version column: 'updateCount' // <-- This was my attempt
}
}
I would definitely appreciate any help in...
Determining whether this is possible, and
If so, making it work :-)
Thanks!

First thing first. MongoDB (NoSQL) deals with Documents and Collections instead of Table and rows.
Being said that, the domain class should look like:
class Item {
ObjectId id
String itemName
static hasMany = [versions: ItemVersion]
static mapping = {
//Collection in Mongodb is to Table in relational world
collection 'item'
//attr in Mongodb is to column in relational world
itemName attr: 'item_name'
//After spending some time investigating it was found that
//attr for version does not make any difference
//The below would not work for implicit GORM variable "version"
//default attribute name is the variable name.
//version attr: 'updateCount'
}
}
In case you want to configure default property across the domains to switch on/off the versioning then have a look at Global Mapping Configuration.

Related

In Objection.js, what's the benefit of setting up relationMappings?

I'm kind of confused about what relationMappings do inside a Objection.js Model class.
I thought once we setup the relationMapping inside a Model, we will get related data in every query. But, it turns out that I still only the Model properties itself.
Is there anything else I should use to get related data in query?
Relation mappings gives model semantics how relations can be fetched when they are needed. It would be really bad for performance to always query all related rows in addition to main table's row. When you create relation mappings to model, you will not need to write joins manually every time you need to query relations. Also they enable many other objection features, which requires information how row relations goes in DB.
To use relation mappings in query Objection.js requires that within every query you must tell which relations you want to fetch with the main row with .withGraphFetched or .withGraphJoined methods https://vincit.github.io/objection.js/guide/query-examples.html#eager-loading
for example:
class Person extends Model {
static get tableName() {
return 'persons';
}
static get relationMappings() {
return {
pets: {
relation: Model.HasManyRelation,
modelClass: Animal,
join: {
from: 'persons.id',
to: 'animals.ownerId'
}
}
};
}
}
const people = await Person.query().withGraphFetched('pets');
// Each person has the `pets` property populated with Animal objects related
// through the `pets` relation.
console.log(people[0].pets[0].name);
console.log(people[0].pets[0] instanceof Animal); // --> true
Mappings are also used when you insert nested object data with .insertGraph so that related objects are inserted to related tables and foreign key references etc. are automatically filled according to relation mapping declarations.
There are many other places where those are used, but I hope this gives a rough idea why they exist.

Selected Updates in Nested AppSync Schema

I am trying to carry out selected upates of individual nested fields with a DynamoDB table which is connected to an AppSync interface. I am able to update individual top level fields but when it comes to nested fields I am unsure how to approach. I am a newbie to this so perhaps I am thinking about this wrong and I need to flatten the data through the schema so that the data is flat in the DynamoDb tables. I have struggled to find an example of how to tackle this kind of situation with fairly complex tables. I am using the Custom Types to bring some standardisation across the App and different resolvers/.
We have a AppSync Schema defined approximately like this
type Main_entries {
id: String!
title: String!
recordInfo: CustomType
}
Type CustomType {
fieldA: String
fieldB: String
fieldC: String
}
What I have are some main types but also some Custom Types used throughout the application. What I want to be able to do is to update fieldB whilst keeping the rest of the data intact.
I have used the UpdateItem approach here
With this I can say update title whilst keeping the rest of the record intact but if my Mutation instructs fieldB to be updated a SET is created to update the entire recordInfo type so fieldA and fieldC are omitted.
Does anyone know of any ideas or even better know where there may be some examples.
Many thanks in advance.

Eloquent Friendly Column Name

We're currently transitioning from one database to another. A table in our legacy database has column names that are less than ideal, for example:
some_crazy_name__xyz
In our new database, we'd like to have a column name like:
someCrazyName
In the short term, we have to work with data from our legacy database. At some point in the near future, we'd like to switch over without having to refactor all of our Eloquent code to query for different column names. For example:
$model = MyModel::where('someCrazyName', '=', 1);
I'm currently extending the Model class, where all implementing models provide a map of terrible names to friendly names:
class MyModel extends BaseModel {
$columnMap = array(
'someCrazyName' => 'some_crazy_name__xyz'
);
}
This works well where I can use __get and __set in BaseModel to lookup properties in my map, for example:
$myModel = new MyModel;
// ...
echo $myModel->someCrazyName;
However, this obviously doesn't work well with queries without having to always use my map to look up column names. I'm wondering if it's possible without having to override all of the methods within Illuminate\Database\Eloquent\Model, Illuminate\Database\Query\Builder and Illuminate\Database\Eloquent\Builder that deal with columns, where the underlying query that is built always maps to the correct column? Then after we transition databases, we can remove that one piece of code rather then remove potentially thousands of column name mappings.
This is what you need: https://github.com/jarektkaczyk/eloquence/wiki/Mappable
It's not only for mapping badly_named_columns to something_useful, but also can be used for relational mappings:
// simple aliasing
User::where('cool_name', 'value') // where badName = ?
// relations, eg. User hasOne Profile
User::where('first_name', 'Jon') // search through related profiles table
// and obviously mutators:
$user->first_name == $user->profile->first_name
$user->cool_name = 'Jon' // becomes $user->badName = 'value'
$user->cool_name; // 'Jon'
One way to do it would be with accessors.
For example, in MyModel you could define an accessor for the some_crazy_name__xyz column like this:
public function getSomeCrazyNameAttribute()
{
return $this->attributes['some_crazy_name__xyz'];
}
You can then transparently refer to that column with $mymodel->someCrazyName. You can also define a mutator to set the value.
Admittedly, this may not be the best solution if you have MANY values like this. But it does have one important benefit: later on, if you refactor your database so that the column some_crazy_name__xyz is actually called someCrazyName, all you need to do is remove that function from your model. And, to my mind at least, it's simpler than trying to override a bunch of methods on the various classes involved.
And unfortunately, it doesn't adequately address the use of column names in queries. For that, you might want to look at the repository pattern. But in any event, it looks like there's going to be a lot of coding involved.
Finally, you haven't mentioned what database you're using. If it's MySQL, it is possible to create updatable and insertable views. Using a view, you could simply map old column names to new, and point your Eloquent model at the view instead of a table. Other database servers may provide similar functionality.

Create index in correct collection

I annotate a document with #Index(unique = true) like so:
public class ADocumentWithUniqueIndex {
private static final long serialVersionUID = 1L;
#Indexed(unique = true)
private String iAmUnique;
public String getiAmUnique() {
return iAmUnique;
}
public void setiAmUnique(String iAmUnique) {
this.iAmUnique = iAmUnique;
}
}
When saving the object, I specify a custom collection:
MongoOperations mongoDb = ...
mongoDb.save(document, "MyCollection");
As a result I get:
A new document in "MyCollection"
An index in the collection "ADocumentWithUniqueIndex"
How can I create the index in "MyCollection" instead without having to explicitly specify it in the annotation?
BACKGROUND:
The default collection name is too ambiguous in our use case. We cannot guarantee, that there wouldn't be two documents with the same name but in different packages. So we added the package name to the collection.
Mapping a document to a collection is dealt with in an infrastructure component.
The implementation details like collection name etc. shouldn't leak into the individual documents.
I understand this is a bit of an "abstraction on top of an abstraction" smell but required since we had to support MongoDb and Windows Azure blob storage. Not anymore though...
This seemed like a fairly standard approach to hide the persistence details in a infrastructure component. Any comments on the approach appreciated as well.
It's kind of unusual to define the collection for an object to be stored and then expect the index annotations to work. There's a few options you have here:
Use #Document on ADocumentWithUniqueIndex and configure the collection name manually. This will cause all objects of that class to be persisted into that collection of course.
Manually create indexes via MongoOperations.indexOps() into the collections you'd like to use. This would be more consistent to your approach of manually determining the collection name during persistence operations.

Combine columns in entity framework into one column with the edmx designer

I'm using EntityFramework 5 EDMX designer and would like to combine the first & last name of a person into a single field value (name, for instance) on the entity.
I thought in previous versions there was a way to do this, but I don't see anything available to do what I need to do.
Is this still possible?
Unless I'm not understanding your question, I believe I've done that with a partial class that resembles something like the following:
public partial class person
{
public string name {
get
{
return firstname + " " + lastname;
}
set{ }
}
}
No it is not possible. You can create model defined function and use it in queries but it will still not be part of your entity. If your entity is read only you can create database view with combined column and map it instead of the table - it shows also main reason why combining columns into single property is not such easy task. Automatic concatenating during reading is easy but automatic decomposing to save correct value into correct column is hard and error prone.
If you need combined property for anything else than querying you can simply create another partial part of your entity class and add your own computed property. If you need the combined property for querying use the model defined function.
The way I do this is through a Computed Column as explained here:
How to make a computed column nullable in SQL Server
If you use a computed column you'll be able to use such a column in your LINQ queries. For example:
var users = Database.Users.Where(u => u.FullName.ToLower().Contains("string"));
You won't get errors like "not supported in LINQ to Entities" because this property is really a part of your model object. All the heavy lifting occurs on the database side.
Of course you could place a FullName property in a partial class and use it.
public string FullName
{
get { return string.Format("{0} {1}", FirstName, LastName); }
}
In this case, you'll have to call .ToList() first ( Database.Users.ToList(); ) to be able to use this property in LINQ queries. .ToList() will hydrate/bring all your Users to memory. This is not desirable!
You can also try the FullName property implementation that's described here: Calculated Columns in Entity Framework Code First Migrations