Grails iterating through database tables - database

As I'm a bit new to Grails, I'm wondering how I can iterate through the current data i have saved in the database to check if the information already exists.
For instance, lets say I have a domain class for Books and I create an action that automatically adds more books but I want to check if the book.title already exists so I don't add it again.
Side note
I'm just using the default database (whatever is used when the project is set to production mode)
Edit
I'll post my domains so it is a bit easier to understand. Instead of book.title, I changed it to where book belongs to author. So I only want the author added once but able to add many books for it. The issue happens in an action i created in the controller.
Author Domain:
class Author {
static hasMany = [books:Book]
String authorName
String notes
String age
String toString() { authorName }
static constraints = {
authorName()
notes(maxSize:500)
age()
}
}
Book Domain:
class Book {
static belongsTo = Author
String toString() { bookNumber }
Author bookAuthor
String title
String numberOfPages
static constraints = {
bookAuthor()
title()
numberOfPages()
}
}
Book Controller (this is where I'm having issues):
class BookController {
static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
//took out index, create, list, etc. to focus on the once that I'm concerned about
//this action will simple read a text file and add books and authors
def gather = {
def parseData = new parseClient() //parses text file line by line and puts it into a list
def dataHolder = parseData.information //dataHolder will hold data from text file
int linesOfData = dataHolder.size() //get size to iterate and add authors & books
linesOfData.times {
def _author = dataHolder.author[it] //get author - Author
def _age = dataHolder.age[it] //get age - Author
def _title = dataHolder.title[it] //get title - Book
def _pages = dataHolder.pages[it] //get pages - Book
def authorInstance //create new Author to add
authorInstance = new Author() //for some reason I have to create and save AuthorName (can't have other fields) before I can add my Book correctly
authorInstance.setAuthorName(_author)
authorInstance.save()
def bookInstance
bookInstance = new Book() //create a new Book to add
bookInstance.setBookAuthor(authorInstance)
bookInstance.setTitle(_title)
bookInstance.setNumberOfPages(_pages)
bookInstance.save() //has to have access to the authorInstance to add correctly which is why i was wondering how to access the database to grab it if it existed
authorInstance.setAge(_age) //add whatever data is left for Author
authorInstance.save() //save again because cant save it with this information before I add authorInstance to the Book
}
}
}
Text File Content:
//You'll notice that author _Scott Davis_ is in here twice.
//I don't want to add two instances of Scott Davis but need to access it to add the book
//the unique constraint makes the value come up as not null but can't be added
Scott Davis : Groovy Recipes
Bashar Abdul Jawad : Groovy and Grails Recipes
Fergal Dearle : Groovy for Domain-Specific Languages
Scott Davis : GIS for Web Developers: Adding 'Where' to Your Web Applications
So I'm basically looking for a way to add that information and haven't found a way that seems to work without running into random problems.
Hope this clears my question up a bit, as the original question was a bit broad

In this case, you can put a unique constraint on title and grails will do that for you.
You can iterate thru the data, but you probably don't want to load the db if you can avoid it. So you could write a custom query to select the number of books for the title, for example.
Edit: for your updates
You don't need to use setters in your controller. Grails adds setters/getters for you dynamically at runtime. If you want to put some logic in your setters, then you can define your own and use them in that case
Have you looked at the grails documentation? http://grails.org/doc/latest/
you have a static constraints block, but you haven't defined how you want each property to be constrained. for unique title it would be
title(unique:true)
if you want to get a list of author names, you can do
List names = Author.executeQuery('select authorName from Author')

Related

Use two completely different classes as one

I have very stupid question about design patterns: let's say we have two classes Post and Product, for each of them we have different table in the DB, and they have nothing in common with each other, so we can't create base class for them. Some Posts even contains Products. And here's what we should do with them:
Somehow store Post and Product instances in the DB, pack them in one array(using C++, if it matters) when user requests news feed from the next item, send it to the client, and receive and unpack on the client side(using Java).
Next, we have to show both Post and Product in the one list(such as news feed on the Facebook).
Also, we can share Post or Product with our friends using chat. So we can send Post or Product as an attachment of the message(consequently, we should to store id of sent Post or Product in the column attached_item of the messages table in the DB on the server side).
So, what design pattern would be best here? How should I implement the Post and Product classes?
It is a very broad question, but here is a skeleton of what you could you, just to give you some ideas:
// An interface containing methods specific to objects you can list
interface Listable {}
// An interface containing methods specific to objects you can share
interface Shareable {}
// An interface containing methods specific to objects you can send
interface Sendable {}
class Post implements Listable, Shareable, Sendable {
List<Product> products;
}
class Product implements Listable, Shareable, Sendable {
}
class ListManager {
public void addToList(Listable element) { }
}
class ShareManager {
public void share(Shareable element) { }
}
class SendManager {
public void send(Sendable element) { }
}
You could then use Post and Product interchangeably this way:
Post post = new Post();
Product product = new Product();
ListManager listManager = new ListManager();
listManager.addToList(post);
listManager.addToList(product);
ShareManager shareManager = new ShareManager();
shareManager.share(post);
shareManager.share(product);
SendManager sendManager = new SendManager();
sendManager.send(post);
sendManager.send(product);
Regarding the database representation, as suggested fusiled in his comment, just stick them in 2 separate tables. With a mapping table in between to link the products to their post.
EDIT
Regarding the issue with the MESSAGES table
You could add a new mapping table MESSAGE_ATTACHED_ITEM with columns messageId, postId, productId. Only set a value to the relevant colum when attaching an item to a message
Or an other option would be to have an ATTACHED_ITEM table with an id only.
And have Post and Product tables to have a foreign key to this table Id.
you can then stick this attachedItemId into your attached_item column
I think the solution could be simpler than you think. Why don't you ust use a common Java-like interface and hide the implementation details?
Just implement a common interface with the methods you need. Supposing this common interface is called EntityInterface:
public class Post implements EntityInterface {};
public class Product implements EntityInterface {};
Then when you want to handle these classes, you treat them as an EntityInterface object:
EntityInterface myNewPost = new Post();
EntityInterface myNewProduct = new Product();
//Now you see myNewProduct and myNewPost as EntityInterface objects
These code fragments are in Java, but use virtual functions in C++ and you get the same.

Create Class object through class name in Salesforce

I am new to Salesforce and want to code one requirement, I have an api name in string variable through which I want to create an object of that class.
For Eg. Object name is Account which is stored in string variable.
String var = 'Account'
Now I want to create object of 'Account'. In java it is possible by Class.forName('Account') but similar approach is not working in Salesforce Apex.
Can anyone please help me out in this.
Have a look at Type class. The documentation for it isn't terribly intuitive, perhaps you'll benefit more from the article that introduced it: https://developer.salesforce.com/blogs/developer-relations/2012/05/dynamic-apex-class-instantiation-in-summer-12.html
I'm using this in managed package code which inserts Chatter posts (feed items) only if the org has Chatter enabled:
sObject fItem = (sObject)System.Type.forName('FeedItem').newInstance();
fItem.put('ParentId', UserInfo.getUserId());
fItem.put('Body', 'Bla bla bla');
insert fItem;
(If I'd hardcode the FeedItem class & insert it directly it'd mark my package as "requires Chatter to run").
Alternative would be to build a JSON representation of your object (String with not only the type but also some field values). You could have a look at https://salesforce.stackexchange.com/questions/171926/how-to-deserialize-json-to-sobject
At the very least now you know what keywords & examples to search for :)
Edit:
Based on your code snippet - try something like this:
String typeName = 'List<Account>';
String content = '[{"attributes":{"type":"Account"},"Name":"Some account"},{"attributes":{"type":"Account"},"Name":"Another account"}]';
Type t = Type.forName(typeName);
List<sObject> parsed = (List<sObject>) JSON.deserialize(content, t);
System.debug(parsed);
System.debug(parsed[1].get('Name'));
// And if you need to write code "if it's accounts then do something special with them":
if(t == List<Account>.class){
List<Account> accs = (List<Account>) parsed;
accs[1].BillingCountry = 'USA';
}

