Been using Faker in combination with sqLite in-memory database for testing in Laravel lately and I have this strange issue where my model has a factory and everything except the first variable (which happens to also be the primary key of the table) gets set correctly.
Let's explain further, the variable I'm pointing at uses the following rule in the factory:
'kvk' => strval($faker->randomNumber(9)),
So it should become a string containing a 9 digit number. Now the next step is calling the factory from my controller test and I also have another User model which uses this 'kvk' variable from my company as a foreign key reference:
$this->_company = factory(Company::class)->create([ 'address_id' => $this->_address->id ]);
$this->_user = factory(User::class)->create([ 'kvk' => $this->_company->kvk ]);
But when I put an echo $this->_company->kvk; in between, it shows me that 'kvk is set to 1, which should not be possible because of the rule I put in my factory.
Finally the user is used to mock the session in the test and is also used to check wether I should have the rights to edit an address using the following check:
$user = Auth::user();
$company = Company::where('kvk', $user->kvk)->first();
$address = Address::whereId($id)->first();
if($company->address_id != $address->id)
{
return abort(403);
}
So first I get the current logged in user (which is mocked to the created user above, and this works perfectly. Next I get the company associated with this user (which should be the one created above, since I used the company->kvk as a foreign key reference), however when I output the saved Company to my log I see that the kvk is set to a 9 digit string like it's supposed to.
I really can't put my finger on why at first the kvk is set to 1 and afterwards in my test it seems perfectly fine the way it should be, but my test fails because the wrong reference is set in my User so it can't find the right Company. Do you have any idea what could be the reason for this? I've also tried setting the 'kvk' explicitly while creating with the factory, but this also does not work and will stil output 1.
After diving into the source of Laravel, I found out it had to with my models. While I did set the primary key attribute in my models, I forgot to set the auto increment boolean to false. This caused my models to cast the primary key to an auto increment integer every time it was saved to the database. This solved the issue.
Related
$added_obj = [];
foreach ($something as $data) {
$obj = $this->class->function($data, $par2);
if (null !== $obj && !(array_key_exists
(->getVal1(), $added_obj[$obj->getVal1()] === $$obj->getVal2())) {
$this->persister->persist($obj);
$added_bank_account[$obj->getVal1()] = $obj->getVal2();
} else {
}
}
What the code does: It calls an function which returns an entity or null. If an entity was created there is an check if 2 values already exists in an array, if not, than persist and add the 2 values to an array as key/val pair.
But, when an entity is created and it already exists in the array i don't want it to be persisted, but I want to do nothing with it.
But, when I do absolutely zero with it I got the error:
```Multiple non-persisted new entities were found through the given association graph:
A new entity was found through the relationship 'MyCompany\Client\Entity\Client#something' that was not configured to cascade persist operations for entity:
which makes sense because doctrine doesn't know what to do with the created entity. How can I "destroy" the created entity so that the problem is solved.
When there is only 1 object created everything works fine.
In your case you can simply merge or clear the entity from EntityManager
ex :
$em->merge($obj);
OR
$em->clear($obj);
I was facing the same issue because it was trying to insert a duplicated registry in a particular table, when in fact I was just trying to update it.
I was doing a persist with a flush right after.
So I found that (obvious for many, but certainly helpful):
->merge
will duplicate the registry in many cases, if the id is not set properly.
If you are trying to update an entity, this is not a good idea.
->persist
In the same way, if you are trying to update an entity, you may not use it. It's used to add a new entity to the db. To update a record, you may just use flush as you can see in this example from the docs.
I had the same problem and googling this error did not give me much results, but it appeared that in case of only one entity (not multiple) doctrine gives different error message, which has a solution that worked for multiple entities too. So, let me leave here a link for it: Doctrine - A new entity was found through the relationship
This problem occurs if you got the related entity in another object manager. For example, if there was previously a check for duplication through an exception and resetting the manager.
In our Siebel 7.8 application, we have three entities: service requests (SR), groups and employees. Each employee can be member of one or many groups, and each service request can be assigned to one or many groups too.
I have a requeriment to create a calculated field on the service request BC, which will indicate if the current user belongs to any of the groups asociated with the service request.
I already have created a multivalue field, called SR Groups, on the service request BC. I have also another multivalue field, Employee Groups; this one is on the Personalization Profile business component, which means that Siebel will generate automatically a multivalued profile attribute with the same name. All of the above is working as expected.
Next I've created this calculated field:
IIf(InList([SR Groups], GetProfileAttrAsList("Employee Groups")), "Y", "N")
It works, but it only checks if the SR's primary group is one of the current user's groups. I need to check all the SR groups, not only the primary one. So, I have created another calculated field:
IIf(EXISTS([SR Groups] = GetProfileAttrAsList("Employee Groups")), "Y", "N")
This one doesn't work. It shows always "N". However, according to this Bookshelf document:
a typical usage of the EXISTS operator in this scenario is EXISTS ([Targeted States] = GetProfileAttrAsList("State")). This does a many-to-many match of the MVG Business Component Field Targeted State against the MVG profile attribute State.
Which is exactly what I'm trying to do, without success. I can't see any difference between my expression and the example one. And there isn't any of the typical Bookshelf warnings, like "if you're going to use this function, you must activate the Link Specification property of the MVF", or anything like that.
The business component is based on a specialized class, CSSBCServiceRequest, but I don't think that should be a problem in this case - switching it to CSSBCBase doesn't fix the issue either. The only thing not working seems to be the EXISTS operator, which is pretty standard in Siebel.
Also, if I execute a query on the application with the expression EXISTS([SR Groups] = GetProfileAttrAsList("Employee Groups")), it doesn't filter out any service request as it should.
Any clues?
After a lot of testing, I've been able to figure out a workaround. I'd still like to know why my first attempt didn't work, but anyway...
Given that the problem with my first attempt seemed to be matching a many-to-many relationship between the MVF and the multivalued profile attribute, I've split it in two one-to-many matches:
In the link, I've stablished a search specification property. This way, my multivalue field will contain only groups associated with the user:
InList([Group], GetProfileAttrAsList("Employee Groups"))
In the BC, it only remains to check if there is any value in the MVF or not:
IIf(EXISTS([Filtered SR Groups] IS NOT NULL), "Y", "N")
My issue is when saving new models that need to reference each other, not just using a related_name lookup, such as this:
class Many:
owner = models.ForeignKey('One')
class One:
current = models.OneToOneField('Many')
By default, these have null=False and, please correct me if I'm wrong, using these are impossible until I change one of the relationships:
current = models.OneToOneField('Many', null=True)
The reason is because you can't assign a model to a relationship unless its already saved. Otherwise resulting in ValueError: 'Cannot assign "<...>": "..." instance isn't saved in the database.'.
But now when I create a pair of these objects I need to save twice:
many = Many()
one = One()
one.save()
many.owner = one
many.save()
one.current = many
one.save()
Is this the right way to do it, or is there another way around saving twice?
There is no way around it, you need to save one of the objects twice anyway.
This is because, at the database level, you need to save an object to get its ID. There is no way to tell a sql database "save those 2 objects and assign the ids to those fields on the other object". So if you were to do it manually, you would INSERT the first object with NULL for the FK, get its ID back, INSERT the second object with the ID of the first one, get its ID back, then UPDATE the first object to set the FK.
You would encapsulate the whole thing in a transaction.
So what you're doing with the ORM is the closest you can get. You may want to add the following on top of that:
1) Use a transaction for the changes, like this:
from django.db import transaction
with transaction.atomic():
many, one = Many(), One()
one.save()
many.owner = one
many.save()
one.current = many
one.save(update_fields=['current']) # slight optimization here
2) Now this is encapsulated in a transaction, you would want to remove the null=True. But you cannot, as those are, unfortunately, checked immediately.
[edit: it appears Oracle might support deferring the NOT NULL check, so if you're using Oracle you can try dropping the null=True and it should work.]
You'll probably want to check how your code reacts if at a later point, when reading the db, if for some reason (manual editing, bugged insert somewhere, ...) one.current.owner != one.
I am having the most frustrating problem, basically I have a website and a webservice running on the same server. Both use ADO.net to connect to data tables using a couple of custom calls I have created myself, the website has never had a problem with connecting to a particular proc to return data, however the webservice, once in say every 100 calls to that proc, returns an empty dataset even though it should have come back populated and does in a query in SQL Mgmt Studio. The weird thing is it works most times, but on the odd occasion returns this error:
System.IndexOutOfRangeException: Cannot find table 0. at System.Data.DataTableCollection.get_Item(Int32 index)
Dim SQLCmd As SqlCommand = CreateSPCommand("VerifyCredentialsSP")
SQLCmd.Parameters.AddWithValue("#Password", Credentials.Password)
GetData(SQLCmd)
ds.DataSetName = "Customer"
If ds.Tables(0) IsNot Nothing Then
ds.Tables(0).TableName = "Customer"
End If
One way to do this is to catch the exception being thrown, but the better method is to check for null or nothing in your case.
Do not access the index ds.Tables(0)....
Do a check if your dataset ds is null before accessing it like so:
If ds IsNot Nothing then
'only then can you index ds.
end if
In this way you avoid a lookup on the index of your dataset given that it contains some valid reference. In your method you are accessing Tables(0) which may or may not exist, without a valid check your code could potentially throw an exception, and in this case it has!
Each time the save() method is called on a Django object, Django executes two queries one INSERT and one SELECT. In my case this is usefull except for some specific places where each query is expensive. Any ideas on how to sometimes state that no object needs to be returned - no SELECT needed.
Also I'm using django-mssql to connect to, this problem doesn't seem to exist on MySQL.
EDIT : A better explanation
h = Human()
h.name='John Foo'
print h.id # Returns None, No insert has been done therefore no id is available
h.save()
print h.id # Returns the ID, an insert has taken place and also a select statement to return the id
Sometimes I don't the need the retruning ID, just insert
40ins's answer was right, but probably it might have higher costs...
When django execustes a save(), it needed to be sure if the object is a new one or an existing one. So it hits the database to check if related objext exists. If yes, it executes an UPDATE, orherwise it executes an ISERT
Check documentatin from here...
You can use force_insert or force_update ,but that might be cause serious data integrity problems, like creating a duplicate entry instead of updating the existing one...
So, if you wish to use force , you must be sure whether it will be an INSERT or an UPDATE...
Try to use save() method with force_insert or force_update attributes. With this attributes django knows about record existence and don't make additional query.
The additional select is the django-mssql backend getting the identity value from the table to determine the ID that was just inserted. If this select is slow, then something is wrong with your SQL server/configuration because it is only doing SELECT CAST(IDENT_CURRENT(*table_name*) as bigint) call.