I am using RedBean and i want to remove the relationships existing at sharedList. Right now i am using
$bean->sharedList = array();
R::store($bean);
But it does not work. Any suggestions?
As per RedBean documentation
A shared list contains beans that may be associated with more than
just one other bean (many-to-many relation).
list($vase, $lamp) = R::dispense('product', 2);
$tag = R::dispense( 'tag' );
$tag->name = 'Art Deco';
//creates product_tag table!
$vase->sharedTagList[] = $tag;
$lamp->sharedTagList[] = $tag;
R::storeAll( [$vase, $lamp] );
In your code you are not sharing it with any other list. Would you share what exactly you are trying to achieve.
The property containing the collection needs to have the name of a bean type in it;
e.g.
$class->sharedStudent = array();
R::store($class);
This will remove the relationship between the $class bean and any student beans it was previously related to. The student beans will not be deleted however.
Your example would only work if the shared bean type was of type 'list' (which I doubt it is.)
Incidentally, you don't need to add 'List' onto the end of a shared collection any more. This was deprecated a few versions back, near the beginning of Redbean 4 I believe.
Related
A pattern we use here for large dynamic forms is to allow the client to edit pretty much the entire graph including children and removal and addition of children is handled in javascript. Failing use case is when user deletes a property of one of the children and for this example we'll say the email address of the second child is removed and the parm is sent empty.
Example Class Structure
Domain X
Long id
String name
SortedSet<Child> children
Domain Child
Long id
Integer position // used to sort
String name (required)
String email (required)
Parms are named in this manner:
x.id = 1
x.name = 'blah'
x.children[0].id = 1
x.children[0].position = 0
x.children[0].name = 'childa0'
x.children[0].email = 'child0#any.com'
x.children[1].id = 2
x.children[1].position = 1
x.children[1].name = 'child1'
x.children[1].email = ''
Current stored values:
x.id = 1
x.name = 'blah'
x.children[0].id = 1
x.children[0].position = 0
x.children[0].name = 'childa0'
x.children[0].email = 'child0#any.com'
x.children[1].id = 2
x.children[1].position = 1
x.children[1].name = 'child1'
x.children[1].email = 'child1#any.com'
The pattern to update has been:
Browser
user edits all and submits changes
parms are sent as shown above and in this use case user accidentally deleted email address that is required (yes submit could be prevented in this simple case but there are more extensive validation rules and this is just a simple example to illustrate issue)
Server
retrieve current parent domain class using id parm
check current stored version against edited version and ensure it has not changed
apply all parms to current domain object in this manner: x.properties = parms.x
This is where it breaks down. With Grails 2.2.2 the email property of child[1] is updated to an empty string and running validation catches the error. Grails 2.4.4 does NOT update the child value. I know the data binding changed and perhaps there are valid reasons for this change but I can't fathom it. This has worked from 1.3.6 to 2.2.2.
One thing to note is that if I do not retrieve the domain class and instead create a new instance with the parms passed in all of the child parms are set correctly.
X x = new X(params.x)
This seems to indicate some Grails issue as the user guide talks about both methods as equal - one to use for new instances and the other for updates but the examples clearly demonstrate that both methods should handle indexed child properties.
Any help or thoughts are appreciated!
I ran into this problem my self upgrading an application from 2.2.4 to 2.4.4.
Setting grails.databinding.useSpringBinder = true for config.groovy
and adding grails-web-databinding-spring to the pom worked flawlessy for me.
Obviously doing this was a lot less hassle than rewriting all the binding code :-)
Looking into this further Grails 2.4.4 documentation states that it will bind sets positionally if they are indexed (ie. [0]).
http://grails.org/doc/latest/guide/single.html#dataBinding
The section titled "Data Binding and Many-ended Associations" states that these parms will be bound and that new instances of the set will be created if their index is greater than the current set. This was true for me in Grails 2.2.2 but NOT in 2.4.4.
HOWEVER, earlier in the documentation in the section "Binding To Collections And Maps" it states clearly: "When updating existing elements in a Set the Map being assigned to the Set must have id elements in it which represent the element in the Set".
If you are upgrading to Grails 2.4.4 and have any complex form data binding I suggest you look there first to decide whether to upgrade. Due to these changes in data binding this has become the most complex upgrade we've encountered yet with Grails.
The other disappointment with 2.4.4 is that it states you can override the new binding and fall back to the old spring binding but you cannot past 2.4 - at least from what I can gather from others' posts and my attempts. Setting the config property as documented and adding the dependency required resulted in startup runtime errors.
Apparently older versions of grails prior to 2.4.4 would match the child instances to params positionally, i.e. using the indexes ([0],[1], etc.) to match the children not caring if the IDs of the instances matched. The new binder does want the IDs of the instances to match before binding. I had never realised I was not placing the ID in a hidden field as it always worked perfectly.
I had a similar problem after migrating to Grails 2.4.4 (from 2.2.2). After a lot of reading and seaching (you must to definitly read http://docs.grails.org/2.4.4/guide/single.html#dataBinding mencioned in user2863513 post) I've resolved it in a very simple way
In my application I had nested domains relationships. Example:
class A {
String name
static hasMany = [b:B]
}
class B {
String name
static hasMany = [c:C]
}
class C {
String name
}
Due to the form complexity, class C object were not binding correcly. I've resolved this defining the C atribute on class B as a List (remember, has many relationships are implemented as Sets by default). So, my class B changed to:
class B {
String name
static hasMany = [c:C]
List c
}
And voila! Everything works perfectly again.
Following many tutorials from official and non-official docs, there is no such a clear vision for common approach for creating editing the entity and updating just specific fields.
The main questions are:
1 - Create the entity - fill the form, validate, create entity object and populate it with exchangeArray and then save, in save method via docs we must configure an array from passed object like:
$data = array(
'artist' => $album->artist,
'title' => $album->title,
);
Can we avoid this array re-configuring in save method?
2 - Update the entity - same logic
3 - What if we want to update only one specific field?
I pass the array to updateEntity method, but is it normal way to pass object(and configure array inside method) to save method and pass array to update method?
4 - Almost same thing with 3 but issue now when we have an array with another keys among our entity fields keys, we can strip 'bad' array keys using hydrator and make something like array_intersect style, but what you suggest?
You can use a smart combination of your entity, form, input filter and hydrator to have almost no logic to get CRUD things done. For an admin interface I usually generate my controller, form and other classes. I use Sublime Text 2 and the snippets to generate these classes can be found in my repository.
This results in:
A controller with index (listing), view (single item), create, update and delete
A form to contain all entity fields
A repository (Doctrine) to query entities
A service to persist to the database (either create one, save one or delete one)
This will solve #1 and #2. Due to the way ZF2 filtering and hydration works, this will also solve #4 for you. Then, it is possible to set only a select no. of fields to be filtered, but I have not implemented that (yet). I can only refer to the manual to know how to do that.
If you want to know the implementation of above snippets, take a look at Soflomo\Portfolio which uses a similar strategy.
PHP, contrary to other languages, is array centric than object centric. Most task could be done via Array. In this case, instead of use
<?php
class SomeClass {
public $artist;
public $title;
}
$album=new SomeClass();
$data = array(
'artist' => $album->artist,
'title' => $album->title,
);
?>
We should use
<?
$SomeObject=array("artist"=>xxx,"title"=>xxxx);
$data = $someObject;
?>
i.e. we should avoid to use classes when we are referencing a POCO class and instead we should use the (less elegant) array. Otherwise, sometimes we will be forced to do such conversion between array and object.
Anyways i we will need to keep it as a object then, we can do the conversion between object to array using:
<?php
class SomeClass {
public $artist;
public $title;
}
$album=new SomeClass();
$data = (array)$album;
?>
However, this conversion sometimes is tricky.
I'm facing this exception An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported. when I try to insert a new entity into my Employees table (the master one).
There is a relationship between the master Employees table and the details Orders table, and I'm sure that the relationship between these two tables (and specifically Employee.Orders EntitySet) is the cause of the problem since when I removed the relationship, it returns back to insert into Employees table with no problems.
When I searched for the problem, there was this blog post which I tried to implement but my case is a different than the one in the blog post in these items:
He faces the exception when tries to update (while I try to insert).
The tables architecture is different.
how can I solve this problem?
Here's the insertion code:
Employee emp = new Employee();
emp.Name = empName; // empName is a local variable
// What should I default emp.Orders to?
dc.Employees.InsertOnSubmit(emp);
dc.SubmitChanges();
P.S: My DataContext is defined on class-level in my repository and the exception is being thrown when I call dc.SubmitChanges();. and I didn't Attach any object why does it say that?
Here is an article explaining what you need to do using the Attach and Detach methods:
http://www.codeproject.com/KB/linq/linq-to-sql-detach.aspx
I am guessing it is trying to save something else besides just the employee object or you aren't showing us the full code in your repository. When you instantiate your DataContext object (dc) try setting DeferredLoadingEnabled = false, and ObjectTrackingEnabled = false and see if it works. If it does, try watching the SQL code in SQL Server Profiler and see if it is modifying other objects that may have came from a different context like the message says.
var dc = new MyDataContext()
{
DeferredLoadingEnabled = false,
ObjectTrackingEnabled = false
};
My bet is on the primary key.
Are you sure the primary key is also set on auto increment?
Did you
try changing the name, does it work then?
What happens if you remove
all rows from your DB? can you insert one then?
I have a POCO entity Report with a collection of a related POCO entity Reference. When creating a Report I get an ICollection<int> of ids. I use this collection to query the reference repository to get an ICollection<Reference> like so:
from r in referencesRepository.References
where viewModel.ReferenceIds.Contains(r.Id)
select r
I would like to connect the collection straight to Report like so:
report.References = from r in referencesRepository.References
where viewModel.ReferenceIds.Contains(r.Id)
select r;
This doesn't work because References is an ICollection and the result is an IEnumerable. I can do ToList(), but I think I will then load all of the references into memory. There also is no AddRange() function.
I would like to be able to do this without loading them into memory.
My question is very similar to this one. There, the only solution was to loop through the items and add them one by one. Except in this question the list of references does not come from the database (which seemed to matter). In my case, the collection does come from the database. So I hope that it is somehow possible.
Thanks in advance.
When working with entity framework you must load objects into memory if you want to work with them so basically you can do something like this:
report.References = (from r in referencesRepository.References
where viewModel.ReferenceIds.Contains(r.Id)
select r).ToList();
Other approach is using dummy objects but it can cause other problems. Dummy object is new instance of Reference object which have only Id set to PK of existing object in DB - it will act like that existing object. The problem is that when you add Report object to context you must manually set each instance of Reference in ObjectStateManager to Unchanged state otherwise it will insert it to DB.
report.References = viewModel.ReferenceIds.Select(i => new Reference { Id = i }).ToList();
// later in Report repository
context.Reports.AddObject(report);
foreach (var reference in report.References)
{
context.ObjectStateManager.ChangeObjectState(reference, EntityState.Unchanged);
}
When I use criteria queries, the result contains array list of lazy initialized objects. that is, the list has values with handler org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwareJavassistLazyInitializer.
This prevent me from doing any array operation (minus, remove etc) in it. When I use, GORM methods, I get array list of actual object types. How can I get the actual objects in criteria query?
The code is listed below.
availableTypes = Type.withCriteria() {
'in'("roleFrom", from)
'in'("roleTo", to)
}
availableTypes (an array list) has one value , but not actual object but value with a handler of GroovyAwareJavassistLazyInitializer
availableTypes (an array list) has values with type Type
availableTypes = Type.findByRoleFrom(from)
---------- Update ----------
I did further troubleshooting, and this is what I found. Probably the above description might be misleading, but I kept it in case it helps.
When using findAllBy for the first time, I get proxy objects rather than the actual instance. Then, I invoke the method through an ajax call, the actual instance is loaded (anything to do with cache loading??). When I refresh the page, it again loads the proxy
def typeFrom = Type.findAllByParty(partyFrom)
there is another use of findAllBy in the same method, which always returns actual instances.
def relFrom = Relation.findAllByParty(partyFrom)
When compared the two classes, the attribute 'party' of class Roles is part of a 1-m relation. like
class Role {
RoleType roleType
LocalDate validFrom
LocalDate validTo
static belongsTo = [party : Party ]
...
}
I know if I do statement like Party.findAll(), the role instances would be proxy till they access. But, when using gorm directly on the class (Role), why I am getting the proxy objects ???
thanks for the help.
thanks.
Turns out are a couple of possible solutions which I came across but didn't try, such as
Overloading the equals method so that the proxy and the domain
object use a primary key instead of the hashCode for equality
Using a join query so that you get actual instances back and not proxies
GrailsHibernateUtil.unwrapProxy(o)
HibernateProxyHelper.getClassWithoutInitializingProxy(object)
One solution that worked for me was to specify lazy loading to be false in the domain object mapping.
History of this problem seems to be discussed here: GRAILS-4614
See also: eager load