Entity Framework Attach not updating DB

I have the following problem: when i try to change the town of a user by passing the modified user entry to my ModifyUser method in my UserService class everything seems ok but the changes are not applied in the database.
I tried the solutions from similar problems i found on stackoverflow but none of them seem to work.
As they say "a picture is worth a thousand words" take a look at this, since its easier to understand compared to my short explanation.
http://prntscr.com/el51z0
else if (property == "BornTown")
{
if (this.townService.TownExists(value))
{
User user = this.userService.GetUserByName(username);
Town town = this.townService.GetTownByName(value);
user.BornTown = town;
this.userService.ModifyUser(user);
}
else
{
Console.WriteLine($"Value {value} is not valid.");
throw new ArgumentException($"Town {value} not found!");
}
}
When i pass the user to the ModifyUser the database does not update, and BornTown stays NULL.
public void ModifyUser(User user)
{
using (PhotoShareContext context = new PhotoShareContext())
{
context.Users.Attach(user);
context.Entry(user).State = EntityState.Modified;
context.SaveChanges();
}
}
Or else try below code:
User user = context.users.where(x=>x.username == username).FirstOrDefault();
user.BornTown = town; //string
context.savechanges();
Can you try
context.Users.where(x=>x.username == username).FirstOrDefault();
and don't use any()
Can you check if you are getting the proper username, by again checking the username once you are getting back the value in the function.
Instead of manipulating the navigation properties directly try to manage the entity relation using it's foreign keys:
Town town = this.townService.GetTownByName(value);
user.BornTownId = town.Id;
Keep in mind that if you have not created explicit foreign keys in your model entity you should map the existing one: take a look at "Users" table - see how the foreign key column is named- it should look something like UserTown_Id. Then put it in your model class (you may add foreign key attribute or map it in model builder).
Be careful when adding the new property to your model (it can make your optional relation with "Towns" required).

