Entity Framework 4 - Navigation Property Object Null on Client Side - entity-framework

There are two tables of interest in my entity conceptual model: tblProducts and tblInstalledProducts.
Each installed product has a ProductID foreign key linking it to a specific product, which was set up automatically as a navigation property.
Within the entity domain service I have the following query:
public IQueryable<tblInstalledProduct> GetInstalledProductsBySiteID(string SiteID)
{
ObjectSet<tblInstalledProduct> installedProducts = this.ObjectContext.tblInstalledProducts;
var filterBySite =
from p in installedProducts.Include("tblProduct")
where p.SiteID == SiteID
select p;
return filterBySite;
}
I have a DataGridView bound to a DomainDataSource configured to use this query.
When I debug this query, p.tblProduct and p.tblProductReference are populated as expected. The problem arises when trying to access the tblProduct property of any tblInstalledProduct from the client side.
//Find associated install record for the selected product
tblInstalledProduct selectedInstall =
Context.tblInstalledProducts.Where(
p => p.SiteID == "Site1" && p.ProductID == 38
).First();
string productName = selectedInstall.tblProduct.ProductName;
For some reason tblProduct is always null. I've tried .Include() / .Load() and can't seem to get it to populate itself.
Why is tblInstalledProduct.tblProduct loaded up as expected on the service side of things, but is seemingly inaccessible on the client side?
Thanks for reading.
Edit:
XAML DataSource:
<telerik:RadDomainDataSource x:Key="InstalledProductsDataSource"
Name="InstalledProductsDataSource"
DomainContext="{StaticResource DomainContext}"
AutoLoad="True"
QueryName="GetInstalledProductsInfoBySiteID"
SubmittedChanges="InstalledProductsDataSource_SubmittedChanges">
<telerik:RadDomainDataSource.QueryParameters>
<telerik:QueryParameter
ParameterName="SiteID"
Value="{Binding SelectedValue,ElementName=SiteList}" />
</telerik:RadDomainDataSource.QueryParameters>
</telerik:RadDomainDataSource>
XAML DataGrid:
<telerik:RadGridView x:Name="InstalledProductsGridView"
ItemsSource="{Binding DataView, Source={StaticResource InstalledProductsDataSource}}">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="Product Name" DataMemberBinding="{Binding ProductName, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Version" DataMemberBinding="{Binding ProductVersion, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Description" DataMemberBinding="{Binding Description, Mode=TwoWay}" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
Right now the grid is bound to a collection of tblProducts, but I'd like to bind it to a collection of tblInstalledProducts (as there is some extra information in that table that I need access to) like so:
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn Header="DateInstalled" DataMemberBinding="{Binding DateInstalled, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Product Name" DataMemberBinding="{Binding tblProduct.ProductName, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Version" DataMemberBinding="{Binding tblProduct.ProductVersion, Mode=TwoWay}" />
<telerik:GridViewDataColumn Header="Description" DataMemberBinding="{Binding tblProduct.Description, Mode=TwoWay}" />
</telerik:RadGridView.Columns>

you need to do something like this
tblInstalledProduct selectedInstall = Context.GetInstalledProductsBySiteID("Site1").Where(p=> p.ProductID == 38 ).FirstOrDefault();
string productName="";
if(selectedInstall !=null)
{
productName= selectedInstall.tblProduct.ProductName;
}
for testing try to use;
public IQueryable<tblInstalledProduct> GetInstalledProductsNew()
{
//Im nut Sure of 'tblProduct' or 'tblProducts' it is dependent on your relations
return this.ObjectContext.tblInstalledProducts.Include("tblProduct");
}

For anyone else having problems with this, I did eventually find the solution. You need to use both .Include() on the query to tell it to load related objects, as well as the [Include] attribute in the metadata to allow those related objects to be serialized and sent to the client.

Related

Pass ID of current record to Apex Controller

