I like the idea of Records mainly because we can get away from using someObject.get('someKey')
But Record seems to operate more like some kind of template for records.
If you just instantiate Record each time you need a read only immutable object, simply because you like to access properties as someObject.key, would this be a bad idea?
A call to Record returns a traditional JS type (class) when you call it. Ideally you should store this type reference and create new record instances from it. Otherwise stuff like inheritance-check doesn't work as intended.
You should prefer Record over traditional JS objects or Immutable Maps because of the integrity and immutability it offers while retaining the first class member access. However don't create a Record from a Map just for the sake of syntax convenience, you should use Record in place of the said Map everywhere.
Said that, bear in mind that Record has its own baggage of issues. You can read about it in my other post here... https://stackoverflow.com/a/36357288/2790937
Related
I'm building an api that receives webhook data (orders from shopify) and saves them to a relational mysql database. Each order has products in it that belong to collections (categories). I relate the product to the collection, or create a new collection if it doesn't already exist. The problem I run into is that since I can't use findOrCreate() I do a find() first, and then if nothing is found I do a create. However, since nodejs is async, if I get many orders coming in at once, sometimes the same collection isn't found for two different products at the same time, and then one will create it right before the other one tries, so when the other one tries to create it waterline throws an error:
col_id
• A record with that col_id already exists (405145674).
What is the best way to catch this error so I can just do another find() so the function returns the proper collection instead of an undefined? I could just do this:
if (err){ findmethodagain(); }
But then it would try that for any error, not a "record with that id already exists" error.
If you're not seeing this a lot, it wouldn't hurt to just do a second attempt after a delay. You can use Promise.delay from, for example, Bluebird to run a second function after some number of milliseconds on any error. If in most situations one of them creates the collection, then you'll succeed with just one retry.
If you are seeing lots of other errors, well, fix them.
However, race conditions usually indicate that you need to rework the architecture. I'd suggest instead of relying on error attributes or trying to hack around them, you redesign it, at least for the situation where you have to create a new collection. One popular option is to set up a worker queue. In your case, you would just use find in the first pass to see if a collection exists, and if not, kick it off to the queue for a single worker to pick up sequentially. In the worker job, do your find then create. You can use Redis and Bull to set this up quickly and easily.
I am almost done researching for my application. The last thing that I need to be able to learn how to do is the following situation: Let's say I have created a UItableview drilldown app, but once the user gets to the end of that drill down (their choices on a specific dog product for instance are now very specific), they can save that information. What I want my app to do here is, at the end of the drilldown, save their entire nsindexpath as another entity so that I can send this information later up to my MySQL database. My question is, how could I re-save an nsstring from an nsindexpath in another entity?
Start writing code instead of researching your entire app's architecture before you start it. You really only will learn from actually programming.
Use Core Data
Use tableView:didSelectRowAtIndexPath: to obtain the selected tableview cell's indexPath and store the indexPath or the data as needed.
I agree with runmads suggestions. CoreData will probably make your life easier in the long run. To answer your question though:
Don't save the table view's NSIndexPath. The selection index path is a view related property (in MVC terms). Your users choice belongs to the model domain. It's bad practice to mix the two and if you later insert new choices in one of your tables, your stored index paths will become invalid.
Instead create something like a UserChoice object or a dictionary or an array which you can pass down your tableview controllers as the user drills down. When the user selects a cell, add the primary key of the associated data object to your array. At the end, store the primary keys you've collected along the way into your database.
I have two entities which are Student and Class entities.
Student and Class are many to one relationship. So student contains class attribute.
Now i want to save or create a student associate with existing class(means i know primary key ID already).
Solution 1:
Student student = new Student();
Class class = session.load(classId);
student.setClass(class);
session.save(student);
Solution 2:
Student student = new Student();
Class class = new Class();
class.setClassId(classId);
student.setClass(class);
session.save(student);
My question here is in solution 1 it will issue two SQL, one is to get Class another is to insert student. But in solution 2 only need to have one SQL. If I have more class attribute,
i will load and issue more select sql before insert. It seems not that efficient. Is there any side-effect in solution 2?
which way to do save/insert is better? By the way, i do not set up cascade.
Thank you
Yee Chen
Solution 1 won't issue an SQL query to load Class. Unlike get(), load() returns a proxy object with the specified identifier and doesn't perform a database query immediately. Thus, load() method is a natural choice for this scenario (when you actually need to load an object, use get()).
Possible side effect of solution 2 depends on cascading configuration of relationship and so on. Even if it works fine in your current case, it makes your code more fragile, since seemingly unrelated changes in the code may break it.
So, I recommend you to use Solution 1 and don't worry about performance.
Is there any side-effect in solution 2?
First of all, you haven't associated your student with any class there.
Secondly, where do you get that class id from in the general case? At some earlier point in time, you had to either fetch an existing class instance from the DB, or create a new instance and persist it, so that you get its id. Of course, reusing an entity you already have is fine, but juggling with ids like you do above is IMHO not.
Thirdly, it is not a good idea to prematurely optimize your app. Get it to work properly first, then measure performance, and optimize only if and where needed.
I've been battling this for a while. I'm trying to implement a many to one association. I have a bunch of rows in a table, called readings. These accumulate over time, and every now and then I want to export them. When I export them I want to create a new object called ExportEvent, to track which rows were exported, so they can be re-exported if need be. Therefore Reading has a nullable foreign key relationship with ExportEvent, as I create the readings before I export them.
What I'm finding is that when I then do the export, whether I first create the ExportEvent (evt) and add the readings using
evt.Readings.AddRange(),
or if I use
foreach(reading)
reading.ExportEvent = evt
When I call SubmitChanges I am always getting a new bunch of readings created with the association to evt, and the original records aren't updated.
I pared this back to its simplest though, just to see if I could create the two objects with no association, and I even found when I just retrieved all the readings and updated an int value on them, submitchanges still inserted a bunch of new records. What's going on?
Hmmm. Interesting - just clicked this link in my bookmarks, and found that the question has been resurrected, so will provide the (embarrassing) solution. All of my entities have audit data properties on them - CreatedDate and UpdatedDate. Therefore I've implemented the partial methods for the insert and update of each entity in the datacontext. I had copied and pasted (how often is this the cause of some downfall) some of these insert and update methods for the newly created entities. As a result I'd also copied an error, where the Update[blah] methods were calling ExecuteDynamicInsert, instead of ExecuteDynamicUpdate.
Suffice to say I was very frustrated when for 3 hours I'd been trying frantically to solve this problem, only to find it was due to a (silly) copy/paste error - and only to find the error about 3 mins after I'd posted this question!
Hope this helps someone.
I suspect it is because you are calling AddRange(). This will add the new objects to the data context. Instead, you should try just re attaching the existing objects by called Attach() on your data context.
(Or if you never detached them and still have your original data context, you don't need to do anything, just make the changes to the objects and call SubmitChanges())
I have a question related to this one. I don't want to do a calculation (aggregation), but I need to get display values from an association. In my C# code, I can directly reference the value, because the foreign key constraint made Linq generate all the necessary wiring.
When I specify the IQueryable as the Gridview datasource property, and reference something that is not a column of the primary entity in the result set, I get an error that the column does not exist.
As a newbie to Linq, I am guessing the assignment implicitely converts the IQueryable to a list, and the associations are lost.
My question is, what is a good way to do this?
I assume that I can work around this by writing a parallel query returning an anonymous type that contains all the columns that I need for the gridview. It seems that by doing that I would hold data in memory redundantly that I already have. Can I query the in-memory data structures on the fly when assigning the data source? Or is there a more direct solution?
The gridview is supposed to display the physician's medical group associations, and the name of the association is in a lookup table.
IQueryable<Physician> ph =
from phys in db.Physicians
//from name in phys.PhysicianNames.DefaultIfEmpty()
//from lic in phys.PhysicianLicenseNums.DefaultIfEmpty()
//from addr in phys.PhysicianAddresses.DefaultIfEmpty()
//from npi in phys.PhysicianNPIs.DefaultIfEmpty()
//from assoc in phys.PhysicianMedGroups.DefaultIfEmpty()
where phys.BQID == bqid
select phys;
(source: heeroz.com)
So, based on Denis' answer, I removed all the unneeded stuff from my query. I figured that I may not be asking the right question to begin with.
Anyways, the page shows a physician's data. I want to display all medical group affiliations in a grid (and let the user insert, edit, and update affiliations). I now realize that I don't need to explicitly join in these other tables - Linq does that for me. I can access the license number, which is in a separate table, by referencing it through the chain of child associations.
I cannot reference the medical group name in the gridview, which brings me back to my question:
AffiliationGrid.DataSource = ph.First().PhysicianMedGroups;
This does not work, because med_group_print_name is not accessible for the GridView:
A field or property with the name 'med_group_print_name' was not found on the
selected data source.
Again, bear with me, if it is all too obvious that I don't understand Linq ... because I don't.
Your query seems strange. You should try to simply display
ph = from phys in db.Physicians
where phys.BQID == bqid
select phys;
in your grid. That should work.
Also, why the calls to Load()? If the DataContext is not disposed when the grid is binding, you should not need it.
If you still have issues, can you please post the error message you get, that would help...
Part 2
The problem is that you have the name is effectively not in the PhysMedGroup. You need to navigate one level down to the MedGroupLookup to access the name, since it is a property of that class.
Depending on the technology you are using (it seems to be either WinForms or Web Forms), you will need to configure your data-binding to access MedGroupLookup.med_group_print_name.