I'm creating a prototype mobile app that will store data locally in an sqLite database and also on the cloud (CloudKit for now). The cloud storage uses a certain way of storing the data, and sqlite uses another.
my class looks like this:
public class MyDataClass {
public int ID;
public string Name;
public string SomeOtherData;
// in reality this has some more logic, and implements INotifyPropertyChanged for all
}
As I see it, there are two ways to store the data:
- Have the class be a pure data class that doesn't know or care about its storage methods. Then duplicate the class and copy data for each data store. So the data store copies would contain all the boilerplate. For example [PrimaryKey] for sqlite and "NamePropertyKey" for CloudKit, etc unique to each storage method.
This method has the advantage of the model class itself being very clean and easy to maintain. But now if I add or refactor a field, I have to change it in 3 spots to sync the changes to the databases.
So here you'd have my above class, plus another class for SQL Looking like this:
public class MySQLDataClass {
//Constructor needed here to map all the fields over from base data class
[PrimaryKey] [Column("id")]
public int ID { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("someotherdata")]
public string SomeOtherData { get; set; }
}
Plus a similar class for CloudKit
- Have all the boilerplate garbage included in the main data class. This would clutter up the class significantly.
This method has the advantage that there is a single version of truth. I only have to add a new field in one spot. However, It couples the data model heavily to the storage methods. If I decide to drop support for Cloudkit, or add support for AWS, I would need to heavily modify my data class, which might break the local database functionality.
public class MyCombinedDataClass {
//for cloudkit
const string NamePropertyKey = nameof(Name);
// No Constructor needed to map fields, since this is base data class
[PrimaryKey] [Column("id")]
public int ID { get; set; }
// This is for cloudkit since it can't really use ID.
public Guid guid { get; set; }
[Column("name")]
public string Name { get; set; }
[Column("someotherdata")]
public string SomeOtherData { get; set; }
// plus more boilerplate plus INotifyPropertyChanged
}
I'm currently going with option 2. But I can see it getting unwieldy as my data class is growing out of control with only a few fields so far.
I'm sure this is a pretty common problem in apps that have multiple sources of data storage. Are there any ways to elegantly deal with this problem? Any ideas how to improve my design?
For completeness I'm currently coding for Xamarin.IOS as a proof-of-concept, but have future plans to support android using another database system other than CloudKit.