How to override the primaryKey() method. on Yii2 - yii2

Good morning dear community,
I'm new to Yii2 and working on a user login program but i get a database Exception why i try to login due to the primary key for user table
Here my code at vendor/yiisoft/yii2/db/BaseActiveRecord.php
Thank you in advance for the valuable help
* is composite or `$asArray` is `true`. A string is returned otherwise (null will be returned if
* the key value is null).
* #throws Exception if the AR model does not have a primary key
*/
public function getOldPrimaryKey($asArray = false)
{
$keys = $this->primaryKey();
if (empty($keys)) {
throw new Exception(get_class($this) . ' does not have a primary key. You should either define a primary key for the corresponding table or override the primaryKey() method.');
}
if (!$asArray && count($keys) === 1) {
return isset($this->_oldAttributes[$keys[0]]) ? $this->_oldAttributes[$keys[0]] : null;
}
$values = [];
foreach ($keys as $name) {
$values[$name] = isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;
}```

For everybody that gonna face this kind of error
here is the solution
public static function primaryKey()
{
return ["id"];
}

Related

autoincrement attribute is always null after save()

I have table query with field id which is autoincrement primary key.
Model
class Query extends \yii\db\ActiveRecord
{
public static function tableName()
{
return '{{%query}}';
}
public function rules()
{
return [
[['id', 'created_at'], 'integer'],
[['data'], 'string'],
];
}
}
Application
$q = new Query();
$q->created_at = time();
$q->data = Json::encode($query);
if ($q->save())
echo $q->id == null ? "null" : $q->id;
else
echo "Validation error";
Result is null, though new record with incremented id does occur in database.
Also I see only insert record in db log, but no record to obtain inserted row id.
What's wrong?
as you can see in vendor/yiisoft/yii2/db/ActiveRecord.php
there is already a primaryKey method
public static function primaryKey()
{
return static::getTableSchema()->primaryKey;
}
that return the proper primaryKey for the tableSchema
so you should not redefine this method ..
the method is specifically called primaryKey() not getPrimaryKey() .. this last one is the magic getter .. and return a value for var $primaryKey ..
if no insert is performed could be you have some validation problems .. try (just for debugging) using save(false)

jdbcTemplate pass in null value

I'm working with mysql and spring 4.1.6, but am having trouble sending in a null variable to the data base. I know to send a null value the syntax IS NULL is used but the field being sent into the data base is optional(the only optional value in the entire object), so it may be null or may have a value.
My request to database that simple checks if the address exists called by CRUD methods:
Note: the variable in question is street2
public boolean doesExist(Address address){
String sql = "SELECT EXISTS(SELECT * FROM Address WHERE contactType=? AND street1=? AND street2 ? AND city=? AND state=? AND zip=? AND country=?);";
String s = isNullDBQuery(address.getStreet2());
jdbcTemplate = new JdbcTemplate(dataSource);
int exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), isNullDBQuery(address.getStreet2()), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
if(exist == 1){
return true;
} else {
return false;
}
}
My isNullDBQuery:
private String isNullDBQuery(String s){
if(s == null){
return "IS NULL";
} else {
return "=" + s;
}
}
The error that's being returned is a syntax error with 'IS NULL'. The query sent to the database is street2 'IS NULL' rather then street2 IS NULL. Is it possible to get rid of the single quotation marks in my request? or is there a better way to do this?
any help is appreciated
No. Only values may be passed as parameters of a prepared statement. Not arbitrary portions of the query.
You need to use two different SQL queries (or generate it dynamically based on the nullness of the street2).
I managed to figure out how to achieve what I wanted:
public boolean doesExist(Address address){
String street2 = stringIsNull(address.getStreet2());
String sql = "SELECT EXISTS(SELECT * FROM Address WHERE contactType=? AND street1=? AND street2 " + street2 + " AND city=? AND state=? AND zip=? AND country=?);";
jdbcTemplate = new JdbcTemplate(dataSource);
int exist;
if(street2.equals("IS NULL")){
exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
} else {
exist = jdbcTemplate.queryForObject(sql, new Object[] {address.getContactType().name(), address.getStreet1(), address.getStreet2(), address.getCity(), address.getState().name(), address.getZip(), address.getCountry().name()}, Integer.class);
}
if(exist == 1){
return true;
} else {
return false;
}
}
private String stringIsNull(String string){
if(string == null) {
return "IS NULL";
} else {
return "=?";
}
}

ibatis can not rereurn primary key for batch insert

in my project , we use springmvc , spring and ibatis framework, the problem is :
in my dao code is :
#Override
public Integer insertAdzoneEnvInfoBatch(List<AdzoneEnvInfoDO> adzoneEnvInfoList) {
return executeInsertBatch("AdzoneEnvInfoDAO.insertAdzoneEnvInfo",adzoneEnvInfoList);
}
public Integer executeInsertBatch(final String sqlID, final List stList) {
Integer result = new Integer(-1);
if ((sqlID != null) && (stList != null) && !stList.isEmpty()) {
result = (Integer) getSqlMapClientTemplate().execute(
new SqlMapClientCallback() {
public Object doInSqlMapClient(SqlMapExecutor executor)
throws SQLException {
Integer result = new Integer(-1);
executor.startBatch();
for (int i = 0; i < stList.size(); i++) {
executor.insert(sqlID, stList.get(i));
}
result = new Integer(executor.executeBatch());
return result;
}
});
}
return result;
}
in my sqlmap file ,the sql is
<insert id="AdzoneEnvInfoDAO.insertAdzoneEnvInfo" parameterClass="adzoneEnvInfo">
insert into c_adzone_env_info(
url,adzoneid,pid,total_screen,screen_no,snapshot,adzone_num,ali_adzone_num,same_screen_num,same_screen_ali_num,
covered,ad_link,ad_snapshot,adzone_owner,
adzone_style,adzone_size,date_time,create_time,update_time
)
values(
#url#,#adzoneid#,#pid#,#totalScreen#,#screenNo#,#snapshot#,#adzoneNum#,#aliAdzoneNum#,
#sameScreenNum#,#sameScreenAliNum#,#covered#,#adLink#,#adSnapshot#,#adzoneOwner#,
#adzoneStyle#,#adzoneSize#,#dateTime# , now() , now()
)
<selectKey resultClass="long" keyProperty="id" type="post">
SELECT last_insert_id() as ID from c_adzone_env_info limit 1
</selectKey>
</insert>
and the dataobject has a property id respond to mysql autoincrement primary key
in my unittest ,code is
#Test
public void test(){
AdzoneEnvInfoDO adzoneEnvInfoDO = new AdzoneEnvInfoDO();
adzoneEnvInfoDO.setAdLink("adlink");
adzoneEnvInfoDO.setAdSnapshot("adsnapshot");
adzoneEnvInfoDO.setAdzoneid(99999999L);
adzoneEnvInfoDO.setAdzoneNum(434);
adzoneEnvInfoDO.setAdzoneOwner(11);
adzoneEnvInfoDO.setAdzoneSize("232下232");
adzoneEnvInfoDO.setAdzoneStyle(2);
adzoneEnvInfoDO.setAliAdzoneNum(334);
adzoneEnvInfoDO.setCovered(33);
adzoneEnvInfoDO.setUrl("sds");
adzoneEnvInfoDO.setUrlId(232323L);
adzoneEnvInfoDO.setTotalScreen(32423);
AdzoneEnvInfoDO adzoneEnvInfoDO1 = new AdzoneEnvInfoDO();
adzoneEnvInfoDO1.setAdLink("adlink");
adzoneEnvInfoDO1.setAdSnapshot("adsnapshot");
adzoneEnvInfoDO1.setAdzoneid(99999999L);
adzoneEnvInfoDO1.setAdzoneNum(434);
adzoneEnvInfoDO1.setAdzoneOwner(12);
adzoneEnvInfoDO1.setAdzoneSize("232下232");
adzoneEnvInfoDO1.setAdzoneStyle(22);
adzoneEnvInfoDO1.setAliAdzoneNum(334);
adzoneEnvInfoDO1.setCovered(33);
adzoneEnvInfoDO1.setUrl("sds");
adzoneEnvInfoDO1.setUrlId(232323L);
adzoneEnvInfoDO1.setTotalScreen(32423);
adzoneEnvInfoDAO.insertAdzoneEnvInfoBatch(Arrays.asList(adzoneEnvInfoDO, adzoneEnvInfoDO1));
System.out.println(adzoneEnvInfoDO.getId());
System.out.println(adzoneEnvInfoDO1.getId());
}
and in normal, the two object id should be parimary key in mysql ,but i found it is always null 0
and if i call a not batch method , it will be normal , the single data method is
public Long insertAdzoneEnvInfo(AdzoneEnvInfoDO adzoneEnvInfo) {
return (Long)executeInsert("AdzoneEnvInfoDAO.insertAdzoneEnvInfo",adzoneEnvInfo);
}
I got the same problem as you recently. I just read around the mybatis codes. This one is helpful to insert entities into MySQL. However it is a bit complicated because an ObjectWrapperFactory and a TypeHandler are registered in mybatis configuration file. See
https://github.com/jactive/java/tree/master/test/mybatis-demo
and the entry point
https://github.com/jactive/java/blob/master/test/mybatis-demo/java/com/jactive/mybatis/DaoTest.java

Default value for function argument, guaranteed to be unique

Just wondering, if i could provide default argument for function in ActionScript 3 which is never can be passed to the function by user. This is the case:
public function getAttr (obj:Object, key:String, def:* = DEFAULT_VALUE):* {
if (!obj.hasOwnProperty(key)) {
if (def === DEFAULT_VALUE) {
throw ReferenceError('Attribute not found: ' + key);
} else {
return def;
}
} else {
return obj[key];
}
}
I cannot use as DEFAULT_VALUE any of null, undefined, Number, Boolean or String here, cause, logically, user could use any of this values. I need something really unique here. In python, for example, i can do this:
_DEFAULT_VALUE = object()
def get_attr(obj, key, d=_DEFAULT_VALUE):
if not hasattr(obj, key):
if d is DEFAULT_VALUE:
raise KeyError('Attribute not found: {}'.format(key))
else:
return d
else:
return obj[d]
But in ActionScript 3 such approach produces an error:
Error code: 1047: Parameter initializer unknown or is not a compile-time constant.
Maybe some hack here?
Your problem here is that def value have to be a compile time constant so there is no way to store a default value into a var and pass it as a default value.
But what you really want here is to know if the user have passed an extra parameter into the def field of the function, so you can check the arguments array length and see if there is 2 or 3 parameters passed.
public function getAttr (obj:Object, key:String, def:* = null):* {
if (!obj.hasOwnProperty(key)) {
if (arguments.length==2) { // no default value passed to the function
throw new ReferenceError('Attribute not found: ' + key);
} else {
return def;
}
} else {
return obj[key];
}
}
Transfer null, and check for null. After all, null is a default value that's really nothing, if you require a parameter to be supplied and be valid, use null as default value so that if something will be supplied, it will not be null, thus valid.
Vesper's answer seems correct for your situation. But, I've used similar method for singletons though:
class Singleton
{
private var k_CONS_BLOCKER:Object = {};
public Singleton(cons_blocker:Object)
{
if(cons_blocker!=k_CONS_BLOCKER)
{
throw new Error("Use static getter to get the object");
}
}
public function getObject():Singleton
{
return obj;//you can of course create it now or do some other logic...
}
}
I know the answer isn't directly related to the question, but I think the idea solves the problem in general.
HTH.

How do you get the DataContext of a LINQ to SQL Entity?

Currently this is what I have:
public partial class LinqToSqlEntity {
public IQueryable<AnotherLinqToSqlEntity> AnotherLinqToSqlEntities {
using(DataContext context = new DataContext) {
return context.AnotherLinqToSqlEntities.Where(item => item.Property == SOME_VALUE);
}
}
}
Is there a way to get the DataContext of this so that I would not need to create a new DataContext?
Sorry, that is not possible. An entity or querable in that case keeps no direct reference of the context.
You can achieve that using the reflection by figuring out if PropertyChanging event was hooked up, but consider this a hack and maybe you can avoid using it with better design.
Our use case of this is on detach_EntityName delegate where we change the default Linq behaviour of only deleting the foreign key of a record (setting it to null), with the actual delete from DB.
public static DataContext GetDataContextFromEntityObject(object entity)
{
// Use a reflection to get the invocaiton list.
var o = (PropertyChangingEventHandler)entity.GetType().GetField("PropertyChanging", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(entity);
var o = GetFieldValue(entity, "PropertyChanging");
if (o == null) return null;
var invocationList = o.GetInvocationList();
if (invocationList != null)
{
// DataContext changes are tracked through StandardChangeTracker
object changeTracker = (from i in invocationList where i.Target.GetType().FullName == "System.Data.Linq.ChangeTracker+StandardChangeTracker" select i.Target).FirstOrDefault();
if (changeTracker != null)
{
object services = GetFieldValue(changeTracker, "services");
return (DataContext)GetFieldValue(services, "context");
}
}
return null;
}
private static object GetFieldValue(object instance, string propertyName)
{
return instance.GetType().GetField(propertyName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instance);
}