how to add a record in a sub-level transaction using procedure in genexus without Business Componet - genexus

I'm just learning more about genexus and wanted to know if there was a way to do this.
As the title says, i just want to know how to add a sublevel Transaccion without using Business component, I have readed the majority of "new", "for each", "blocking" and other stuff on genexus wiki, but to no luck.
For example, let's say we have this transaccion:
Person
{
PersonId
PersonName
City
{
CityId
CityName
}
}
I have a record with a Person, and want to add his City, how would i do it?

Suppose you hold the Person Id in &PersonId, then you would issue:
new
PersonId = &PersonId
CityId = ...
CityName = ...
when duplicate // This is optional
... // do something if there already exists a tuple PersonId/CityId with those values
endnew
In this sample, I am assuming you have a table Person with key PersonId and a table PersonCity with key PersonId, CityId
Don't forget to commit the transaction explicitly or implicitly (by having the procedure property Commit on Exit set to yes).

For a defensive approach that person exists, you can surround the "new" with a for each on person like this:
for each Person
where PersonId = &PersonId
new
Defined by PersonId
CityId = ...
CityName = ...
when duplicate // This is optional
... // do something if there already exists a tuple PersonId/CityId with those values
endnew
endfor

Related

Adding records with many to many back-references in Go Gorm

What is the approach in Go Gorm for writing and updating records that are back-referencing many to many structs.
For example, I have a Contact struct with a self-referenced Related property:
type Contact struct {
gorm.Model
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
MiddleName string `json:"middle_name,omitempty"`
Related []Contact `json:"related,omitempty" gorm:"many2many:related_contacts"`
}
Populating two contacts where each references the other
fred := model.Contact{
FirstName: "Fred",
LastName: "Jones",
MiddleName: "B",
}
bill := model.Contact{
FirstName: "Bill",
LastName: "Brown",
MiddleName: "R",
}
fred.Related = []model.Contact{bill}
bill.Related = []model.Contact{fred}
Performing a db.Save(&fred) will write two records to the database; one for bill and one for fred, however, bill record doesn't have a back reference to fred (as it hasn't been added yet and has no ID).
If I also perform db.Save(&bill), I now get 4 records, because saving bill didn't know that fred was already saved.
While I do realize that I can save one, then find the second and update it, I am wondering if there is a better "Gorm Way" of doing it where I don't have to manually keep the back references in sync when adding records?
Also, what is the approach if fred is to be removed? Do I need to take care of the related_contacts table manually?
The problem I think you're having is that the fred that you have in bill.Related is a copy, and thus does not get its ID updated by the call to db.Save(&fred).
When you call Save gorm checks the ID field of any models to know whether it should create or update that model.
What I would try is:
fred := model.Contact{
FirstName: "Fred",
LastName: "Jones",
MiddleName: "B",
}
db.Save(&fred)
bill := model.Contact{
FirstName: "Bill",
LastName: "Brown",
MiddleName: "R",
Related: []model.Contact{fred},
}
db.Save(&bill)
// Now both bill and fred have IDs
fred.Related = []model.Contact{bill}
db.Save(&fred)
One thing to watch out for here will be whether gorm tries to save fred.Related[0] and goes into an infinite loop. You can manage this by skipping the upserting of associations. So that means you would change the last two lines to:
fred.Related = []model.Contact{bill}
db.Omit("Related.*").Save(&fred)
// or using association mode
db.Model(&fred).Association("Related").Append(&bill)
EDIT: And with regards to deletion. Knowing nothing about which database you're using, you would normally have to manage related-entity deletion yourself. If you're using a db that supports foreign key constraints you could declare the join table foreign keys as REFERENCES contacts(id) ON DELETE CASCADE. This would mean that if you delete any Contact, the rows in the join table that contain the same ID would be automatically deleted also.

Is there a way to add a custom column when we create a many2many association in gorm?

I want to know 2 things
I got the following structs from a similar question.
// models/school.go
type School struct {
ID int `gorm:"primary_key"`
Name string `gorm:"not null"`
Accreditations []Accreditation `gorm:"many2many:school_accreditation;"`
}
type Accreditation struct {
// "accreditation" table
ID int `gorm:"primary_key"`
Name string
Description string
}
So, by default this will create a school_accreditation table with 2 columns:
one will have School's ID
other will have Accreditation's ID
My questions:
What is the most efficient way to add another column to the school_accreditation table?
Let's say I want to have the Name field of Accreditation in the school_accreditation table.
2.1) How do I achieve this eg: school_accreditation will have school_id, accreditation_id, accreditation_name
For the 1st question,
It seems the only way of doing it by defining the SchoolAccreditation model & adding fields to it.
Also, it gives me more control over the relationship.
For the 2nd question, I am yet to find a way if there is any!
bost
For the 2nd,
You have to manually get the name from Accreditation & then add it to the column via the defined SchoolAccreditation model.

Laravel Eloquent: Nested relationship and save data

