Binding lists of objects in MVC3 - c#

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.

Related

Assign Different Type to Class Property

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

Distinct event types on same collection - MongoDB and .NET Core

I want to use MongoDB to store domain events in a system written with .NET Core and C#.
I've googled a little about this, and it seems it is a common practice to have a single collection called events and simply store all events there. I've also seem people to create one field type to distinguish events. An example of this is Slide 66 of this presentation.
So if I wanted to save one UserCreated event I would add it with type user-created, and so forth.
Now I'm in doubt with respect to the mapping when it comes to using .NET Core.
Two distinct events will in general have different schema, so I think that the automatic mapping would do no good. Of course I could use the option of ignoring extra elements. But it may be the case that two events have subsets of properties which are equal, for example, all of them will have a OccurredOn DateTime. I think this could be an issue.
My idea was to query the field type. Something like:
colection.Find(BsonDocument.Parse("{type: user-created}"))
But I don't know if that is the best option, or if there is a way to set up a mapping so that the MongoDrive knows that whenever we try to get an instance of UserCreated it should look just for that type, and when we try to insert, it should create the correct type field.
In that case: given that we save distinct event types to the same collection, what is the correct approach to map this into the right C# event objects?
You could use a container like this one.
public class DomainEventContainer
{
public ObjectId Id { get; set; }
public string Type { get; set; }
public string EventData { get; set; }
}
And then based on the value of DomainEventContainer.Type, you could deserialize EventData into your desired type.

ViewModel with related objects

Relatively new to .Net MVC. Stumped by what appears to be a very simple problem.
I've got a few objects that are related to each other.
(as an example)
public class Asset{
public int Id{get;set;}
public AssetCategory AssetCategory {get;set;}
public string Value {get;set;}
}
public class AssetCategory{
public string Name{get;set;}
public DateTime SomeDate{get;set;}
public int Id{get;set;}
}
I want to create a new "Asset" object in my View and pre so I create an empty one with the AssetCategory set. Then pass it through as the model for that view.
I've tried having a #Html.HiddenFor(m=>m.AssetCategory)
Which obviously fails as it doesn't how how to convert from that object to a string and back.
If I have #Html.HiddenFor(m=>m.AssetCategory.Id) then my ModelState is valid, But doesn't have all the information tied to the AssetCategory.
In this situation, do I just have to get the correct versions of any detached objects from my DB?
As it stands, when I try to save my new Asset. I get an error because the non-nullable DateTime on the AssetCategory object is invalid.
If you only need the category information on the server, then yes, get that on the server and attach to your object before saving it.
You should only include the AssetCategory in your model if your client will change it, ie. you have a dropdown the user can choose from. In that case, add the id only and a list of valid items to your model. When your model is posted back, convert it to the object you need to save.
In other words, keep the classes you have to save to the db, but create a separate view model.
If all you need is the Id then your original option would work (but as you said no other details known based of posted back data only).
#Html.HiddenFor(m=>m.AssetCategory.Id)
If you want more information that that, try to make it modular by using an EditorTemplate.
#Html.EditorFor(m=>m.AssetCategory)
\Views\Assets\EditorTemplates\AssetCategory.cshtml
#model AssetCategory
#Html.HiddenFor(m=>m.Id)
#Html.DisplayFor(m=>m.Name)
That being said, you should be using ViewModels for this sort of thing not EntityModels. What I'd recommend is keep it as passing back only the Id, but then on your postback, load the full asset category info from the database using the AssetCategoryId prior to saving your Asset itself.
For performance EF doesn't load all the data into the model by default. So, you have to load this manually like this:
public ActionResult MyAction(int id)
{
var asset = db.Assets.Single(a => a.Id == Id).Include(a => a.AssetCategory);
return View(asset);
}
The Include method will load the related object into its model, so you will get all properties and #Html.HiddenFor(m=>m.AssetCategory.Id) will have the Id filled with the correct data.
Take a look at Loading Related Objects for more EF Related information!
Hope Its help you!

Data serialization with and without specific field

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
}

When I use projection to create a flatten ViewModel I lose metadata

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

Categories