I'm currently developing an application based on no-sql (using raven db). The core aspect of this application is a tree-like data structure with many nodes, subnodes and so on.
Currently, each node or subnode is represented by a c# object. A parent-child relationship is made with a collection of subnodes on the parent node, a forward-only relationship.
The whole thing is handled by ad hoc forms, in an Mvc application, with proper GETs and POSTs for each data type. The whole graph is stored as JSON on Raven DB.
Now the goal is to modify the UI part using knockoutjs. Since KO works with json data structures as well, I was wondering if there is a way to make the ravendb json structure "knockout compatible", meaning I can directly use it without having to make a KO specific structure (to implement observables, etc) and then create a mapping between the two.
A sample of the object graph:
public class NodeA
{
public string Name {get;set;}
public List<SubNode> Childs {get;set;}
}
public class SubNode
{
public string Name {get;set;}
public bool SomeBool {get;set;}
}
public class NodeB
{
public string Name {get;set;}
public int SomeInt {get;set;}
}
public class GraphToStore
{
public List<NodeA> NodeAList {get;set;}
public List<NodeB> NodeBList {get;set;}
}
The read/write part would still be handled server side, with ajax calls after stuff gets updated on the UI. Validation would be server-side and returned to the client via ajax calls too. My problem is as I said making the ravendb json work with knockoutjs, otherwise I have to reconstruct the whole thing and map it, and the graph is huge (50+ classes).
Take a look at Knockout-mapping-plugin. It will "automagically" generate the knockout compatible viewmodel with one call.
You would do something like
var viewModel.myRavenDbData = ko.mapping.fromJSON(json data variable);
var unwrappedData = viewModel.myRavenDbData(); // need only if viewModel.myRavenDbData is an observable
After you have this working, breakpoint after the call to mapping and explore the data structure. Generally, it will look like your data structure with ko.observables for the actual values. All the nodes needed for navigation will be normal javascript objects.
Yes you can use the Knockouts Mapping capabilities and create ViewModels directly from the model objects. But, I have two points:
1) I think that the fact that the objects are stored in RavenDB does not metter. Your MVC applications retrieves the objects from RavenDB - so they are deserialized from JSON and than they are served to your JS page via REST interface, so they are serialized again into JSON. So you are not working directly with the RavenDB's JSON structure, it is a standard CLR object serialized to JSON.
If you want to work directly with Raven, you have to plug your application directly to raven's interface - and that is not a good idea (but of course in the metter of performance it should work great).
2) I don't think that it is good idea to use your model objects as ViewModels, only by using the knockout mapping plugin.
Soon you will need to add some logic to the view model. Either for computing values to be showed in the view, or adding some action logic (save/edit...etc).
For the first case, you can define your viewmodels on the server side and use the mapping plugin.
For the later, you will have to write the view models in javascript anyway. I would recomend start writing the viewmodels in javascript directly.
It works the best for me.
Related
I have created a class to store data from API calls I am making. It returns JSON with some meta information, and then an array of data depending on the call being made. The meta information will always have the same fields, so I have created a "Root" class for this, but the data will be different depending on the call being made, so I have created different classes for each type of data, e.g. user data, company data, etc. As shown below, I currently have the "data" property set to a list of objects, but I am trying to figure out the best way to incorporate the different types of data that can be returned, since it will vary based on the call being made.
Right now I have the data saved as a list of objects, but I would like this to change depending on what data I am receiving. Like, if I am retrieving users, I would like for it to be a list of users.
What is the ideal way to accommodate for this? The only way I can think to do it now is to create a different "Root" class for every type of data I am expecting to receive, but that doesn't feel like it should be the most concise way to do it. I was looking into making this a factory design pattern but I wasn't sure that it fit this scenario.
Just use a generic base class:
public abstract class ApiCallResult<T>
{
// With your properties
// public int Limit { get; set; }
// [...]
//
public IEnumerable<T> Data { get; set; }
}
Then define a result per api call.
public class UserApiCallResult : ApiCallResult<User>
{
}
Created a small working example here:
dotnet fiddle
I am struggling to implement MVVM pattern in my current project.
"ClassA" continuously gets required data from a remote device and stores this data inside it's fields. It is a model, I guess. ClassA updates required information via Update method.
"ClassB" continuously gets the data from "ClassA" and stores it in corresponding properties. Looks like it is a view model.
View is a simple MainWindow.xaml with a DataGrid inside.
I have the following questions:
1) How do I update ViewModel?
Should ClassB have an Update method, which accepts an instance of ClassA and updates corresponding fields?
2) Where do I store an instance of ClassA?
Should ClassA be a field of ClassB? If it should, then how do I update Model?
I thought of something like the following:
public void UpdateB()
{
ClassA.UpdateA();
this.FieldOne = ClassA.FieldOne;
this.FieldTwo = ClassA.FieldTwo;
}
4) Does model have it's update method at all or model just stores the data?
3) What do I do inside MainWindow.cs, aside from windows initialization? Do I update view model (ClassB) there?
I find it best to have a object representing an item in each layer of abstraction. This includes the form of the data as it exists on the disk. Remember that in MVVM, the only real goal is to promote loose coupling between the interface(User Interface) and the implementation(ViewModel functionality).
For example, if I have objects stored in XML files, I will have an object in my data access layer that exists only for the proper management of the XML data. Let's call it ObjectXml. This object only contains data in the form that is native to the data on the disk. In this case, all data has a string representation, as in the XML files.
In the model layer, you will have the data representation of the XML file in the expected data types. Let's call this Object. The property getters and setters may access and set the string representation of the data by performing conversions in both directions. This way, the data is ready to be persisted to the data source(xml file, database etc.).
In ObjectViewModel, properties may access those in Object. The viewmodel contains all the members for representing and modifying the model.
Note that ObjectXml is really only beneficial when you are only allowed to store string information, or when a suitable schema does not exist for your data types.
At the end, you have a hierarchy of containment such as the one below:
public class ObjectXml
{
[XmlArray("People"), XmlArrayItem("Person")]
public List<PersonXml> People { get; set; }
//PersonXml is an xml data model similar to this one
[XmlElement("Item")]
public string Items { get; set; }
}
Here is the model for the Xml object:
public class Object
{
private ObjectXml _xmlContext;
public Object(ObjectXml xmlContext)
{
this._xmlContext = xmlContext;
}
public List<Person> People
{
get
{
//Person requires a constructor that takes a PersonXml object in order for this to work properly
return this._xmlContext.People.Select(x => new Person(x)).ToList();
}
set
{
this._xmlContext.People = value.Select(x => new PersonXml(x)).ToList();
}
}
public double Item
{
get { return double.Parse(this._xmlContext.Item); }
set { this._xmlContext.Item = value.ToString(); }
}
}
Obviously, it's not wise to name your class Object as it's a reserved word in C#. Hopefully I've given you some ideas of how to access and update data in a robust and extensible manner.
In short, you don't need an update method at all. Also, short of constants and property backing fields, there are very few reasons to need direct field access in C# MVVM.
See below. Do not listen to people that say the ViewModel and Model need to be decoupled. The main purpose of the model is an intermediary layer that prepares data to be saved or loaded into the program and to store data in a way that is agnostic to both the data and the program functionality(ViewModel)
You do not need an update method. Use properties that access the data model and persist to the data storage(xml, database etc.) if needed.
You do not need an update method.
You should not have to do anything inside of ViewModel.cs. Only code that modifies the view should be in the codebehind. The only ViewModel you should ever access in a view is one that follows the form of MainWindowViewModel, which is more like an ApplicationViewModel that carries instances of other required viewmodels.
Finally, don't get stuck using an overcomplicated MVVM "framework" as most of the functionality is not useful or necessary.
Like stated in Yuris comment, you should not use any update method, but rather implement the INotifyPropertyChanged interface. Like the name says this notifies all subscribers when the value of a certain Property changed.
This is a nice article which contains code to a minimalistic MVVM implementation. If you have trouble implementing the pattern from scratch, try to start with this example and replace the existing classes with your own one-by-one.
As to the update mechanic inside your MainWindow.cs - you don't need any, if you specify the DataBinding in your xaml code like it is done in the example linked above.
I hope this helps you getting started!
I have a simple set of 20+ classes. They are all serializable to allow use of these objects within a web service. (DataContract/DataMember) Each of them has an ID and a variable number of other properties, depending on the class.
And I have a database which will store just an ID, a Name that identifies the class and an XML string. And this XML is also the same data in serialized form, but without one property: the ID field should not be stored, since it's redundant.
But the ID must still be sent to the client of the web service, making things a bit complex. And although I could just create a copy of each class, where one has the ID as DataMember and the other doesn't, I'm just looking for a much cleaner solution to solve this. One where I would not need to store the ID field as part of the XML within the database.
So, question: what is the simplest solution to make sure the ID becomes part of the data that's sent to the client, but skipped when storing it as XML? (Without the need of hacking in the XML to remove it.)
And although I could just create a copy of each class, where one has
the ID as DataMember and the other doesn't
What about inheritance?
public class MyEntity
{
// some props
}
public class MyEntityWithId : MyEntity
{
public int Id { get; set; }
// some props
}
I have an issue with the project I'm working on. I'm using Entity Framework. Some quick background on the db model:
public class AssetType{
public ICollection<Field> Fields { get; set; }
}
public class Field{
public int Id {get;set;
public string Name {get;set;
}
Now I'm creating a view that would create a new Asset Type. As part of this process the user must also create all of the fields they want for that type. The issue is that I'm not sure how to represent the list of "Fields" on the page. The idea is that the user can add a new field, or remove one at any time with jQuery.
I can't figure how the data could be posted back to the server as part of the form. I thought about constructing the list in JSON form, but this seemed a bit messy. Has anyone got any better ideas?
You're going to have problems with this. The object parser does not handle complex objects very well. Collections usually need to be primitive types, or collections of primitive types themselves.
There are ways to do it, but if this is a requirement for you, I would look at storing your data in a JSON string variable, and parsing it where/ when needed.
Many tutorials say that when i have to pass data from controller to view the best way is to create a flattern viewMoldel.
This solution came to solve also other problems (like the eager loading problem).
My concern is that when i create a flatten viewModel I lose all the informations that I store in the entities via annotation.
Suppose that i have a model composed by
class product{
[DisplayName("Name")]
public String Name{get;set;}
[DisplayName("Image")]
public String Image{get;set;}
[DisplayName("Description")]
public String Description{get;set;}
public String CategoryId{get;set;}
}
class category{
[DisplayName("Code")]
Public String Id{get;set;}
[DisplayName("Category name")]
public String Name{get;set;}
}
To render a grid that show product informations many tutorials say that the best way is to provide a flatten viewModel like this:
class productGridViewModel{
Public String ProductName{get;set}
Public String ProductImage{get;set}
Public String ProductDescription{get;set}
Public String CategoryName{get;set}
}
My concern is that I need to write again all the DisplayName annotations in the viewModel.
If you are flattening your model entities into ViewModels, shouldn't the attributes be removed from the model entity classes and placed on the ViewModels? Your model entities will not be used for display, so they should not have those attributes.
One simple solution is to have read-only properties in the viewModel which read the meta-data of the underlying Model object. Then you can bind this meta-data with the appropriate control in the View.
As below:
class productGridViewModel{
Public String ProductName{get;set}
Public String ProductImage{get;set}
Public String ProductDescription{get;set}
Public String CategoryName{get;set}
public string ProductDisplayName
{
get
{
//Please dont mind this code.. I am sure you can write it in much better way.
return typeof(Producy).GetProperty("Name").GetCustomAttributes(typeof(DisplayName))[0].ToString();
}
}
}
Your view model is your data consumption use case. If you need metadata then the view model flattened or otherwise will need to support it. May be you need to add it dynamically? Or if that's too onerous, then you need to encode it at compile time.
Edit.
You can use T4 transformations to ensure that dependent code it kept up to date. In fact we use this allow users to customise the DB and thus allow express the customisations in the view models.
What you do is put the source of the truth in one assembly, and then use a T4 transform file to create other representations from this assembly using reflection in another assembly.
The way to do it would be by implementing a custom AssociatedMetadataProvider. This isn't as much work as you'd think, and you could implement one to generate metadata from an xml file, database, convention, or even buddy types like the current one does.
The only thing you'd need to do differently to the current implementation is allow buddy types to contain field/properties which don't exist on the model they apply to, because that is the only thing currently preventing you from creating a buddy type which you could apply to all view/editor models of your particula model.
Its a bit of work and depends how much time it would save you but don't forget most of the MVC source code is available and you wouldn't have to change very much
Martin