What does Realm Database save? Only variables or functions as well? - swift

In this simple class:
class Simple: Object{
#objc var name: String = ""
func doSomething(){}
}
When I save this into Realm, what does get saved? The variable only or the function as well? The reason I am asking this, is because when I got a lot of Simple objects, I do not want to save the functions ofcourse. The objects would get bigger causing a negative influence on performance.

The variable. It creates a 'column' named "name". Check the realm docs.
Also if you have a lot of data and you would like to browse it you could do it with this Realm Browser where you can see clearly your realm database structure.

You should read through the official documentation and especially the part about supported model properties, which clearly mentions what you can persist in Realm objects.
You can only save properties of certain supported types (Int, String, etc.) or references to other Realm objects (as one-to-to, one-to-many or inverse relations), but you cannot save function references and it wouldn't make sense anyways.
You can add ignored properties and functions to your Realm model classes, but they will only exist in memory, they won't be saved to Realm. For functions this is all you actually need, it wouldn't make any sense to save a function to local storage.
Also, your current model is flawed as your name property is missing the dynamic keyword in its declaration and hence it cannot be treated as a Realm property.

Related

What are the disadvantages of using records instead of classes?

C# 9 introduces record reference types. A record provides some synthesized methods like copy constructor, clone operation, hash codes calculation and comparison/equality operations. It seems to me convenient to use records instead of classes in general. Are there reasons no to do so?
It seems to me that currently Visual Studio as an editor does not support records as well as classes but this will probably change in the future.
Firstly, be aware that if it's possible for a class to contain circular references (which is true for most mutable classes) then many of the auto generated record members can StackOverflow. So that's a pretty good reason to not use records for everything.
So when should you use a record?
Use a record when an instance of a class is entirely defined by the public data it contains, and has no unique identity of it's own.
This means that the record is basically just an immutable bag of data. I don't really care about that particular instance of the record at all, other than that it provides a convenient way of grouping related bits of data together.
Why?
Consider the members a record generates:
Value Equality
Two instances of a record are considered equal if they have the same data (by default: if all fields are the same).
This is appropriate for classes with no behavior, which are just used as immutable bags of data. However this is rarely the case for classes which are mutable, or have behavior.
For example if a class is mutable, then two instances which happen to contain the same data shouldn't be considered equal, as that would imply that updating one would update the other, which is obviously false. Instead you should use reference equality for such objects.
Meanwhile if a class is an abstraction providing a service you have to think more carefully about what equality means, or if it's even relevant to your class. For example imagine a Crawler class which can crawl websites and return a list of pages. What would equality mean for such a class? You'd rarely have two instances of a Crawler, and if you did, why would you compare them?
with blocks
with blocks provides a convenient way to copy an object and update specific fields. However this is always safe if the object has no identity, as copying it doesn't lose any information. Copying a mutable class loses the identity of the original object, as updating the copy won't update the original. As such you have to consider whether this really makes sense for your class.
ToString
The generated ToString prints out the values of all public properties. If your class is entirely defined by the properties it contains, then this makes a lot of sense. However if your class is not, then that's not necessarily the information you are interested in. A Crawler for example may have no public fields at all, but the private fields are likely to be highly relevant to its behavior. You'll probably want to define ToString yourself for such classes.
All properties of a record are per default public
All properties of a record are per default immutable
By default, I mean when using the simple record definition syntax.
Also, records can only derive from records and you cannot derive a regular class from a record.

Should I use Classes or Structs in a YapDatabase?

I have a simple data structure for storing a User:
struct User{
let id: String
var name: String
}
I'm confused as to whether I should be using a Struct or a Class. I've consulted Apple's documentation:
In an app that consults a remote database, for example, an instance's identity may be fully owned by an external entity and communicated by an identifier. If the consistency of an app's models is stored on a server, you can model records as structures with identifiers.
Local changes to model types like PenPalRecord are useful. For example, an app might recommend multiple different penpals in response to user feedback. Because the PenPalRecord structure doesn't control the identity of the underlying database records, there's no risk that the changes made to local PenPalRecord instances accidentally change values in the database.
This would suggest using a struct, since I wouldn't want to accidentally modify the model in the database, the YapDatabase being a a key/value store. YapDatabase is clear that you can store both Structs and Classes. Yet most of their documentation seems to suggest using a Class.
Any thoughts?

