I have a table where it's beneficial to generate a pre-calculated value in the database engine rather than in my application code. For this, I'm using Postgres' generated column feature. The SQL is like this:
ALTER TABLE "Items"
ADD "generatedValue" DOUBLE PRECISION GENERATED ALWAYS AS (
LEAST("someCol", "someOtherCol")
) STORED;
This works well, but I'm using Sequelize with this database. I want to find a way to define this column in my model definition, so that Sequelize will query it, not attempt to update a row's value for that column, and ideally will create the column on sync.
class Item extends Sequelize.Model {
static init(sequelize) {
return super.init({
someCol: Sequelize.DOUBLE,
someOtherColl: Sequelize.DOUBLE,
generatedValue: // <<<-- What goes here??
});
}
}
How can I do this with Sequelize?
I can specify the column as a DOUBLE, and Sequelize will read it, but the column won't be created correctly on sync. Perhaps there's some post-sync hook I can use? I was considering afterSync to drop the column and re-add it with my generated value statement, but I would first need to detect that the column wasn't already converted or I would lose my data. (I run sync [without force: true] on every app startup.)
Any thoughts, or alternative ideas would be appreciated.
Until Sequelize supports readOnly fields and the GENERATED datatype, you can get around Sequelize with a custom datatype:
const Item = sequelize.define('Item', {
someCol: { type: DataTypes.DOUBLE },
someOtherCol: { type: DataTypes.DOUBLE },
generatedValue: {
type: 'DOUBLE PRECISION GENERATED ALWAYS AS (LEAST("someCol", "someOtherCol")) STORED',
set() {
throw new Error('generatedValue is read-only')
},
},
})
This will generate the column correctly in postgres when using sync(), and prevent setting the generatedValue in javascript by throwing an Error.
Assuming that sequelize never tries to update the field if it hasn't changed, as specified in https://sequelize.org/master/manual/model-instances.html#change-awareness-of-save, then it should work.
is it possible to add and delete column to my existing database using the controller? is it possible not to use the migration? and how do my model automatically picked up the new column which is create and automatically put in inside fillable? anyone has idea on how to approach this type of situation,if you could point me into a tutorial that would be so cool.
Reason: i have a table with the student mark-book points breakdown column example: [Exam, Homework,Quiz etc..] then every term or year we will remove it or changed it or add more so that's why i need to something like dynamic approach on this matter. where anytime i can change the column or add new column.
Same way the migrations do it, use the Schema builder class. For example:
$newColumnType = 'string';
$newColumnName = 'my_new_column';
Schema::table('my_table', function (Blueprint $table) use ($newColumnType, $newColumnName) {
$table->$newColumnType($newColumnName);
});
You probably should use $guarded = ['id', 'foo', 'bar'] in your model instead of fillable if you're going to be adding columns.
I have a MySQL database which has GUID's stored as binary(16) for the primary keys. I'm using a MySQL user defined routine when inserting and selecting to convert the id's to and from GUID's (GUIDToBinary() and BinaryToGUID()).
In order to use my routines in Phalcon, I am setting the 'columns' parameter for the find() and findFirst() model functions which now means i'm working with incomplete objects as the functions return an instance of Phalcon\Mvc\Model\Row.
The docs state when using the columns parameter the following occurs;
Return specific columns instead of the full columns in the model. When
using this option an incomplete object is returned
UserController.php
// Returns Phalcon\Mvc\Model\Row
$incompleteUser = User::find(['columns' => 'BinaryToGUID(id) as id, status, username, password, .....']);
// Create a new user object to update
$user = new User();
// Populate with existing data
$user->assign($incompleteUser->toArray());
// Assign new changes requested by the user
$user->assign($this->request->getPost());
// Update
$user->updateUser();
User.php
public function updateUser()
{
$manager = $this->getModelsManager();
return $manager->executeQuery("UPDATE User SET ..... WHERE id = GUIDToBinary(".$this->getDI()->get('db')->escapeString($this->id).")");
}
Irrespective of the fact that I've explicitly defined an update, an insert is performed due to the Model being in a transient state.
One solution I thought of was to move the binary to GUID conversion into Phalcon by using Model events however I can't find a suitable method for performing the conversion when selecting. Updating/Inserting is possible by using the beforeSave() and beforeUpdate() events. Perhaps I could just have different properties getId() and getIdGuid() within the model but I would prefer to avoid this if possible.
Is there a way to use MySQL user defined routines in Phalcon and hydrate my model so that it remains in a persistent state? Or do i need to go down the raw SQL route for my updates and avoid PHQL?
Thanks in advance for your time.
When I run my application and I click a specific button I get the error:
"The "X" property on "Y" could not be set to a 'null' value. You must set this property to a non-null value of type 'Int32'."
Cool so I go to my Entity project, go to Y table, find X column, right-click and go to X's properties and find that Nullable is set to False.
I verify in SQL that in Y table, X is set to allow nulls, and it is.
I then go back to my Entity project, set Nullable to True, save and build and I receive:
Error 3031: Problem in mapping fragments starting at line 4049:Non-nullable column "X" in table "Y" is mapped to a nullable entity property.
I've heard that deleting the table from the .edmx file and then re-adding it is a possibility but have never done that and don't understand the implications enough to feel comfortable in doing that.
I've heard that it could be in the view, could be in the stored procedure...
Also have heard that this is a bug.
Has anyone come across this and found an "across the board" fix or somewhat of a road map of sorts on where to look for this error?
Thanks!
"The "X" property on "Y" could not be set to a 'null' value. You must set this property to a non-null value of type 'Int32'."
In your EDMX, if you go under your Y table and click on X column, right-click, click on Properties, scroll down to Nullable and change from False to True.
If you get a "mapping fragment" error, you'll have to delete the table from the EDMX and re-add it, because in the Model Browser it stores the table properties and the only way to refresh that (that I know of) is to delete the table from the Model Browser under <database>.Store then retrieving it using Update Model from Database.. command.
I just replace data type int to int32?
public Int32 Field{ get; set; }
to
public Int32? Field{ get; set; }
and the problem is solved
My problem was that my Model database was out of sync with the actual (dev) database. So the EDMX thought it was smallint but the actual column was int. I updated the model database to int and the EDMX to Int32 and now it works.
For future readers.
I got this error when I had a multiple result stored procedure.
As seen here:
http://msdn.microsoft.com/en-us/data/jj691402.aspx
If you try to access an item in the first-result, after doing a .NextResult, you may get this error.
From the article:
var reader = cmd.ExecuteReader();
// Read Blogs from the first result set
var blogs = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<Blog>(reader, "Blogs", MergeOption.AppendOnly);
foreach (var item in blogs)
{
Console.WriteLine(item.Name);
}
// Move to second result set and read Posts
reader.NextResult();
var posts = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<Post>(reader, "Posts", MergeOption.AppendOnly);
foreach (var item in posts)
{
Console.WriteLine(item.Title);
}
Now, if before the line
foreach (var item in posts)
you put in this code
Blog foundBlog = blogs.FirstOrDefault();
I think you can simulate the error.
Rule of Thumb:
You still gotta treat this thing like a DataReader (fire-hose).
For my needs, I had to convert to a List<>.
So I changed this:
foreach (var item in blogs)
{
Console.WriteLine(item.Name);
}
to this:
List<Blog> blogsList = blogs.ToList();
foreach (var item in blogsList )
{
Console.WriteLine(item.Name);
}
And I was able to navigate the objects without getting the error.
Here is another way I encountered it.
private void DoSomething(ObjectResult<Blog> blogs, ObjectResult<Post> posts)
{
}
And then after this code (in the original sample)
foreach (var item in posts)
{
Console.WriteLine(item.Title);
}
put in this code:
DoSomething(blogs,posts);
If I called that routine and started accessing items/properties in the blogs and posts, I would encounter the issue. I understand why, I should have caught it the first time.
I verified that the entity was pointing at the correct database.
I then deleted the table from the .edmx file and added it again.
Problem solved.
Check your model & database both should be defined accordingly....
public Int32? X { get; set; } ----> Nullable
Accordingly in DB 'X' should be Nullable = True
or
public Int32 X { get; set; } ----> not Nullable
Accordingly in DB 'X' should be Nullable = false
In my case in created view in DB column that I select that contains null value I change that value by this select statement:
Before my change
select
..., GroupUuId , ..
after my change
select
..., ISNULL(GroupUuId, 0), ...
Sorry for my bad English
This may happen when the database table allows NULL and there are records that have a null value and you try to read this record with EF and the mapping class does not allow a null value.
The solution is either change the database table so that it does not allow null or change your class to allow null.
For me the following Steps corrected the Error:
Remove the 'X'-Property from the 'Y'-Table
Save EDMX
build Database from Model
compile
Add the 'X'-Property to 'Y'-Table again (with non-nullable and int16)
Save EDMX
build Database from Model
compile
to fix the error
Error 3031: Problem in mapping fragments starting at line 4049:Non-nullable column "X" in table "Y" is mapped to a nullable entity property.
open your EDMX file with and xml editor and lookup you table in
edmx:StorageModels
find the propertie which gives the error and set or add
Nullable="false" >> to Nullable="true"
save the edmx, open it in visual studio and build it. problem solved
Got same error but different context, tried to join tables using linq where for one of the tables in database, a non-null column had a null value inserted, updated the value to default and the issue is fixed.
I am working on create a custom field type and for implementation issue I need to retrieve the ID of the SPListItem in the SPField class which belong to these field type but I can't retrieve it.
For example:
public class myField:SPFieldText
{
// I need ListItemID in this class
}
Can anyone help me please?
SPFieldText is an SPField, which is the schema definition for a field. Its like saying, given an SQL create table statement, give me the id of row x. Can't be done.
I think the logic you are trying to perform should be done in an event receiver, so say when an item is saved, you take the ID and add it to the text field.
I didn't find a solution but I've tried another solution which is
I can get the ID of the item in the New and Edit forms so I saved the ID and the field value as a one value separated by '/' and in the SPFieldText class I've been able to retrieve the ID value from the value of the field