-
Notifications
You must be signed in to change notification settings - Fork 824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FIX isInDB actually checks if the object is in DB #7799
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
use SilverStripe\ORM\Filters\SearchFilter; | ||
use SilverStripe\ORM\Queries\SQLDelete; | ||
use SilverStripe\ORM\Queries\SQLInsert; | ||
use SilverStripe\ORM\Queries\SQLSelect; | ||
use SilverStripe\ORM\Search\SearchContext; | ||
use SilverStripe\Security\Member; | ||
use SilverStripe\Security\Permission; | ||
|
@@ -225,6 +226,13 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity | |
*/ | ||
protected static $_cache_get_one; | ||
|
||
/** | ||
* Static caches use by isInDB to check if an ID is in the DB | ||
* | ||
* @var array | ||
*/ | ||
protected static $_cache_in_db = []; | ||
|
||
/** | ||
* Cache of field labels | ||
* | ||
|
@@ -596,7 +604,7 @@ public function defineMethods() | |
*/ | ||
public function exists() | ||
{ | ||
return (isset($this->record['ID']) && $this->record['ID'] > 0); | ||
return $this->isInDB(); | ||
} | ||
|
||
/** | ||
|
@@ -1284,10 +1292,17 @@ protected function writeBaseRecord($baseTable, $now) | |
// Perform an insert on the base table | ||
$insert = new SQLInsert('"' . $baseTable . '"'); | ||
$insert | ||
->assign('"Created"', $now) | ||
->execute(); | ||
->assign('"Created"', $now); | ||
if ($id = $this->ID) { | ||
$insert = $insert->assign('"ID"', $id); | ||
} | ||
$insert->execute(); | ||
if (!$id) { | ||
$id = DB::get_generated_id($baseTable); | ||
} | ||
$this->changed['ID'] = self::CHANGE_VALUE; | ||
$this->record['ID'] = DB::get_generated_id($baseTable); | ||
$this->record['ID'] = $id; | ||
self::register_object($this); | ||
} | ||
|
||
/** | ||
|
@@ -2903,7 +2918,10 @@ public function flushCache($persistent = true) | |
{ | ||
if (static::class == self::class) { | ||
self::$_cache_get_one = array(); | ||
self::$_cache_in_db = []; | ||
return $this; | ||
} else { | ||
self::unregister_object($this); | ||
} | ||
|
||
$classes = ClassInfo::ancestry(static::class); | ||
|
@@ -2949,6 +2967,23 @@ public static function reset() | |
static::getSchema()->reset(); | ||
self::$_cache_get_one = array(); | ||
self::$_cache_field_labels = array(); | ||
self::$_cache_in_db = []; | ||
} | ||
|
||
/** | ||
* @param DataObject $object | ||
*/ | ||
public static function register_object($object) | ||
{ | ||
self::$_cache_in_db[$object->baseClass()][$object->ID] = true; | ||
} | ||
|
||
/** | ||
* @param DataObject $object | ||
*/ | ||
public function unregister_object($object) | ||
{ | ||
unset(self::$_cache_in_db[$object->baseClass()][$object->ID]); | ||
} | ||
|
||
/** | ||
|
@@ -3413,7 +3448,21 @@ public function defaultSearchFilters() | |
*/ | ||
public function isInDB() | ||
{ | ||
return is_numeric($this->ID) && $this->ID > 0; | ||
if (empty($this->ID)) { | ||
return false; | ||
} | ||
$class = $this->baseClass(); | ||
if (!isset(self::$_cache_in_db[$class][$this->ID])) { | ||
$sqlSelect = new SQLSelect(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only way that you can get to this code is if you have manually set the ID and not yet written the record. So, this code is picking up the case when you've manually set the ID to an existing record. We have the option of simply returning false in this case. If we did this, the functionality would match the "has been written" logic that I've recommended. It would remove the cause for performance / logic concerns that others have had. My view would be that checking the database for the presence of an ID that has been manually applied is a narrow & different use-case from the current uses of So I think that should simply return false in this case, and the update the docblock of
Note also that, after this change, the static registry can probably be replaced with an instance-specific |
||
$sqlSelect->setFrom('"' . $this->baseTable() . '"'); | ||
$sqlSelect->setWhere([ | ||
'"ID" = ?' => $this->ID, | ||
]); | ||
if ($sqlSelect->count() > 0) { | ||
static::register_object($this); | ||
} | ||
} | ||
return self::$_cache_in_db[$class][$this->ID]; | ||
} | ||
|
||
/* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can(should?) be marked as static too?