Is it possible to write an entire object to Dexie without knowing the schema?
I just want to do this:
var db = new Dexie(gameDataLocalStorageName);
db.version(1).stores({
myData: "gameData"
});
db.myData.put(gameData);
console.log(db.myData.get('gameData'));
But I'm getting the following error:
Unhandled rejection: DataError: Failed to execute 'put' on 'IDBObjectStore': Evaluating the object store's key path did not yield a value.
DataError: Failed to execute 'put' on 'IDBObjectStore': Evaluating the object store's key path did not yield a value.
The error is because you've specified the schema to use inbound key "gameData", i.e. require each object to have the property "gameData" as its primary key.
If you don't need to have the primary key within the objects, you can declare the schema as {myData: ""} instead of {myData: "gameData"}. By doing so, you will need to provide the primary key separate from the object in calls to db.myData.put().
See docs for inbound vs non-inbound keys and detailed schema syntax
var db = new Dexie(gameDataLocalStorageName);
db.version(1).stores({
myData: ""
});
Promise.resolve().then(async () => {
await db.myData.put(gameData, 'gameData'); // 'gameData' is key.
console.log(await db.myData.get('gameData'));
}).catch(console.error);
Since we're changing the primary key here, you will need to delete the database in devtools before this would work.
Related
I have a loader function in order to fetch chefs from a database. So that loader receive an array of ids and what's is strange is that the ids have a readonly type.
When I try to pass that read-only type to the database query, it gives an error.
How can I fix the type definition?
Source code: https://github.com/LauraBeatris/graphql-with-nextjs/blob/master/pages/api/loader.ts
I fixed that according to #DanielRearden comment.
The function that the DataLoader instance receives uses generic types, so we're able to pass a type to the ids argument and then use it inside of the whereIn knex method.
new DataLoader((ids: string[]) => (
databaseClient
.table("chefs")
.whereIn("id", ids)
.select("*")
.then(rows => ids.map(id => rows.find(row => row.id === id)))
))
i am using dexiedb for my angular project. I have a database with a comments table. I would like to add the user inputs to the database and i am using table.put(item, [key]). I want to only add in the first row, so primary key = 0, thats why i specify the key. But it is not working.
Below is my code snippet. I am getting error when having the primary key as argument.
Failed to execute 'put' on 'IDBObjectStore': The o… in-line keys and the key parameter was provided.",
#Injectable()
export class DexieService{
onNewComment = new EventEmitter<Comments>();
contactDB: Dexie;
constructor(){
this.contactDB = new Dexie('contact');
this.contactDB.version(1).stores({
comments:'++id,comment'
})
}
addComment(comment: Comments): Promise<any>{
return(
this.contactDB.table('comments').put(comment,0)
.then((result) =>{
this.onNewComment.next(comment);
return (result);
})
)
}
Expected result should be that when any new comments are added, it will always go to first row with primary key = 0 as the primary key already exists
Your primary key (++id) is inbound, which means you can only specify the key within the object itself and do not need to use the optional key parameter. The API will fail if using the optional key argument unless the primary key is outbound. This API mirrors the raw IndexedDB's IDBObjectStore.put() method that works the same for inbound keys.
Instead, use:
this.contactDB.table('comments').put({...comment, id: 0})
I have used breeze's CreateEntity a few times when table's PK is a user-entered value. And a few times with SQL SERVER when PK is an IDENTITY. This is my first time trying to do it when PK is autogenerated ID (actually a "sequence") in ORACLE. It isn't working.
I do check first to make sure I have fetched the Metadata then create the new, empty entity that will be filled in with values by user.
My code to createEntity (newEntity is a knockout Observable):
function createEntity(newEntity) {
newEntity(manager.createEntity(entityNames.escctransactions, {})); <<<<< this fails
return;
}
The Error:
Cannot attach an object of type (ESCC_TRANSACTIONS:... ) to an EntityManager without first setting its key or setting its entityType 'AutoGeneratedKeyType' property to something other than 'None'
I know I need to set the AutoGeneratedKeyType to "Identity" but not sure how to do it. Tried this when I'm inititalizing the metadata, but still getting same error so it's obviously not working:
var entyType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entyType.setProperties({ AutoGeneratedKeyType: AutoGeneratedKeyType.Identity });
I've seen something about doing it in a constructor but I've never used a constructor in JavaScript. Also something about changing it in a config?
Using Breeze 1.6, Knockout.js 3.4, .NET 4.5.2 framework
THANKS
Figured it out myself and it's working now. The code to set AutoGeneratedKeyType is as follows:
var entityType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entityType.autoGeneratedKeyType = "Identity";
Or this works:
var entityType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entityType.autoGeneratedKeyType = breeze.AutoGeneratedKeyType.Identity;
And in spite of the Breeze documentation for AutoGeneratedKeyType here:
http://breeze.github.io/doc-js/api-docs/classes/AutoGeneratedKeyType.html, it's not a capital "A" in Auto, it's a small "a".
Right now, if I add a field to a Parse object and then save it, the new column shows up in the Parse dashboard.
For example, after running:
let media = new Parse.Object("Media");
media.set("foo", "bar");
await media.save();
I will have a new column called foo.
Is it possible to prevent this from happening?
Yes. This can be done using class-level permissions, which allow you to prevent fields being added to classes.
Parse lets you specify what operations are allowed per class. This lets you restrict the ways in which clients can access or modify your classes.
...
Add fields: Parse classes have schemas that are inferred when objects are created. While you’re developing your app, this is great, because you can add a new field to your object without having to make any changes on the backend. But once you ship your app, it’s very rare to need to add new fields to your classes automatically. You should pretty much always turn off this permission for all of your classes when you submit your app to the public.
You would have to add a beforeSave trigger for every one of your classes, keep a schema of all your keys, iterate over the request.object's keys, and see if there are any that do not belong in your schema. You can then either un-set them and call response.success(), or you can call response.error() to block the save entirely, preferably with a message indicating the offending field(s).
const approvedFields = ["field1", "field2", "field3"];
Parse.Cloud.beforeSave("MyClass", function(request, response) {
let object = request.object;
for( var key in object.dirtyKeys() ) {
if( approviedFields.indexOf(key) == -1 ) return response.error(`Error: Attempt to save invalid field: ${key});
}
response.success();
});
Edit:
Since this got a little attention, I thought I'd add that you can get the current schema of your class. From the docs: https://docs.parseplatform.org/js/guide/#schema
// create an instance to manage your class
const mySchema = new Parse.Schema('MyClass');
// gets the current schema data
mySchema.get();
It's not clear if that's async or not (you'll have to test yourself, feel free to comment update the answer once you know!)
However, once you have the schema, it has a fields property, which is an object. Check the link for what those look like.
You could validate an object by iterating over it's keys, and seeing if the schema.fields has that property:
Parse.Cloud.beforeSave('MyClass', (request, response) => {
let object = request.object;
for( var key in object.dirtyKeys() ) {
if( !schema.fields.hasOwnProperty(key) ) < Unset or return error >
}
response.success();
}
And an obligatory note for anyone just starting with Parse-Server on the latest version ,the request scheme has changed to no longer use a response object. You just return the result. So, keep that in mind.
I've managed to create number of readonly Web Api OData services following the tutorials here: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api. I'm therefore employing the ODataConventionModel builder to create the model from a set of entities (incidentally coming from a Telerik ORM). This all seems to work fine and I can happily issue queries, view the metadata and so forth on the service.
I've now tried to turn my attention to the other CRUD operations - firstly Create and have stumbled into a problem! Namely, the Post method fires correctly (CreateEntity) but the entity parameter is null - by doing a check against the ModelState.IsValid, it shows that the problem is a null ID (key) value. This is unsurprising because the database uses a Database Generated Identity for the ID column and therefore the ID would be created when the entity is saved into the database context.
I've therefore tried all sorts of ways of marking the ID column as database generated, but haven't managed to find anything. Strangely, I can't seem to find even one post of someone asking for this - surely I can't be the only one?!
I noted that when looking at the EF modelbuilder (for example here: http://forums.asp.net/t/1848984.aspx/1) there appears to be a means of affecting the model builder with a .HasDatabaseGeneratedOption property, but no similar option exists in the System.Web.Http.OData equivalent.
So the questions therefore are:
Is there a means of altering the model builder (or something else) so that the controller will accept the object and deserialize the entity even with a null key value?
If so, how can I do this?
If not, any suggestions as to other options?
I realise that I could potentially just populate the object with an (in this case) integer value from the client request, but this seems a) semantically wrong and b) won't necessarilly always be possible as a result of the client toolkit that might be used.
All help gratefully received!
Many thanks,
J.
You need to create a viewmodel for insert which does not contain the ID parameter. Use Automapper to map the properties of the incoming insert-model to your data entities.
The problem that you're having is that ID is a required attribute in your data model because it is your PK, except during insert, where it shouldn't be specified.
In my case, my database-generated key is a Guid.
As a work-around, in my TypeScript client code, I submit (via http POST) the object with an empty Guid like this: Note: ErrorId is the key column.
let elmahEntry: ELMAH_Error = {
Application: 'PTUnconvCost',
Host: this.serviceConfig.url,
Message: message,
User: that.userService.currentUserEmail,
AllXml: `<info><![CDATA[\r\n\r\n${JSON.stringify(info || {})}\r\n\r\n]]></info>`,
Sequence: 1,
Source: source,
StatusCode: 0,
TimeUtc: new Date(Date.now()),
Type: '',
ErrorId: '00000000-0000-0000-0000-000000000000'
};
Then, in my WebApi OData controller, I check to see if the key is the empty guid, and if so, I replace it with a new Guid, like this:
// POST: odata/ELMAH_Error
public IHttpActionResult Post(ELMAH_Error eLMAH_Error)
{
if (eLMAH_Error.ErrorId == Guid.Empty)
{
eLMAH_Error.ErrorId = Guid.NewGuid();
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.ELMAH_Error.Add(eLMAH_Error);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (ELMAH_ErrorExists(eLMAH_Error.ErrorId))
{
return Conflict();
}
else
{
throw;
}
}
return Created(eLMAH_Error);
}