NSManagedObjectID vs custom UUID identifier attribute - fetch performance

I would really like to avoid using NSManagedObjectID as a way to connect my model structs to their CoreData objects. I mean something like this:
Say I have a Book entity in CoreData and then I have a model struct like this representing it for my model layer:
struct BookModel {
let name: String
...
let objectID: NSManagedObjectID // I need this to refer back to the entry in the database
}
I don't like this approach. It makes working with the structs tedious and, for instance, testing is annoying because I always have to generate dummy objectIds or make BookModel.objectID optional.
What I would love to have is an id property of type UUID inside the Book entity. This would be so easy to connect to structs and also allows the structs to properly exist without a database:
struct BookModel {
let name: String
...
let id: UUID
...
func object() -> Book {
// Retrieve managed object using a fetch request with a predicate.
}
}
I've noticed that you can actually have UUID properties in an entity. However, the performance difference seems to be enormous. I've created an example that tries to fetch individual objects 10000 times.
First, I fetched them using the contexts object(with: NSManagedObjectID). I hard-coded all the possible objectIds in an array and passed a random one each time.
Then, I used a simple fetch request with a NSPredicate that got passed a random UUID.
The difference in execution time is significant:
With ObjectID: 0.015282376s
With UUID: 1.093346287s
However, the strange thing is that the first method didn't actually produce any SQL queries (I logged them using the launch argument -com.apple.CoreData.SQLDebug 4). This would explain the speed but not why it doesn't need to communicate with the database at all.
I researched a bit but can't really figure out what object(with: NSManagedObjectID) actually does behind the scenes.
Does this mean, using a "custom" UUID property is not a good idea? I would really appreciate any insights on this!
I would not rely on the NSManagedObjectID in your code. It makes your code dependent on Apple's database implementation, which may change at any time, and it would not make your app resilient against future changes.
By way of example, you would not be able to use the new NSPersistentCloudKitContainer. It does not support NSManagedObjectID: see https://developer.apple.com/documentation/coredata/mirroring_a_core_data_store_with_cloudkit/creating_a_core_data_model_for_cloudkit
Instead of hardcoding NSManagedObjectID you are better off giving your entities unique UUIDs, as you have suggested. This may or may not affect performance, but you are better off in the long run, as the underlying core database technologies will shift.
You should just use a String to represent the NSManagedObjectID. To convert from NSManagedObjectID to string is easy:
objectID.uriRepresentation().absoluteString
To convert from String to NSManagedObjectID is slightly more complicated:
if let url = URL(string: viewModel.id),
let objectID = context.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: url)
This will make your model objects cleaner.
NSManagedObjectID is good to be used within one application on one device, but it should never be stored and referenced across different applications on different device. I think it is not true that NSManagedObjectID is not supported for CloudKit.
As per why object(with: NSManagedObjectID) is fast. The document says it returns:
The identified object, if its known to the context; otherwise, a fault
with its objectID property set to objectID.
This means that if the object has been loaded before, it will return it immediately, if it has not been loaded before, it will return a fault. If you want to trigger a SQL to happen for a good comparison, you need to access one of the attributes after you call object(with: NSManagedObjectID). I would assume the performance should be very similar to the one using UUID.

Can I get the object from the database, without knowing what type of the object is?

