I need to show a table with a list of inherited objects.
For example:
public abstract class Animal
{
public string Name { get; set; }
public abstract string Detail { get; }
}
public class Dog : Animal
{
public override Detail { get { return "A dog"; } }
}
public class Cat : Animal
{
public override Detail { get { return "A cat"; } }
}
It seems that the datasource takes de first object class type and the other objects shows with #ERROR
How I can fix it?
You need to map your properties using the expressions area. If you want to show a column with the cats details, add this to the expression for that field.
=Fields!Cat.Value.Detail
Related
The requirement is to build a custom form tab screen that starts of with an account selector. After choosing the account, the bottom grid is populated with a list of custom DAC's that basically consists of a key of CompanyID, AccountID, SubID that is stored in a custom table. The existing Account DAC does not have a selector component, which I can use for the top selection. The solution I tried to get past this is to create a new DAC but with only one unbound property, but this is giving me issues on the BQL side when setting up the Master/Detail data views for the screen. I will then attempt to setup a master detail relationship between my custom DAC and the Account DAC. Is this the best approach to build this screen, or is there another which I haven't thought of?
Screen Graph (ignore the where and filters, just doing a proof of concept first):
using System;
using PX.Data;
using PX.Data.BQL.Fluent;
using PX.Objects.GL;
namespace IP_GLRestrictions2
{
public class IPGLAcctToSubLinkMaint : PXGraph<IPGLAcctToSubLinkMaint>
{
public PXSave<IPAccount> Save;
public PXCancel<IPAccount> Cancel;
public PXFilter<IPAccount> MasterView;
public PXFilter<IPAcctSubLink> DetailsView;
public SelectFrom<IPAccount>.View AccountView;
public SelectFrom<IPAcctSubLink>
//.Where<IPAcctSubLink.accountID.IsEqual<IPAccount.accountID.FromCurrent>>
.View SubLinkView;
}
}
Custom DAC ( I want to show the Description and Active as unbound fields as soon as a subaccount ID is chosen in the details grid):
[Serializable]
[PXCacheName("Account To Subaccount Link")]
public class IPAcctSubLink : IBqlTable
{
#region AccountID
[PXDBInt(IsKey = true)]
[PXUIField(DisplayName = "Account ID")]
[PXDBDefault(typeof(IPAccount.accountID))]
[PXParent(typeof(SelectFrom<IPAccount>.Where<IPAccount.accountID.IsEqual<IPAcctSubLink.accountID.FromCurrent>>))]
////[PXSelector(typeof(Search<IPAccount.accountID>),
//// typeof(Account.accountCD),
//// typeof(Account.description),
//// SubstituteKey = typeof(Account.accountCD))]
public virtual int? AccountID { get; set; }
public abstract class accountID : PX.Data.BQL.BqlInt.Field<accountID> { }
#endregion
#region Subid
[PXDBInt(IsKey = true)]
[PXUIField(DisplayName = "Subaccount ID")]
[PXSelector(typeof(Search<Sub.subID>),
typeof(Sub.subCD),
typeof(Sub.description),
typeof(Sub.active),
SubstituteKey = typeof(Sub.subCD))]
public virtual int? Subid { get; set; }
public abstract class subid : PX.Data.BQL.BqlInt.Field<subid> { }
#endregion
#region Description
[PXString]
[PXUIField(DisplayName = "Description")]
//[PXDefault(typeof(Search<Sub.description, Where<Sub.subID, Equal<Current<IPAcctSubLink.subid>>>>))]
public virtual int? SubDescription { get; set; }
public abstract class subdescription : PX.Data.BQL.BqlInt.Field<subdescription> { }
#endregion
#region Active
[PXBool]
[PXUIField(DisplayName = "Active")]
//[PXDefault(typeof(Search<Sub.active, Where<Sub.subID, Equal<Current<IPAcctSubLink.subid>>>>))]
public virtual int? SubActive { get; set; }
public abstract class subActive : PX.Data.BQL.BqlInt.Field<subActive> { }
#endregion
If you just need a selector for a specific field in a DAC the easiest way to do that would be via a cache extension.
You can simply add the PXSelector attribute inside the cache extension.
public sealed class CacheExtension : PXCacheExtension<YourDAC>{
public static bool IsActive() => true;
[YourSelectorAttribute]
public int? AccountID { get; set; }
}
I have this tree structure:
Page1
PageA
PageX
PageY
PageB
Page2
I want Page1 and Page2 as well as all child pages. I have created two classes. In one class using sitecore query
[SitecoreQuery("../*[##templateid={GUID}]", IsRelative = true)]
public virtual IEnumerable<ItemModel> Links { get; set; }
In other ItemModel class getting child pages
public class ItemModel
{
[SitecoreId]
public Guid Id { get; set; }
[SitecoreChildren]
public IEnumerable<SideMenuModel> Children { get; set; }
}
This is working fine but now I want to get only those child pages who have some specific template. Please provide me some solution.
It looks like you have most of the code correct but you need to also apply restrictions to the Children property on the ItemModel class.
You can use a SitecoreQuery on the like you have on the parent model:
public class ItemModel
{
[SitecoreId]
public Guid Id { get; set; }
[SitecoreQuery("./*[##templateid={SideMenuModel-GUID}]", IsRelative = true)]
public virtual IEnumerable<SideMenuModel> ChildItems { get; set; }
}
Or you can use the EnforceTemplate attribute on your SideMenuModel class:
[SitecoreType(TemplateId = "GUID", EnforceTemplate = SitecoreEnforceTemplate.Template)]
public class SideMenuModel
{
[SitecoreId]
public Guid Id { get; set; }
}
public class ItemModel
{
[SitecoreId]
public Guid Id { get; set; }
[SitecoreChildren]
public virtual IEnumerable<SideMenuModel> ChildItems { get; set; }
}
Since you have set EnforceTemplate then using the [SitecoreChildren] attribute means that only items matching the template id will be returned, otherwise they will be skipped.
If you need children of children mapped then you should add [SitecoreChildren] property on your SideMenuModel class as well (or refactor your code so the class references itself) or you could use a "get all descendants query (.//*[##templateid={SideMenuModel-GUID}]) although I would recommend that you ur he Content Search API at this point instead.
You can read more in the blog post about Getting child items with Glass.
We are facing issue in Glass mapper 4.0 where it does not load item children.
Here is our controller class , It is inheriting from GlassController:
public class CarouselController : GlassController
{
public ActionResult GetCarousel()
{
Model = this.GetDataSourceItem<CarouselViewModel>();
return View(Model);
}
}
And here is our View Model:
public class CarouselViewModel:Carousel_Folder
{
[SitecoreChildren]
public virtual IEnumerable<Carousel> Carousels { get; set; }
}
we get only the parent node information not the childeren (carousels) in the result
Here is the result we get:
[Result Image][1]
Also, following classes were generated with TDS:
[SitecoreType(TemplateId = ICarousel_FolderConstants.TemplateIdString )] //, Cachable = true
public partial interface ICarousel_Folder : IGlassBase
{}
Carousel template is inheriting from two templates content base and image base.
I had this issue before, for me i added [SitecoreChildren(IsLazy = false)] to my model and it works fine, in your case it should be like this :
public class CarouselViewModel:Carousel_Folder
{
[SitecoreChildren(IsLazy = false)]
public virtual IEnumerable<Carousel> Carousels { get; set; }
}
It seems that Carousels property is not par of the Carousel_Folder template, that's why your Interface/Class doesn't have something like:
[SitecoreType(TemplateId=ICarousel_FolderConstants.TemplateIdString)]
public partial class Carousel_Folder : GlassBase, ICarousel_Folder
{
[SitecoreField(ICarouselConstants.CarouselsFieldName)]
public virtual IEnumerable<Carousel> Carousels {get; set;}
}
In this case you will need to get the Parent item and get the children manually, i.e.:
var children = parentItem.Children.Select(x => x.GlassCast<Carousel>())
I have a QuestionsData class that has a List of QuestionData.
The QuestionData is an abstract class and has two implementations: TextQuestionData and SelectionQuestionData.
The problem is that after doing clientResponse.getEntity, I get the object with a list of SelectionQuestionData only, while I know that some of the questions are of type TextQuestionData.
I tried to add #XmlSeeAlso, but it did not help.
I also tried to change the order of elements in the #XmlElementRefs but that caused all the questions to be of type TextQuestionData.
I don't know if this is relevant or not, but the object I use in jersey is another Jaxb Object that has QuestionsData as a member
Here is the code:
#XmlRootElement(name = "questions")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso({SelectionQuestionData.class, TextQuestionData.class })
public class QuestionsData {
#XmlElementRefs({#XmlElementRef(type = TextQuestionData.class), #XmlElementRef(type = SelectionQuestionData.class)})
private List<QuestionData> questions;
private QuestionsData() {}
public QuestionsData(List<QuestionData> questions) {
this.questions = questions;
}
}
#XmlRootElement(name = "question")
#XmlAccessorType(XmlAccessType.FIELD)
public class TextQuestionData extends QuestionData {
#XmlElement
private String someString;
public TextQuestionData() {}
}
#XmlRootElement(name = "question")
#XmlAccessorType(XmlAccessType.FIELD)
public class SelectionQuestionData extends QuestionData {
#XmlElements({#XmlElement(name = "option")})
private List<String> options;
public SelectionQuestionData() {}
}
In this use case the element name is used to determine which subclass (mapped with #XmlRootElement) should be instantiated during unmarshalling. Since you mapped both subclasses to question the JAXB (JSR-222) implementation can not determine the correct one to unmarshal. You will need to map them to different root elements.
TextQuestionData
#XmlRootElement(name = "textQuestion")
#XmlAccessorType(XmlAccessType.FIELD)
public class TextQuestionData extends QuestionData {
#XmlElement
private String someString;
public TextQuestionData() {}
}
SelectionQuestionData
#XmlRootElement(name = "selectionQuestion")
#XmlAccessorType(XmlAccessType.FIELD)
public class SelectionQuestionData extends QuestionData {
#XmlElements({#XmlElement(name = "option")})
private List<String> options;
public SelectionQuestionData() {}
}
For More Information
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
I designing an applications which basically has 3 different logic layers:
DB connector (implemented by ADO.NET).
BL the business logic (the only thing the UI knows).
DB repositories (connects between the first two).
The DB repositories are separated into sections of dependency and every final entity is polymorphic to one interface. In some cases there are dependencies between objects inside the same dependency sections - ISectionFactory (hence dependent).
In practice the BL is going to ask for an object of specific type (such as IngrediantType in my example) from the MainFactory (which is a factor for all the DB)
Because of this design I am forced to cast types on the UI - which obviously is a drag.
How can I change the design ?
Here is a brief look of design:
public class MainFactory
{
private Dictionary<Type, ISectionFactory> m_SectionsFactories;
private ISectionFactory treatmentsSectionFactory =
new TreatmentsSectionFactory();
public MainFactory()
{
m_SectionsFactories = new Dictionary<Type, ISectionFactory>
{
{typeof(IngrediantType),treatmentsSectionFactory}
};
}
public IConcreteDataCollection GetConcreteData(Type i_EntitiesName)
{
return m_SectionsFactories[i_EntitiesName]
.GetConcreteData(i_EntitiesName);
}
}
internal interface ISectionFactory
{
IConcreteDataCollection GetConcreteData(Type i_EntitiesName);
}
public class TreatmentsSectionFactory : ISectionFactory
{
private Dictionary<Type, IConcreteDataCollection>
m_ConcreteDataCollections;
private IngrediantTypes m_IngrediantTypes = new IngrediantTypes();
private Ingrediants m_Ingrediants = new Ingrediants();
public TreatmentsSectionFactory()
{
m_ConcreteDataCollections =
new Dictionary<Type, IConcreteDataCollection>();
m_ConcreteDataCollections
.Add(typeof(IngrediantType), m_IngrediantTypes);
m_ConcreteDataCollections
.Add(typeof(Ingrediants), m_Ingrediants);
}
public IConcreteDataCollection GetConcreteData(Type i_EntitiesName)
{
return m_ConcreteDataCollections[i_EntitiesName];
}
}
public interface IConcreteDataCollection : IEnumerable
{
// Iteratable.
IConcreteData GetById(int i_Id);
void AddNewConcreteData(IConcreteData i_ConcreteData);
void UppdateConcreteData(IConcreteData i_ConcreteData);
void DeleteConcreteData(IConcreteData i_ConcreteToDelete);
}
public class IngrediantTypes : IConcreteDataCollection
{
public string TestType { get; set; }
public IConcreteData GetById(int i_Id){}
public void AddNewConcreteData(IConcreteData i_ConcreteData){}
public void UppdateConcreteData(IConcreteData i_ConcreteData){}
public void DeleteConcreteData(IConcreteData i_ConcreteToDelete){}
public IEnumerator GetEnumerator(){}
}
// also implements IConcreteDataCollection
public class Ingrediants : IConcreteDataCollection
{
}
public interface IConcreteData
{
public int Index { set; get; }
} // the final (highest) entity of all DB entities
public class IngrediantType : IConcreteData
{
public int Index { set; get; }
// other set of properties
}
public class Ingrediant : IConcreteData
{
public int Index { set; get; }
public IngrediantType RelatedIngrediantType { set; get; }
// other set of properties
}
public class mainClass
{
public static void main()
{
MainFactory factory = new MainFactory();
var type = typeof(IngrediantType);
// returns a IngrdiantTypes of type (IConcreteDataCollection)
var t = factory.GetConcreteData(typeof(IngrediantType));
// I want to use the IngrediantType without casting !!!
var s = t.GetById(2);
}
}
It's a little hard to tell what's going on here, but I think the key will be to take advantage of generics like so:
public IConcreteDataCollection<T> GetConcreteData<T>()
{
return ...;
}
If I understand your question correctly, this will allow you to say:
var t = factory.GetConcreteData<IngrediantType>();
You will need to change almost every class in your code to use generics.