I wish to create a custom model that I can reference later: The model is simply a list of countries and their metrics. When the model is created I would like to access it similar to:
Countries('au').population
I have created the class below however beyond this I am unsure of how to initialise the model with the data. I believe I need to have a map of Country instances?
class Country {
final String code;
final String name;
final int population;
Country({
this.code,
this.name,
this.population,
});
Map Countries = {'au': new Country('code': 'au', 'name': 'Australia', population: 25000000),
'uk': new Country('code': 'uk', 'name': 'United Kingdom', 'population': 66000000)}
}
You should use a factory constructor to initialize your class and have all the models in a static method.
class Country {
final String code;
final String name;
final int population;
Country._({
this.code,
this.name,
this.population,
});
factory Country(String code) => countries[code];
static final countries = {
'au': Country._(code: 'au', name: 'Australia', population: 25000000),
'uk': Country._(code: 'uk', name: 'United Kingdom', population: 66000000)
};
}
then you can do:
var population = Country('au').population; //Returns null if the code is not defined in the map.
Note: your code won't even compile since the parameters names don't need to be defined as string.
To initialize the model with the data:
Map<String,Country> countries = {'au':Country(code:'au',name:'Australia', population: 25000000),
'uk': Country(code:'uk',name: 'United Kingdom', population: 66000000)};
To access it later and get Australia population:
Country australia=countries['au'];
int populationOfAustralia=australia.population;
Related
I am working on a Flutter web app, and am using a custom class to keep track of form data. I am instantiating a new instance of the following class:
class Contact {
String name;
String relationship;
String phoneNo;
#override
String toString() {
print("""{
Name: $name,
Relation: $relationship,
Phone: $phoneNo
}""");
}
}
In my controller, once I instantiate, I am printing out the value immediately:
// Method in controller, triggered by onTap
Contact contact = Contact();
print(contact);
The output is:
{
Name: null,
Relation: null,
Phone: null
}
null
Which is causing issues later down the line, as instances of this class are being used as values of a HashMap. I have narrowed down the issue to being caused by the toString method, and when I remove it, Instance of 'Contact' is then printed out, as desired. What is the best way to handle this?
// Method in controller, triggered by onTap
Contact contact = Contact();
print(contact);
You created a new instance of Contact with no arguments that's why all the value of Contact will be null.
To assign a value there are two solutions:
1. Inside from class itself:
class Contact {
String name = 'John doe';
String relationship = 'Brother';
String phoneNo = '1234567890';
#override
String toString() {
print("""{
Name: $name,
Relation: $relationship,
Phone: $phoneNo
}""");
}
}
2.From outside of Class
for that, you have to initiate Constructor in your class
class Contact {
String name;
String relationship;
String phoneNo;
Contact(this.name, this.relationship, this.phoneNo);
//You can also choose between named parameters and positional parameters
// For named parameters Contact({this.name, and so on....})
#override
String toString() => """{
Name: $name,
Relation: $relationship,
Phone: $phoneNo
}""";
}
in this scenario you have to pass values where you create instance of class as shown here:
Contact contact = Contact('John Doe', 'brother', '123456789');
print(contact);
I have a post request from Angular.
addEmployee(Name: string, Address: string, Salary: number, CreateDate: string) {
const headers = new HttpHeaders().set('content-type', 'application/json');
const employee: EmployeeDataModel = { id: null, name: Name, address: Address, salary: Salary, createdate: CreateDate };
alert(employee);
this.http.post<{data: EmployeeDataModel}>(this.appuri + "api/employee", employee, {headers})
.subscribe((responseData) => {
employee.id = responseData.data.id;
this.employees.push(employee);
this.employeesUpdated.next([...this.employees]);
});
}
I can't read a request body in .net core backend.
[HttpPost]
public async Task<ActionResult<Employee>> AddEmployee([FromBody]Employee employee)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
dbContext.Employees.Add(employee);
await dbContext.SaveChangesAsync();
return CreatedAtAction("GetAllEmployees", new { id = employee.ID }, employee);
}
And i also have this error message in ModelState:
The JSON value could not be converted to System.Int32.
Path: $.id | LineNumber: 0 | BytePositionInLine: 10.
Can you help me please because i don't know what's wrong as i'm new to this.
Remove the id property from your request body, or set it to 0. The value null cannot be parsed to an int by the serializer.
const employee: Partial<EmployeeDataModel> = { name: Name, address: Address, salary: Salary, createdate: CreateDate };
// OR
const employee: EmployeeDataModel = { id: 0, name: Name, address: Address, salary: Salary, createdate: CreateDate };
The Partial<> is only to make sure typescript won't scream at you for ommitting the id property.
Note that setting it to a value other than 0 will mean that your DbContext will try to insert that value into the database, and unless your column in the database is not using IDENTITY (or has IDENTITY INSERT turned on), you will get an error again.
Is there a way to set a constructor optional param?
I mean something like:
User.fromData(this._name,
this._email,
this._token,
this._refreshToken,
this._createdAt,
this._expiresAt,
this._isValid,
{this.id});
It indicates that
Named option parameters can't start with an underscore.
But I need this field as private, so, I'm lost now.
This is a more general answer for future viewers.
Positional optional parameters
Wrap the optional parameter with [ ] square brackets.
class User {
String name;
int age;
String home;
User(this.name, this.age, [this.home = 'Earth']);
}
User user1 = User('Bob', 34);
User user2 = User('Bob', 34, 'Mars');
Optional parameters need to be nullable if you don't provide a default value:
class User {
String name;
int age;
String? home; // <-- Nullable
User(this.name, this.age, [this.home]);
}
Named optional parameters
Wrap the optional parameter with { } curly braces.
class User {
String name;
int age;
String home;
User(this.name, this.age, {this.home = 'Earth'});
}
User user1 = User('Bob', 34);
User user2 = User('Bob', 34, home: 'Mars');
The default for home is "Earth", but like before, if you don't provide a default then you need to change String home to String? home.
Private fields
If you need private fields then you can use [] square brackets:
class User {
int? _id;
User([this._id]);
}
User user = User(3);
or do as the accepted answer says and use an initializer list:
class User {
int? _id;
User({int? id})
: _id = id;
}
User user = User(id: 3);
Named required parameters
Named parameters are optional by default, but if you want to make them required, then you can use the required keyword:
class User {
final String name;
final int age;
final String home;
User({
required this.name,
required this.age,
this.home = 'Earth',
});
}
User user1 = User(name: 'Bob', age: 34);
User user2 = User(name: 'Bob', age: 34, home: 'Mars');
You need to use a simple parameter and initialize your private field in initializer list.
class User {
final String _id;
final String _name;
User.fromData(this._name, {required String id})
: _id = id;
}
In addition to great Suragch's answer I wanted to mention required word. You can use it for multiple constructor or function named parameters to specify required ones.
class User {
int _id;
String _firstName;
String _lastName;
User({required int id, String firstName = "", String lastName})
: _id = id, // required parameter
_firstName = firstName, // optional parameter with default value ""
_lastName = lastName; // optional parameter without default value
}
User user1 = User(id: 1);
User user2 = User(id: 2, firstName: "John");
User user3 = User(id: 3, lastName: "Snow");
Related Dart docs here.
For Dart version <= 2.10 #required is an annotation and used with the # prefix.
I'm trying to create a bi-directional relationship between two domains in Grails (parent-child) but i can't seem to make it work.
According to Grails GORM documentation oneToMany I should be able to create a hasMany(Parent) and a belongsTo(Child) between a parent and a child to create a bi-directional relationship but it just doesn't work for me.
I have the following two domains:
class Game {
String name
String description
Double price
}
class Review {
static belongsTo = [game: Game]
String reviewText
Date reviewDate
}
then i create a grails dbm-gorm-diff file.groovy i get a file with the following
databaseChangeLog = {
changeSet(author: "efx (generated)", id: "1456032538941-1") {
createTable(tableName: "game") {
column(name: "id", type: "int8") {
constraints(nullable: "false", primaryKey: "true", primaryKeyName: "gamePK")
}
column(name: "version", type: "int8") {
constraints(nullable: "false")
}
column(name: "description", type: "varchar(255)") {
constraints(nullable: "false")
}
column(name: "name", type: "varchar(255)") {
constraints(nullable: "false")
}
column(name: "price", type: "float8") {
constraints(nullable: "false")
}
column(name: "reviews_id", type: "int8") {
constraints(nullable: "false")
}
}
}
changeSet(author: "efx (generated)", id: "1456032538941-2") {
createTable(tableName: "review") {
column(name: "id", type: "int8") {
constraints(nullable: "false", primaryKey: "true", primaryKeyName: "reviewPK")
}
column(name: "version", type: "int8") {
constraints(nullable: "false")
}
column(name: "review_date", type: "timestamp") {
constraints(nullable: "false")
}
column(name: "review_text", type: "varchar(255)") {
constraints(nullable: "false")
}
}
}
changeSet(author: "efx (generated)", id: "1456032538941-4") {
createSequence(sequenceName: "hibernate_sequence")
}
changeSet(author: "efx (generated)", id: "1456032538941-3") {
addForeignKeyConstraint(baseColumnNames: "reviews_id", baseTableName: "game", constraintName: "FK_jnjkmccicsjmsvqub534xcnnm", deferrable: "false", initiallyDeferred: "false", referencedColumnNames: "id", referencedTableName: "review", referencesUniqueColumn: "false")
}
}
at this point everything is 'perfect' so to say so i run grials dbm-update so the changes get transferred to the DB, but then i want to make this relationship bi-directional therefore i update my Game domain with the 'hasMany' as follows
class Game {
static hasMany = [reviews: Review]
String name
String description
Double price
}
after making the changes to the Game domain i proceed to run grails dbm-gorm-diff fileupdated.groovy so i can finally create the bi-directional relationship but i get an empty migration file
databaseChangeLog = {
}
Note: even if put the 'hasMany" in the first migration on the Game domain I receive the same results, a relationship child-parent(reviews to game) is created, but the parent-child(game to reviews) doesn't get created. On the tutorial i was trying to follow it does work. I'm using grails 2.4.4.
Why is the oneToMany relationship not being created?
thank you,
efx
Edit:
-I create a Game example like below and receive id = 1
groovy:000> g = new com.pluralsight.Game([description: 'Game Desc', name: 'The Game', price: '1.99'])
===> com.pluralsight.Game : (unsaved)
groovy:000> g.save()
===> com.pluralsight.Game : 1
-Then i proceed to create 2 reviews for that game and receive review id 2 and 3
groovy:000> r = new com.pluralsight.Review([game: g, reviewDate: new Date(), reviewText: 'Review 1'])
===> com.pluralsight.Review : (unsaved)
groovy:000> r.save()
===> com.pluralsight.Review : 2
groovy:000> r2 = new com.pluralsight.Review([game: g, reviewDate: new Date(), reviewText: 'Review 2'])
===> com.pluralsight.Review : (unsaved)
groovy:000> r2.save()
===> com.pluralsight.Review : 3
-now if everything was done correctly with my bidirectional domains i should be able to query all my reviews from game but i get a null
groovy:000> retrieve = com.pluralsight.Game.get(1)
===> com.pluralsight.Game : 1
groovy:000> retrieve.reviews
===> null
therefore i'm not sure why my oneToMany from Game to Review is not working
Why do you expect the database to change?
What is important is to understand what Grails/GORM (and Hibernate) mean when talking about a bidirectional relationship.
A relationship is called bidirectional when both ends a the relationship have a reference to the other side. So the Game has a collection of Reviews and the Review has a reference to the Game. This is only talking about the application code. The database only needs 1 foreign key to fully store the relationship.
You could also use a join table, but that is really overkill in this case (in my opinion). But Grails/GORM allows it, just look in the docs how to map it in the static mapping section.
As you know, there are two forms of one-to-many associations: uni-directional and bi-directional. Both require static hasMany = .... It's only in the case of a bi-directional one-to-many association that static belongsTo = ... is used:
Uni-directional
class Game {
String name
String description
Double price
static hasMany = [reviews: Review]
}
class Review {
String reviewText
Date reviewDate
}
Bi-directional
class Game {
String name
String description
Double price
static hasMany = [reviews: Review]
}
class Review {
String reviewText
Date reviewDate
static belongsTo = [game: Game]
}
Database implementation
In the case of a uni-directional one-to-many, you'll end up with three tables: game, review, and game_review. The game_review table joins the other two tables by using two columns: the game ID and the review ID. The game and review tables remain isolated; they only have a relationship through the game_review table.
In a bi-directional one-to-many, you'll get two tables: game and review. However, the review table will contain a foreign key column: the game ID. There's no join table keeping the game and review tables independent of each other.
I hope that helps. You can read more about this in one of my articles.
I would like to thank #hansboogards and #emmanuelrosa for your time, i found a very interesting article about hibernate and the headaches it causes GORM Gotchas and found the reason i couldn't call from Game domain my reviews it was because hibernate haven't put them on the DB although i had done the save.
Even after a save() (without an explicit flush), this will print nulls. It’s only when you flush the session that the child domain instances have their IDs set. This is quite different to the many-to-one case we saw earlier, where you didn’t need an explicit flush for the Location instance to be persisted to the database! It’s important to realise that difference exists, otherwise you’ll be in for a hard time.
Let's say I have the following classes:
abstract class Fruit {
String name
static mapping = {
discriminator column: 'type'
}
class Banana extends Fruit {
static mapping = {
discriminator: 'Banana'
}
}
class Apple extends Fruit {
static mapping = {
discriminator: 'Apple'
}
}
I need to implement a search algorithm such that, given a JSON string, I can find a particular Fruit instance in the DB. For example:
{
"type": "Apple"
"name": "Green"
}
or
{
"type": "Banana"
"name": "Green"
}
Problem is, fruits can have the same name, so if I just do a search for this:
Fruit.getByName('Green')
It might return the Apple or the Banana. I need to be able to filter it by its type as well based on the type, something like:
Fruit.getByNameAndType('Green', 'Apple')
How do I do this in Grails?
Take a look at the generated database.
There will be a class column which you can use in a criteria search on your Fruit class.
Maybe this works as
Fruit.findAllByColorAndClassLike('Green','%Apple')
too
Apple.getByName('Green')
Should work. Have you tried that?
Should this meet your need?
def fruits = Fruit.findAll("from Fruit where type = :type and name = :name", [type: "Apple", name: "Green"])