I have the class GraphHandler. Inside of superclass I try to handle restoring the object that was last saved into the database. For this I'm using primaryKey.
The point is that a the time of restoring I don't know yet which type should I expect. So I tried with this:
let realm = ClientManager.cacheRealm()
realm.object(ofType: Object.self, forPrimaryKey: "uniqueid")
But I get the error:
Terminating app due to uncaught exception RLMException, reason: 'Object type RealmSwiftObject is not managed by the Realm. If using a custom objectClasses / objectTypes array in your configuration, add RealmSwiftObject to the list of objectClasses / objectTypes.'
Im trying to do it a way that the handler don't need to know in advance which type of object was saved last. What can solve this? I think that implementing generics won't do any good to it as I can't be changed on the fly.
By the time you call the function realm.object, the type of the object needs to be known, since using this function, realm is only searching for objects of a specific type. Moreover, the type of primary key can be different as well, hence the type of object you are looking for needs to be known before querying realm.
Querying all types and filtering afterwards is only not an option at the moment, since Result can only store a single type of objects. However, if you really need to query all types using a single query to get the last database entry regardless of what class it had, have a look at this comment on a related GitHub issue, where Realm engineers give some workaround for the issue.
Another workaround you could try is the following: create a TimeStamps class, which is managed by Realm, has only a single entry in Realm and which has a one-to-one relation to each of your other Realm classes. The object on the other side of the one-to-one relation would always be the object that you added the last time to Realm of that specific class. With this approach, if you are looking for the latest object added to realm, you can use a simple query that retrieves the only TimeStamps object you have and you can filter for the object added last by filtering the one-to-one relations TimeStamps have. Of course for this to work, you need to associate the creation date of your objects with the relationships you are storing in your TimeStamps object and update these relationships in each of your write transactions.

Breeze JS Adding a static Lookup dictionary to Metadata

One of my domain models has an Enum property that I like to create a dropdown box for, but the EFContextProvide Metadata function doesn't automatically import the Enum Entity Type for me to access it, so I created a static dictionay of that I like to add to the Metadata Mapping, acting as a lookup table. How can I add Enum entity type, so I can call:
breeze.EntityManager.createEntity(myEnum,...)
right now, I get the following error:
Error: Unable to locate an 'Type' by the name: myEnum
Any suggestion?
UPDATE: (I just added the enumType info of the Metadata function call)
"enumType":{"name":"Plugins","isFlags":"false","underlyingType":"Int32","member":["name":"Custom","value":"0"},{"name":"PluginOfTypeA","value":"1"},{"name":"PluginOfTypeB","value":"2"}]}
Thanks #Jay for your response, I was set in the right direction. Here is what I can say about dealing with Enum:
I created a lookup list on the server that I can separately call, to populate the dropdown list. I have a regular array that I initialize on the success promise of the results, list this data.results[0].myEnumLookup and then on the Viewmodel, I access that property and set in to the ko.observableArray() so I can refer to it in my View. Make sure you set the value: property of the select tag, to the value of item.
But the problem with doing it this way was that at the Save time, it wasn't reading Enum value and it was treating it as just text, so it was failing, so
More robust solution:
In our application we happen to really benefit from having an Enum and their pre-compile value, since we are using those Enum Domain models in other POCO projects, so I ended creating an EF DbSet and proper table that will be populated with all of my Enums values and I can save them into the DB, so now we have the list of items in DB, and I created a single level of inheritance for Enums, so in my controller, I get a IQueryable method that will get all of those Enums, and in the breeze application, in my config file, I define the types of enums, and then I will populate lists of items based on different types in my config, so I can refer to it in my view and binding it to the ko.observableArray(). Also in my original class, I no longer refer to the Enum, I will create MyEnumId as well as virtual MyEnum property that will do the mapping automatically in my EF5 setup.
Lesson I learned, even though Enum in .NET4.5 & EF5 is possible to store and read back, but it's not very practical when it comes to SPA front-end technologies, so I prefer having the integer value, and just manage the enums outside of it.
Not entirely sure I understand the question. By 'Enum entity type' do you mean an 'EntityType' that only has a fixed number of possible instances? If so, you can simply query the entire collection of these entity/instances onto the client and add them directly into your static dictionary. Since, the collection is conceptually immutable, you can query this at the beginning of you session. Further, you should NEVER need to create an instance of any of these 'entity enums' because you can always extract them from your dictionary.
But maybe I'm not understanding your question.