I'm working on a Visualforce Email Template which will be sent from the parent Loan (LLC_BI__Loan__c) record in Salesforce, and I'm trying to include fields from the child Entity Involvement (LLC_BI__Legal_Entities__c) record(s).
I'm unable to pass the correct parent (Loan) Id to get the correct child records. Can anyone see where I may be going wrong ?
Thank you in advance
Component:(Name = BorrowerRecordsFromLoans)
<apex:component controller="BorrowersOnLoans" access="global">
<apex:attribute name="currentRecordId" description="" assignTo="{!loanId}" type="Id"/>
<apex:dataTable value="{!relatedBorrowers}" var="borrower">
<apex:column >
<apex:facet name="header">Borrower Name</apex:facet>
{!borrower.LLC_BI__Borrower_Type__c}
</apex:column>
</apex:dataTable>
</apex:component>
Controller: (Name = BorrowersOnLoans)
public class BorrowersOnLoans {
public Id loanId { get; set { loanId = value; loadChildren(); } }
public LLC_BI__Legal_Entities__c[] relatedBorrowers { get; set; }
void loadChildren()
{
List <LLC_BI__Legal_Entities__c> entList = new List<LLC_BI__Legal_Entities__c>();
for(LLC_BI__Loan__c loan:
[SELECT Id, (SELECT Entity_Name__c FROM LLC_BI__Legal_Entities__r ORDER BY Borrower_Number__c) FROM LLC_BI__Loan__c WHERE Id = :loanId])
{
for(LLC_BI__Legal_Entities__c ent:loan.LLC_BI__Legal_Entities__r) entList.add(ent);
}
}
}
Email Template:
<c:BorrowerRecordsFromLoans currentRecordId="{!relatedTo.Id}" />
We don't have your objects (whatever "LLC_BI" managed package is) but this should help.
If it's just a plain old (directly) related list - you don't need a component & query. The related list is directly available in the VF email template, you just need to know exactly the relationship's name. Here's example with Account and Opportunities:
<messaging:emailTemplate subject="https://stackoverflow.com/q/59502890/313628" recipientType="User" relatedToType="Account">
<messaging:htmlEmailBody >
{!relatedTo.AccountNumber}<br/>
{!relatedTo.Name}<br/>
{!relatedTo.BillingCity}<br/>
Opportunities, like that:
<ol>
<apex:repeat value="{!relatedTo.Opportunities}" var="o">
<li>{!o.Name}, {!o.StageName}, {!o.Amount}</li>
</apex:repeat>
</ol>
<hr/>
or like that:
<apex:dataTable value="{!relatedTo.Opportunities}" var="o">
<apex:column value="{!o.Name}" />
<apex:column value="{!o.StageName}" />
<apex:column value="{!o.Amount}" />
</apex:dataTable>
</messaging:htmlEmailBody>
</messaging:emailTemplate>
This should get you started. Your relationship name will probably be LLC_BI__Legal_Entities__r. You can go pretty far with it in pure Visualforce, limit the list, apply custom styling, even filter some rows by not displaying them (not best performance wise but it's an email template, how often you'll use it. Read about <apex:variable> and rendered attribute if you're curious).
But if you really need a query (need WHERE clause, ORDER BY etc) - you need controller, component and the final template.
public with sharing class Stack59502890 {
public Id accountId {get; set;}
public List<Opportunity> getWonOpportunities(){
return [SELECT Name, StageName, Amount
FROM Opportunity
WHERE AccountId = :accountId AND IsWon = true
ORDER BY Name];
}
}
<apex:component access="global" controller="Stack59502890">
<apex:attribute name="currentRecordId" description="" assignTo="{!accountId}" type="Id"/>
<apex:repeat value="{!wonOpportunities}" var="o">
<li>{!o.Name}, {!o.StageName}, {!o.Amount}</li>
</apex:repeat>
</apex:component>
<messaging:emailTemplate subject="Stack59502890" recipientType="User" relatedToType="Account">
<messaging:htmlEmailBody >
<c:Stack59502890 currentRecordId="{!relatedTo.Id}" />
</messaging:htmlEmailBody>
</messaging:emailTemplate>
For my data this now returns only 2 opps.

ZK MVVM binder save with EL-Expression

How to do this with zk MVVM
i want to save a bean
but with condition
if the type is personal than save into personal, else into company
<textbox value="#save(vm.personal ? vm.masterCifPersonal.cifId : vm.masterCifCompany.cifId)" width="100px" maxlength="10"/>
but when binder save into bean, this exception appear
Illegal Syntax for Set Operation
My tip is to modify your code and use a temporary var:
<textbox value="#save(vm.temp)" width="100px" maxlength="10"/>
and modify your setter as
void setTemp(Long temp) {
if(personal) {
masterCifPersonal.cifId = temp;
} else {
masterCifCompany.cifId = temp;
}
}
another solution could be :
ZK 8 and higher :
<if test="#load(vm.personal)">
<textbox value="#save(vm.masterCifPersonal.cifId)"/>
</if>
<if test="#load(not vm.personal)">
<textbox value="#save(vm.masterCifCompany.cifId)"/>
</if>
ZK 6.5 an higher:
<textbox value="#save(vm.masterCifPersonal.cifId)" visible="="#load(vm.personal)"/>
<textbox value="#save(vm.masterCifCompany.cifId)" visible="="#load(not vm.personal)"/>
Difference:
The if tag will not render the other tag into the dom while using the visible attribute will render it in the dom.
If personal isn't dynamic you could use the if attribute of the Textbox but the usage is then : if="${vm.personal} because binding will not work
Like this the textbox isn't also rendered into the DOM.

MyBatis - Returning a HashMap

I want the returned result of the select statement below to be Map<String, Profile>:
<select id="getLatestProfiles" parameterType="string" resultMap="descProfileMap">
select ml.layerdescription, p1.*
from ( select max(profile_id) as profile_id
from SyncProfiles
group by map_layer_id) p2
inner join SyncProfiles p1 on p1.profile_id = p2.profile_id
inner join maplayers ml on ml.LAYERID = p1.MAP_LAYER_ID
where ml.maxsite = #{site}
</select>
I have seen this post which maps a String to a custom class, but the key was part of the custom class. In my query above, the layerdescription field is not part of the Profile class since I'm aiming to have the Profile class strictly represent the syncprofiles table and the layerdescription field is in another table.
My interface looks like:
public Map<String, Profile> getLatestProfiles(final String site);
How should descProfileMap be defined? I want to do something like:
<resultMap id="descProfileMap" type="java.util.HashMap">
<id property="key" column="layerdescription" />
<result property="value" javaType="Profile"/>
</resultMap>
But this is clearly wrong. Thanks for your help!
Achieving this requires 2 steps:
-Use association and nested resultMap:
<resultMap type="Profile" id="profileResultMap">
<!-- columns to properties mapping -->
</resultMap
<resultMap type="map" id="descProfileMap">
<id property="key" column="layerdescription" />
<association property="value" resultMap="profileResultMap" />
</resultMap>
-Add every record to a Map with expected structure using ResultHandler:
final Map<String, Profile> finalMap = new HashMap<String, Profile>();
ResultHandler handler = new ResultHandler() {
#Override
public void handleResult(ResultContext resultContext) {
Map<String, Object> map = (Map) resultContext.getResultObject();
finalMap.put(map.get("key").toString()), (Profile)map.get("value"));
}
};
session.select("getLatestProfiles", handler);
If you run that as is, expect this exception will likely be raised:
org.apache.ibatis.executor.ExecutorException: Mapped Statements with
nested result mappings cannot be safely used with a custom
ResultHandler. Use safeResultHandlerEnabled=false setting to bypass
this check or ensure your statement returns ordered data and set
resultOrdered=true on it.
Then following the suggestion, you can either disable the check globally in Mybatis config:
According to the documentation:
safeResultHandlerEnabled: Allows using ResultHandler on nested statements. If allow, set the
false. Default: true.
<settings>
<setting name="safeResultHandlerEnabled" value="false"/>
</settings>
or specify your result is ordered in the statement:
The documentation states:
resultOrdered This is only applicable for nested result select
statements: If this is true, it is assumed that nested results are
contained or grouped together such that when a new main result row is
returned, no references to a previous result row will occur anymore.
This allows nested results to be filled much more memory friendly.
Default: false.
<select id="getLatestProfiles" parameterType="string" resultMap="descProfileMap" resultOrdered="true">
But I have not found anyway to specify this statement option when using annotations.

