Glass mapper populate list from Link path - c#

I'm trying to populate a list on my current model with subitems from a different folder.
On my current model I want to define a field of type General Link in which I will select an item from Sitecore who has different subitems.
The "public virtual IEnumerable List" should be populated with the above subitems.
I have read different posts related to how you can make the following type of queries:
[SitecoreQuery("./*[##templatename='Testimonial']", IsRelative = true)]
public virtual IEnumerable Children { get; set; }
but this does not apply in my case because most probably I will have this template in different areas which I do not want to be included here.
Does anyone know if this is possible with Glass or should I just use a custom query to populate the list with an item subitems?

If you use a droplink or droptree field, rather than a General Link, you could do what you want by creating a generic Folder model.
namespace MySite.Models
{
[SitecoreType(AutoMap = true)]
public class Folder<T> : GlassBase
{
[SitecoreChildren]
public virtual IEnumerable<T> Children { get; set; }
}
}
And then use it from another model like so:
[SitecoreField("My Link Field")]
public virtual Folder<ChildModel> MyLinkField { get; set; }

Related

What is best approach for data inheritation in elasticsearch?

I have an parent class and two child like these:
public class Parent {
public Guid Id { get; set; }
public string Name { get; set; }
}
public class FirstChild {
public string IdentityCode { get; set; }
}
public class OtherChild {
public string RegistrationCode { get; set; }
}
There is a question: Is it a good approach to store these two inherited classes in the same Index inside ElasticSearch?
I see there is a _type property that is added to my docs after they are stored in DB but it has always "doc" value.
I test this code to fill it but it seems it is not working this way.
await ElasticClient.IndexAsync<FirstChild>(child, m => m.Index(IndexName));
And Also, I found this question on SO for retrieving my entries from DB but it is outdated and the API is changed and no more accessible.
I want to know if it is a good approach to store sibling data in the same index how can I do this properly.
As of ES 6.0, it is not possible anymore to store multiple types inside the same index, i.e. the _type field you're referring to will always be either doc or _doc. In ES 8.0, the _type field will be removed altogether.
However, if it makes sense for your use case, you can still decide to store several types inside a single index using a custom type field that is present in your document.
You should strive to only store in the same index data that share the same (or very similar) mapping, which doesn't seem to be the case for Parent, FirstChild and SecondChild, but if you add a public string type property to your classes you can still do it.

MVVMCross add multiple dynamic properties to viewmodel

I have an requirement to render the screen (screen type : form) dynamically based on the service response (rather than defining the UI manually). I was able to successfully bind predefined properties to dynamically created textboxes & textviews. Following is the sample code that used to bind predefined property to dynamic textbox
Type myType = typeof(DynamicViewModel);
PropertyInfo myPropInfo = myType.GetProperty(nameof(dynamicProperty)); //dynamicProperty -static property in VM
var set = this.CreateBindingSet<DynamicActivity, DynamicViewModel>();
set.Bind(editText).To(myPropInfo.Name); //editText - dynamically created textbox
set.Apply();
But the code needs to be further improved by dynamically creating the no of properties - matching with the no of UI elements dynamically created.
The project is created using Xamarin.Android with MVVMCross's latest version. Please share the way to generate dynamic string(or object type) properties in viewmodels that can be binded with dynamically generated view elements(textboxes & textviews).
Thanks
There are a couple of ways to do this.
One is using Reflection as you are doing there, but you could have performance issues.
The other way is to arrange a bit the data and model you are getting from the server to be something like you can then use some Factories to build your View/VM:
So it could be:
public enum DataType
{
String,
Number,
Boolean,
List,
// and any other types that you need
}
public class OptionItemModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FieldModel
{
public DataType Type { get; set; }
public string DefaultValue { get; set; } // this is a serialized value
public List<OptionItemModel> Options { get; set; } // this only applies to DataType -> List
}
public class StructureModel
{
public List<FieldModel> Fields { get; set; }
}
So then you can have an ObservableCollection on your VM and your items can be created by a factory iterating for each one of the fields of the structure and so you can have custom Item View Models depending on the DataType of the field.
Then you can have a List on your View that uses a Template selector where you can create the Cell/Row depending on the DataType or the ItemViewModel and that would be it.
Then you can have a similar model structure to fill the values and upload them to the server.
Hope it's clear enough

How to work with advanced entities which does not fit table data in MVC?

Lets say we have a Person entity which fits table exactly:
public class Person
{
public int Id { get; set; }
public int Type { get; set; }
}
Now user have a type, and only if user is of specific type I want to be able to find out what is the Name of that type that person is. Right now I just add extra property on to the entity:
public class Person
{
public int Id { get; set; }
public int Type { get; set; }
public string TypeName { get; set; }
}
But I want to let my entities stay as clean as possible.
Do I need to create a separate "advanced entities" classes for this cases or how do I get around those cases?
PS. I am using stored procedures.
Your question is not clear but i think you are mixing view models with entities. If you want to store your user "Type" into the database then, yes you have to add a new field in your entity ( or use partial classes ) OR if you are using database first then add the field in your table and refresh your edmx . If you don't want to store it in database, just create a view model and use it on our UI.
Change that name to something specific about a person, whatever you want to track about a person (HairColor, EyeColor, Nationality, Size) anything but just plain "Type", which is a system base class in C#.
yes... use partial clases with extended properties inside them