I have three models.
PERSON (hasOne(EMPLOYEE), hasMany(CHILDREN))
id,
name
EMPLOYEE
id,
person_id
CHILDREN
id,
person_id
I want to add a child to person model but i have access to EMPLOYEE_ID. I tried to code but it doesn't work.
$employee->person()->children()->save($child);
and
$employee->person()->children()->associate($child);
But both doesn't work. I don't know if this can be accomplished by just one line of code.
Try this way, When you are calling person() it will return the relation instead of the object itself.
$employee->person->children()->save($child);

LINQ: Joining List<object> and dataset on a comma separated value field?

I am using C# and LINQ and trying to combine two sets of data. The first is a List of a specific type, lets call this Status (List) which is just a class with a bunch of properties one of which includes a comma separated value list of accounts. This is queried from the application database using a stored procedure so I have some flexability as to what is displayed here
For example:
class Status
{
...
public string Accounts {get; set;} (ie. "abcde, qwerty, asdfg")
public string Managers {get; set;}
...
}
The rest of the properties are irrelevant as this is the only field I am joining on.
The second "Accounts" data set is from a web service which I am calling to get a list of "Accounts" and the people associated with each account.
For example:
Account Manager SomeData MoreFields ...
------- ------------------- -------- ---------- ---
abcde Bob Marley Data MoreData ...
qwerty Fred Flinstone Data MoreData ...
So bascially I need to Create a list of Status objects with a CSV list of Manager(s) from the Accounts dataset in the Managers property of Status. Problem is I have no control over what is retruend in this dataset as it is a third party application. So I need to find some way to do this without modifying the "Accounts" data. Unless I do something in memory after getting the dataset from the web service.
I hope this makes sense and I thank you in advance!
What is this "dataset" of which you speak? I don't care where it come from -- I just care what kind of object it is in C#.
I'm going to assume that it's an ICollection, called "accounts"
Next, I'm going to assume that Managers is a CVS list much like Accounts.
Further, I'm only going to create one status object instead of a "list" of them, since you never say what separates one status from another.
var status = new Status();
status.Accounts = string.Join( ", ", from k in accounts select k.Account);
status.Managers = string.Join( ", ", from k in accounts select k.Manager);

Using First() with OrderBy and DynamicQuery in One-To-Many related tables

Note: I realize this question is similar to another question, however that question was asked in the context of Genom-e and remains unanswered. My question is in the context of LINQ DynamicQuery.
I'm using the String extension method overload for OrderBy provided by System.Linq.Dynamic. Passing a String Literal to OrderBy works great. I can sort on primary entity fields ie: person.OrderBy("LastName") and I can sort on children entity fields as long as there is a one-to-one relationship between the parent and child ie: person.OrderBy("Mother.LastName").
However, I am unable to sort on a child's field if there is a one-to-many relationship with the parent and child ie: person.OrderBy("Children.LastName"). This throws an error: No property or field 'Children' exists in type 'Person'.
Obviously this fails because the interpreter doesn't know which child's LastName I'm trying to use in the sort operation. I can solve this problem easily by creating an expression like this (Function(p As Person) p.Children.First.LastName).
But how can I get similar First behavior when using the string literal extension of OrderBy? Ultimately I want to be able to do something like this: person.OrderBy("it.Lastname desc, Children.First().FirstName asc")
Edit: I'm using the Repository pattern and this is what my Find function looks like:
Public Function Find(ByVal predicate As Expression(Of Func(Of TEntity, Boolean)), ByVal orderBy As String, ByVal skip As Integer, ByVal take As Integer) As IEnumerable(Of TEntity) Implements ILinqSqlRepository(Of TEntity, TContext).Find
If String.IsNullOrEmpty(orderBy) Then
Return Find(predicate, skip, take)
Else
Dim qry = Context.GetTable(Of TEntity)().Where(predicate).OrderBy(orderBy).Skip(skip).Take(take)
Return qry.ToList()
End If
End Function
Edit: This is the relationship between Person and Child tables:
Person Table
PersonId (pk)
MotherId (fk to Mother Table)
LastName
FirstName
Child Table
ChildId (pk)
PersonId (fk to Person Table)
LastName
FirstName
Mother Table
MotherId (pk)
LastName
FirstName
Each Person may have 0 or more Children. You can see there can be 0 or 1 Mother rows for each Person.
Obviously these are not the exact table names I'm using in my real project but you can see how relationships between Person and Mother, and with Person and Child are different.
Selector
I've tried overloading Find() to accept a Selector which selects p = Person and child = First().Child but the return type changes to Anonymous, instead of the Generic type. Is there some way to use the Selector in the OrderBy process but still return a IEnumerable(of TEntity)?
You could do (C#, sorry...):
people.Select(p => Person = p, Child = p.Children.First())
.OrderBy("Child.LastName")
.Select(p => p.Person);
BTW, without "it. you're using System.Linq.Dynamic, and with "it. you're using ESQL. Either one is OK, but you should not use both!

Resources