Replace Django ManyToMany fields with chained strings or convert to first normal form

Suppose that I have a Position table that specifies a user's position (leader, assistant, member, ...):
class Position(models.Model):
name = CharField(max_length=20)
A document has a title and privileges, namely, create, modify, and so on. We may specify which user positions may perform which privileges; e.g., a leader or an assistant may create a document:
class Document(models.Model):
title = CharField(max_length=50)
create = ManyToManyField(Position)
modify = ManyToManyField(Position)
...
Of course, the above arrangement is not acceptable in Django because there should be only one ManyToManyField in a model.
I wonder which one of the followings is a better solution:
(a) Chain the positions (provided the number of positions are not great and the position data will not change):
class = Document(...):
...
create = CharField(max_length=100)
modify = CharField(max_length=100)
where create may be leader-assistance-member, which means a leader, an assistance, or a member may create a document. All we have to do is to split the string to obtain a list of positions.
(b) Convert to 1NF:
class = Document(...)
title = ...
class Create(...):
document = ForeignKey(Document)
position = ForeignKey(Position)
class Modify(...):
document = ForeignKey(Document)
position = ForeignKey(Position)
I know this question is old, but per Django docs, you could have multiple many-to-many fields referencing the same model. You'd just need to specify a related_name to differentiate them.
class Document(models.Model):
title = models.CharField(max_length=50)
create = models.ManyToManyField(Position, related_name='create_positions')
modify = models.ManyToManyField(Position, related_name='modify_positions')
...

How to set a ReferenceProperty using only a Key, not getting the Model

I want to be able to, given the key to a model in the datastore, simply set the referenceproperty without loading the model itself (as I don't need that information).
For example:
class Book(db.Model):
author = db.StringProperty()
title = db.StringProperty()
class Review(db.Model):
book = db.ReferenceProperty(Book)
description = db.StringProperty()
Assuming that I already have the key to a Book (call it bookKey), but I don't have the corresponding Book object itself, is there a way to do the equivalent of
review = Review()
review.description = "It was ok, but I would recommend it for insomniacs."
review.book = bookKey
or do I need to
book = Book.get(bookKey) #I don't want this datastore access
#as I don't need the book object.
review = Review()
review.description = "It was ok, but I would recommend it for insomniacs."
review.book = book
I've found the way to extract the key and ID from the ReferenceProperty using get_value_for_datastore, but I'm after a "set".
review.book = bookKey will work just fine, and set the referenceproperty without fetching the model.

Resources