An alternative lookup table approach needed to make C# models more generic

I currently have the following Models in my EF Code First MVC project (edited for brevity):
public class Car
{
public int Id { get; set; }
public string Descrip { get; set; }
// Navigation Property.
public virtual CarColour CarColour { get; set; }
... + numerous other navigation properties.
}
public class CarColour
{
public int Id { get; set; }
public string ColourName { get; set; }
}
The CarColour table in the DB contains many rows.
In my project, I have about 10 of these sorts of tables, which are essentially lookup tables.
Rather than have 10 lookup tables (and 10 corresponding 'hard' types in code), I was tasked with implementing a more re-usable approach, instead of having loads of lookup tables, specific to Car (in this example), along the lines of having a couple of tables, one of which may hold the item types (colour, fuel-type etc.) and one which contains the various values for each of the types. The idea being that our model will be able to be re-used by many other projects - some of which will have potentially hundreds of different attributes, and as such, we won't want to create a new Class/Type in code and generate a new lookup table for each.
I am having difficulty in understanding the c# implementation of this sort of approach and hope someone may be able to give me an example of how this can be achieved in code, more specifically, how the above models would need to change, and what additional classes would be required to accomplish this?
your base entity must implement INotifyPropertyChanged and make it generic:
public virtual CarColour CarColour {
Get { return this.carColour; }
Set {
this.Carcolour; = value
OnPropertyChanged("CarColour");
}
}
For more info see :
patterns & practices: Prism in CodePlex.
http://compositewpf.codeplex.com/wikipage?title=Model%20View%20ViewModel%20(MVVM)
Greetings
Bassam
This is not necessarily specific to EF but I've been down this road and didn't really enjoy it.
I wanted to use a single table to represent 'generic' information and while I thought it was smart, it soon showed it's limitations. One of them being the complexity you need to introduce when writing queries to extract this data if you're performing more than just 'get colours for this car'.
I'd say, if your data is simple key/value and the value type is always going to be the same then go for it, it might even be worth having this a mere 'meta-data' for an object:
public class Car
{
public int Id { get; set; }
public string Descrip { get; set; }
public MetaData CarColours { get; set; }
}
public MetaData : Dictionary<int, string>
{
public MetaData(int group){}
}
Hypothetical table:
TableMetaData(int metaGroup, int metaId, string metaValue)
If you're hoping to store different types as your value and may need to perform joining on this data - avoid it and be a bit more specific.

IEnumerable<> instead of List<> goes well when reading objects

Consider my following class Album:
public class Album
{
public int? Id { get; set; }
public string Name { get; set; }
public IEnumerable<Photo> Photos { get; set; }
public DateTime Registered { get; set; }
}
I have no troubles retrieving data out and populating my album and my photo collection.
However now I also want to 'Add' a Photo item into my Photos collection, 'Add' is not recognized as a valid method on Photos.
'System.Collections.Generic.IEnumerable'does not contain a
definition for 'Add' and no extension method 'Add' accepting a first
argument of type....
What should I do as a simple thing to get it to work with IEnumerable? I don't want to change my property to
public List<Photo> Photos { get; set;}
Do I really need to implement ICollection on my Album class?
public class Album : ICollection<Photo> { ... }
If you do not want to change the property type to something that allows addition (IList<Photo> or ICollection<Photo>) add a separate method for adding pictures, like this:
public void AddPhoto(Photo p) {
...
}
This would let you keep IEnumerable<Photo> as the type of your property, and also allow for validation of what the callers put in. For example, your code would be able to detect if a photo is too big or too small, and throw an exception. This would be a lot harder to do if you exposed IList<Photo>, because you would need to provide your own implementation that overrides Add.
You should also make the setter of your auto property private, or replace the auto property with a getter + a backing field.
Try making Photos a private List then create a standard property exposing it as an IEnumerable. Then add an "AddPhoto" method to your album object.
This way you allow album to control how it adds items to its internal collection.
public class Album
{
private List<Photo> _photos = new List<Photo>();
public IEnumerable<Photo> Photos { get { return _photos; } }
public void AddPhoto(Photo photo)
{
_photos.Add(photo);
}
}
*Edit This is a similar answer to dasblinkenlight, just with a more fleshed out code. I'll leave it here for now as it adds a little bit of clarification.
IEnumerable<T> does not allow sequence to be changed during enumeration. There is no other way but use another interface, such ICollection<T> or IList<T>.
So that the Photos will look like
public IList<Photo> Photos { get; set;}
// or
public ICollection<Photo> Photos { get; set;}
You can of course use actual classes and not interfaces, but usually interfaces give you more freedom.
Try:
myAlbum.Photos = myAlbum.Photos.Concat(newPhoto);
You need to add using System.Linq; on top of your file.

Categories