How to bind Selected item of Combobox to two different Property?

I am developing project using MVVM pattern.In the project I have two viewmodel namely
CountryViewModel and 2. EmpViewModel
In countryviewmodel I have stored information about country,state,city etc.
In EmpViewModel I have a control which have combo box which displays country name and selected value is set to country id which are in CountryViewModel.
Here is code:
<ComboBox Grid.Row="0" Grid.Column="1" Margin="3"
ItemsSource="{Binding CountryViewModel.Countries}" SelectedValue="{Binding Title}"
SelectedItem="{Binding CountryViewModel.SelectedCountry,Mode=TwoWay}"
SelectedValuePath="Country_Id" DisplayMemberPath="Title">
</ComboBox>
This is working fine.
I have local property country id in EmpViewModel and want to bind it to SelectedValue property of Combobox which I can get if I remove CountryViewModel from CountryViewModel.SelectedCountry.
But problem is I have another combobox for state which is dependent on Country combo box.
Edit: i.e in Country ViewModel I have called method GetAllState() when SelectedCountry changes.
So can I bind SelectedValue property of Combobox to both CountryViewModel.SelectedCountry from CountryViewModel and Country_Id from EmpViewModel?
I found a workaround
I have write following method in an interface:
public interface IViewModel
{
T GetValue<T>(string propertyName);
}
In country view model I implement this method as:
public override T GetValue<T>(string propertyName)
{
T result = default(T);
result = (T)Convert.ChangeType(this.SelectedCountry, typeof(T), null); }
And in Emp View Model I added following line:
newEmp.Country_Id = this.CountryViewModel.GetValue<Country>("SelectedCountry").Country_Id;

