How I can access objects of DAC and BLC?
class BaseDACExtension : PXCacheExtension<BaseDAC>
{
public void SomeMethod()
{
BaseDAC dac = Base;
}
}
Assuming I understand your question correctly, just call GetExtension on either your base DAC or base Graph...
For DAC extensions: (where baseDac is an instance of BaseDac)
var dacExt = baseDac.GetExtension<BaseDACExtension>();
For Graph extensions: (where baseGraph is an instance of BaseGraph)
var graphExt = baseGraph.GetExtension<BaseGraphExtension>();
Related
I need to change the Display Name to "Primary Vendor" for a BAccount.acctName field, which is the last field to display in the PXSelector that I have created.
I have tried creating an field Extension which does the trick, but this option also renames the field for another inquiry page, therefore I cannot use it.
The following is my code:
Selector
[PXNonInstantiatedExtension]
public class SO_SOLine_ExistingColumn :
PXCacheExtension<PX.Objects.SO.SOLine>
{
#region InventoryID
[PXMergeAttributes(Method =
MergeMethod.Append)]
[PXSelector(typeof(Search2<InventoryItem.inventoryCD,
LeftJoin<BAccount, On<BAccount.bAccountID,
Equal<InventoryItem.preferredVendorID>>>,
Where<InventoryItem.descr, IsNotNull>>),
typeof(InventoryItem.inventoryID),
typeof(InventoryItem.inventoryCD),
typeof(InventoryItem.descr),
typeof(InventoryItem.postClassID),
typeof(InventoryItem.itemStatus),
typeof(InventoryItem.itemType),
typeof(InventoryItem.baseUnit),
typeof(InventoryItem.salesUnit),
typeof(InventoryItem.purchaseUnit),
typeof(InventoryItem.basePrice),
typeof(BAccount.acctName), ValidateValue = false) ]
public int? InventoryID { get; set; }
#endregion
}
Field Extension
public class BAccountExt : PXCacheExtension<PX.Objects.CR.BAccount>
{
#region UsrCustomField
[PXDBString(250, IsUnicode = true, BqlField =
typeof(BAccountR.acctName))]
[PXUIField(DisplayName = "Primary Vendor")]
public virtual string AcctName { get; set; }
public abstract class acctName : IBqlField
{
}
#endregion
}
As you found out the cache extension modifications applies to all screens who use that DAC. There is another extension mechanism applied on a per graph basis called CacheAttached that is applied after the cache extension.
To use it first you need to identify the graph of the screen you want to customize and the DAC field you want to modify. You can use the inspect element feature for this. In this example the graph for Customers screen is 'CustomerMaint' and the DAC field is 'Customer.acctName':
Once you have that information you can create an extension for that graph and extend the DAC field inside it. DAC field extensions defined in the graph using the CacheAttached method will only apply to screens who uses that graph:
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
[PXMergeAttributes(Method = MergeMethod.Merge)]
[PXUIField(DisplayName = "Display Name For Customers Graph")]
public virtual void Customer_AcctName_CacheAttached(PXCache sender)
{
}
}
The prototype convention for CacheAttached extensions is:
void DAC_DACField_CacheAttached(PXCache sender) { }
You change DAC and DACField to the field you are targeting. Method definition (body) should remain empty. The attributes decorating the CacheAttached method will apply to the field you're customizing. With attribute PXMerge you can tweak how the CacheAttached extension is applied, it allows to merge the field new attributes of the extension with the base one or completely replace the base attributes.
For more details look at this blog post:
http://asiablog.acumatica.com/2017/01/append-and-replace-of-dacs-attributes.html
you can also try like below but this is limited to the specific graph.
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
public override void Initialize()
{
PXUIFieldAttribute.SetDisplayName<Customer.acctName>(Base.BAccount.Cache, "Primary Vendor");
}
}
I have implemented Automapper in my MVC project but not sure if it is been done correctly. I am currently using Entity Framework Database First Approach and retrieving data using stored procedures. As you would be aware Entity Framework creates complex type object which is a wrapper around Stored Procedures.So I have created two classes for mapping purpose. One is used in the repository class to map the complex type to Entity class and second is the viewmodel that is used to map the entity class to view model in the controller. I havent explicitly mapped my entity class to viewmodel in the controller. So I am wondering how is the data bound to the grid as the grid is expecting viewmodel. I am looking forward for suggestions in terms of the approach that I have taken.
spGetUserProfileByUserProfileID_Result - Complex type object
UserProfile - Entity class.
UserProfileViewModel - ViewModel
AutoMapperConfiguration Class
public static void Configure()
{
Assembly[] assemblies = BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToArray();
Mapper.Initialize(cfg =>
cfg.AddProfiles(AllClasses.FromAssemblies(assemblies)
.Where(
a =>
a.FullName.EndsWith("Mapping"))));
}
Mapping class
public class DomainToModelMapping : Profile
{
public DomainToModelMapping()
{
CreateMap<spGetUserProfileByUserProfileID_Result, UserProfile>().ReverseMap();
CreateMap<UserProfileViewModel, UserProfile>().ReverseMap();
}
}
Repository
public List<UserProfile> GetUserProfileById(int id)
{
if (MCRHelper.UserValidate() == 1)
{
var userProfiles = db.spGetUserProfileByUserProfileID(id);
return Mapper.Map<List<UserProfile>>(userProfiles);
}
else
{
return null;
}
}
Controller
public ActionResult UserProfile_Read([DataSourceRequest]DataSourceRequest request)
{
var response = mcrRepository.GetUserProfileById(0).ToDataSourceResult(request);
return Json(response, JsonRequestBehavior.AllowGet);
}
If I add the following , to my controller to map to viewmodel, I get an error Missing type map configuration or unsupported mapping.
Mapping types:
DataSourceResult -> UserProfile
Kendo.Mvc.UI.DataSourceResult -> CC.GRP.MCRequest.Models.UserProfile
var userProfile = mcrRepository.GetUserProfileById(0).ToDataSourceResult(request);
return Json(Mapper.Map<UserProfile>(userProfile), JsonRequestBehavior.AllowGet);
If your question is how to return the viewmodel instead of the entity model from your controller using Automapper, then use Automapper Queryable Extensions:
using Automapper.QueryableExtensions;
...
public JsonResult UserProfile_Read([DataSourceRequest]DataSourceRequest request)
{
var users = mcrRepository.GetUserProfileById(0).Project().To<UserProfileViewModel>();
var response = users.ToDataSourceResult(request);
return Json(response, JsonRequestBehavior.AllowGet);
}
Let's say you have an order as an aggregate root. An order contains one or more line items.
It is my understanding that it's the repository's responsibility to instantiate an order object when asked.
The line items can be loaded at the time of the order object's creation (eager loaded), or the line item collection can be populated when it is accessed by the client code (lazy loaded).
If we are using eager loading, it's seems that the repository code would take responsibility with hydrating the line items when the order is created.
However if we are using lazy loading, how is the repository called when the LineItems collection is accessed without creating a dependency on the repository from the order domain class?
Main problem is in Repository's ability to get only aggregate roots (presenting aggregates), thus you cannot use Repository to get line items. This can lead to aggregate encapsulation violation.
I propose something like:
//Domain level:
public interface IOrderItemList {
IEnumerable<OrderItem> GetItems();
}
public class Order {
private IOrderItemList _orderItems;
public IEnumerable<OrderItem> OrderItems
{ get { return _orderItems.GetItems() } };
public Order(IOrderItemList orderItems)
{
_orderItems = orderItems;
}
}
public class OrderItemList : IOrderItemList
{
private IList<OrderItem> _orderItems;
public IEnumerable<OrderItem> GetItems() {
return _orderItems; //or another logic
}
//other implementation details
}
//Data level
public class OrderItemListProxy : IOrderItemList
{
//link to 'real' object
private OrderItemList _orderItemList;
private int _orderId;
//alternatively:
//private OrderEntity _orderEntity;
//ORM context
private DbContext _context;
public OrderItemListProxy(int orderId, DbContext context)
{
_orderId = orderId;
_context = context;
}
public IEnumerable<OrderItem> GetItems() {
if (_orderItemList == null)
{
var orderItemEntities = DbContext.Orders
.Single(order => order.Id == _orderId).OrderItems;
var orderItems = orderItemEntites.Select(...);
//alternatively: use factory to create OrderItem from OrderItemEntity
_orderItemList = new OrderItemList(orderItems);
}
return _orderItemList.GetItems();
}
}
public class OrderRepository
{
//ORM context
private DbContext _context;
Order GetOrder(int id)
{
var orderEntity = _context.Single(order => order.Id == id);
var order = new Order(new OrderItemListProxy(id, _context))
//alternatively:
//var order = new Order(new OrderItemListProxy(orderEntity, _context))
...
//init other fields
...
}
//other methods
...
}
Most important here is that IOrderItemList corresponds to domain layer, but OrderItemListProxy corresponds to data layer.
Finally,
You may use IList<OrderItem> instead of custom IOrderItemList or another appropriate interface.
Proxy implementation may differ.
I don't provide best practicies for using db context, it may depend on technologies you use.
I came across a lot of code in our company codebase with the following structure
class Base
{
public Base (var a, var b)
{
base_a = a;
base_b = b;
}
var base_a;
var base_b;
}
class Derived:Base
{
publc Derived (var a,b,c,d): base (a,d)
{
der_c = c;
der_d = d;
}
var der_c;
var der_d;
var der_e;
}
class Ref
{
Base _ref;
public Ref( var a,b,c,d)
{
_ref = new Derived (a,b,c,d)
}
public void method( )
{
_ref.der_e = 444; // won't compile
}
}
What is the correct way to initialize der_e ? What is the advantages of having a reference of base class and using an object derived class for _ref ? Just the fact that using a base class reference can hold multiple derived class objects ? If that's the case, should all the member variables of derived class be initialized during construction itself (like this: _ref = new Derived (a,b,c,d) ). What if I want to initialize _ref.der_e later in a method ? I know I can do this (var cast_ref = _ref as Derived; cast_ref.der_e = 444) but this look doesn't seem to the best practice. What is the idea of having such a structure and what is the correct of initializing a member of a derived class object after it has been constructed ?
Those are too many questions in a single post.
What is the correct way to initialize der_e ?
For initializing der_e you will have to have Reference of Derived class as it knows about the der_e property and not Base class.
What is the advantages of having a reference of base class and using
an object derived class for _ref ?
Yes that's called Polymorphism which is the essence of Object Oriented Programming. It allows us to hold various concrete implementations without knowing about the actual implementation.
If that's the case, should all the member variables of derived class
be initialized during construction itself (like this: _ref = new
Derived (a,b,c,d) )
There is no such rule. It depends on your scenario. If the values are not meant to be changed after the creation of the object and the values are known before hand during construction of the object then they should be initialized during construction.
Again if there are various scenarios like sometimes values are known and sometimes not then there can be Overloaded Constructors, which take different arguments.
What if I want to initialize _ref.der_e later in a method ?
That is perfectly fine, it depends on what you are trying to achieve. The question is not a concrete one but an abstract one in which it is difficult to comment on what you are trying to achieve.
I know I can do this (var cast_ref = _ref as Derived; cast_ref.der_e =
444) but this look doesn't seem to the best practice.
I am sharing some Java code which is similar to C# as I am from Java background
//This class knows about Base and nothing about the Derived class
class UserOfBase{
Base ref;
//Constructor of UserOfBase gets passed an instance of Base
public UserOfBase(Base bInstance){
this.ref = bInstance;
}
//Now this class should not cast it into Derived class as that would not be a polymorphic behavior. In that case you have got your design wrong.
public void someMethod(){
Derived derivedRef = (Derived)ref; //This should not happen here
}
}
I am sharing some references which would help you with this, as I think the answer can be very long to explain.
Factory Pattern
Dependency Injection
Head First Design Patterns
Posts on SO regarding polymorphism
You can create a constructor in your derived class and map the objects or create an extension method like this:
public static class Extensions
{
public static void FillPropertiesFromBaseClass<T1, T2>(this T2 drivedClass, T1 baseClass) where T2 : T1
{
//Get the list of properties available in base class
System.Reflection.PropertyInfo[] properties = typeof(T1).GetProperties();
properties.ToList().ForEach(property =>
{
//Check whether that property is present in derived class
System.Reflection.PropertyInfo isPresent = drivedClass.GetType().GetProperty(property.Name);
if (isPresent != null && property.CanWrite)
{
//If present get the value and map it
object value = baseClass.GetType().GetProperty(property.Name).GetValue(baseClass, null);
drivedClass.GetType().GetProperty(property.Name).SetValue(drivedClass, value, null);
}
});
}
}
for example when you have to class like this:
public class Fruit {
public float Sugar { get; set; }
public int Size { get; set; }
}
public class Apple : Fruit {
public int NumberOfWorms { get; set; }
}
you can initialize derived class by this code:
//constructor
public Apple(Fruit fruit)
{
this.FillPropertiesFromBaseClass(fruit);
}
I have a WinTree object which consists of three WinTreeItem objects. The problem I have is that I need to parameterize the first WinTreeItem(root) so I can select 1st, 2nd, or 3rd WinTreeItem.
Here is the code where I have the WinTree object which has the WitTreeItem name as a property.
public class UITree1Tree : WinTree
{
public UITree1Tree(UITestControl searchLimitContainer) :
base(searchLimitContainer)
{
#region Search Criteria
this.SearchProperties[WinTree.PropertyNames.Name] = "Tree Lists:";
this.WindowTitles.Add("Insert Symbol List");
#endregion
}
#region Properties
public UITrSymbolLiTreeItem UITradeStationSymbolLiTreeItem
{
get
{
if ((this.mUITrSymbolLiTreeItem == null))
{
this.mUITrSymbolLiTreeItem = new UITrSymbolLiTreeItem(this);
}
return this.mUITrSymbolLiTreeItem;
}
}
#endregion
#region Fields
private UITrSymbolLiTreeItem mUITrSymbolLiTreeItem;
#endregion
}
public class UITrSymbolLiTreeItem: WinTreeItem
{
public UITrSymbolLiTreeItem (UITestControl searchLimitContainer) :
base(searchLimitContainer)
{
#region Search Criteria
this.SearchProperties[WinTreeItem.PropertyNames.Name] = "Tr Symbol Lists";
this.SearchProperties["Value"] = "0";
this.WindowTitles.Add("Insert Tr List");
#endregion
}
}
You can use the Constructor of the class to pass the parameter.
OR
Add a Property to its parent and set this Property while initializing. The Parent testcontrol will be available inside child and hence your parameter also available. You can use this parameter inside the child wherever you want.
I did in this way through out my project and it works fine.