how to use zk annotations

I am using zk 5.0.3. I want to use the following annotation binding as the title of a "center" region of a borderlayout:
<a:bind content="entrydisplay.activeEntryCaption" /> <html />
I want to do the following:
<borderlayout>
<north title="use the above binding here">
this is north
</north>
</borderlayout>
How do I achieve the functionality such that I can wrap this binding as the value of the title?
Thanks,
Sony
You are using an outdated version of ZK data binding. It is highly recommended that you make use of the latest methodology.
The following link is the databinding section of the ZK Essential guide & Developer's Reference:
Developer's Reference Databinding
ZK Essential's Databinding
Our basic databinding consists of a POJO which follows the Java bean conventions being access from an XML based interface using annotations in attributes. For example:
Person POJO:
public class Person {
private String _firstName = "";
private String _lastName = "";
private Boolean _married = true;
public Person(){
}
public Person(String firstName, String lastName, Boolean married){
_firstName = firstName;
_lastName = lastName;
_married = married;
}
// getter and setters
public void setFullName(String f) {
// do nothing
}
public String getFullName() {
return _firstName + " " + _lastName;
}
//add more here
}
The UI file:
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<window>
<zscript><![CDATA[
//prepare the person object
import bean.Person;
Person person = new Person();
person.setFirstName("Max");
person.setLastName("Planck");
]]>
</zscript>
<grid width="400px">
<rows>
<row> First Name: <textbox value="#{person.firstName}"/></row>
<row> Last Name: <textbox value="#{person.lastName}"/></row>
<row> Full Name: <label value="#{person.fullName}"/></row>
</rows>
</grid>
</window>
The theory is described here.
i think the old way is done it like this
<borderlayout>
<north>
<attribute name="label">
<a:bind value="entrydisplay.activeEntryCaption" />
</attribute>
</north>
</borderlayout>
The new doc
The doc of [http://docs.zkoss.org/wiki/Data_binding][Data Binding]
For your specific question, annotate your component like following:
<borderlayout>
<north id="mynorth" title="#{entrydisplay.activeEntryCaption}">
this is north
</north>
</borderlayout>
Data binder will read such annotation and call the getter and setter methods to set the title of the north component for you. It will do something like:
mynorth.setTitle(entrydisplay.getActiveEntryCaption());