Get a Partial Class to show using EntityDataSource - .net-4.0

I have an entity object student, which has properties StudentID and StudentName. I have a partial class Student which uses a service to find that student's current school. An EntityDataSource fills up the grid just fine, accept for the school. If I watch the RowDataBound event of the grid, I can watch it go to StudentModel.Designer.cs and get the StudentID and StudentName. But it does not get the school. This makes sense, because school is not part of the entity object - but, can I even get the school custom property while using an EntityDataSource?
I've been doing some research, and it seems I need to use the ContextCreating event in order to complete my object?
Before, I was adding the school during the RowDataBound event, but I want to be able to sort on school - so that is the reason I am trying to figure this out.
I'm not sure if I'm close to the solution... or this can't be done at all and I should do all my data binding in code behind?
Here is code:
<asp:EntityDataSource runat="server" ID="StudentGroupEntityDataSource"
ContextTypeName="GearUp.Data.StudentGroupEntities" OnContextCreating="StudentGroupEntityDataSource_ContextCreating" OnContextCreated="StudentGroupEntityDataSource_ContextCreated"
EnableFlattening="False" EnableDelete="True" EnableInsert="True" EnableUpdate="True"
EntitySetName="StudentGroupMembers"
OrderBy="it.FullName"
Where="it.GroupID IN {#ID}">
<WhereParameters>
<asp:ControlParameter DbType="Guid" Name="ID" ControlID="StudentGroupDropDown"
PropertyName="SelectedValue" />
</WhereParameters>
</asp:EntityDataSource>
public partial class StudentGroupMember
{
private string _school;
public string School
{
get
{
if (_school == null)
{
StudentServiceClient clientStudent = new StudentServiceClient();
var studentDetail = clientStudent.RetrieveStudentDetail(this.StudentID.ToString());
_school = studentDetail.SchoolName;
}
return _school;
}
}
}

Related

How to bind entry from page with ViewModel

I'm trying to implement Login system like this:
public Command LoginCommand => new Command(async () =>
{
LoginModel model = new LoginModel("dnetTest", "dnetTest"); // (get value from entry instead of "dnetTest")
if (model.CheckInformation())
{
bool isSuccess = await LoginService.Login(model);
if (isSuccess)
{
await Application.Current.MainPage.DisplayAlert("Пријављивање", "Успешно сте се пријавили", "OK.");
Application.Current.MainPage = new MainPage();
}
}
My LogingPage also have:
<Label Text="Korisničko ime"/>
<Entry x:Name="Entry_Username" Placeholder="Korisničko ime"/>
<Label Text="Lozinka"/>
<Entry x:Name="Entry_Password" Placeholder="Lozinka"/>
<Button Text="Prijavi se" Command="{Binding LoginCommand}"/>
So, my question is how to bind Entry_Username and Entry_Password with LoginModel in LoginViewModel?
And is there any way to bind it without using x:Names?
To be fair; this is a very basic MVVM question that is easy to find, of which the solution is in multiple blogs and pages. But, let me help you get started.
And is there any way to bind it without using x:Names?
The whole point of data binding is that you do not have to make any hard references to these controls. We want to separate the logic from the UI so that we can easily replace one or both without having to touch the other. For instance, say that you want to implement a new design, if you use data binding, you can just show the current properties in the view model (or page model as it is referred to in the Xamarin space as well) if you reference those in your new UI.
If you would have all kind of x:Name references, you would not only have to touch your UI, but also the view model and go through all the references to those fields and replace them as well.
Using data binding promotes reusability and testability mostly.
As for your specific case. I can't see your full code, so there will be some assumptions made here. First, I'm going to assume that your LoginCommand lives in a view model of its own right now. You are already using data binding there, which is good. I don't directly see why you would need a separate model for the view model and the login, possibly your LoginModel is more like a service. Also, I'm assuming you're doing this manually, without the help of an MVVM framework. It's good to know what happens under the hood, but I would recommend looking at using an MVVM framework like FreshMvvm or Prism for example.
The login page that holds your XAML, I will call LoginPage.xaml which should have a LoginPage.xaml.cs code-behind file. In there, go into the constructor and specify this line:
public LoginPage()
{
InitializeComponents();
// This line is relevant here
BindingContext = new LoginViewModel();
}
Seeing that your LoginCommand is already using data binding, this is probably here already.
Now, in your LoginPage.xaml, change your XAML to this:
<Label Text="Korisničko ime"/>
<Entry Text="{Binding Username}" Placeholder="Korisničko ime"/>
<Label Text="Lozinka"/>
<Entry Text="{Binding Password}" Placeholder="Lozinka"/>
<Button Text="Prijavi se" Command="{Binding LoginCommand}"/>
Notice how I removed the x:Name attributes and added the Text attributes on the two Entry controls.
Next, go into your LoginViewModel.cs and add two properties, like this:
public string Username { get; set; }
public string Password { get; set; }
Whenever the text changes in your Entry controls, these properties should contain the value accordingly. Now, you can change the code you posted to something like this:
public Command LoginCommand => new Command(async () =>
{
// Notice how I changed this line
LoginModel model = new LoginModel(Username, Password);
if (model.CheckInformation())
{
bool isSuccess = await LoginService.Login(model);
if (isSuccess)
{
await Application.Current.MainPage.DisplayAlert("Пријављивање", "Успешно сте се пријавили", "OK.");
Application.Current.MainPage = new MainPage();
}
}
This should work for you!
As mentioned, I would recommend looking further into MVVM as a whole and also MVVM frameworks. Here is the official Docs page, a good writeup by Adam Pedley and something I wrote myself a while back.

OptaPlanner - The entity was never added to this ScoreDirector error

I am implementing an algorithm similar to the NurseRoster one in OptaPlanner. I need to implement a rule in drools that check if the Employee cannot work more days than the number of days in his contract. Since i couldn't figure out how to make this in drools, i decided to write it as a method in a class, and then use it in drools to check if the constraint has been broken. Since i needed a List of ShiftAssignments in the Employee class, i needed to use an #InverseRelationShadowVariable that updated that list automatically an Employee got assigned to a Shift. Since my Employee now has to be a PlanningEntity, the error The entity was never added to this ScoreDirector appeared. I believe the error is caused by my ShiftAssignment entity, which has a #ValueRangeProvider of employees that can work in that Shift. I think this is due to the fact that ScoreDirector.beforeEntityAdded and ScoreDirector.afterEntityAdded were never called, hence the error. For some reason when i removed that range provider from ShiftAssignment and put it on NurseRoster which is the #PlanningSolution, it worked.
Here is the code:
Employee:
#InverseRelationShadowVariable(sourceVariableName = "employee")
public List<ShiftAssignment> getEmployeeAssignedToShiftAssignments() {
return employeeAssignedToShiftAssignments;
}
ShiftAssignment:
#PlanningVariable(valueRangeProviderRefs = {
"employeeRange" }, strengthComparatorClass = EmployeeStrengthComparator.class,nullable = true)
public Employee getEmployee() {
return employee;
}
// the value range for this planning entity
#ValueRangeProvider(id = "employeeRange")
public List<Employee> getPossibleEmployees() {
return getShift().getEmployeesThatCanWorkThisShift();
}
NurseRoster:
#ValueRangeProvider(id = "employeeRange")
#PlanningEntityCollectionProperty
public List<Employee> getEmployeeList() {
return employeeList;
}
And this is the method i use to update that listOfEmployeesThatCanWorkThisShift:
public static void checkIfAnEmployeeCanBelongInGivenShiftAssignmentValueRange(NurseRoster nurseRoster) {
List<Shift> shiftList = nurseRoster.getShiftList();
List<Employee> employeeList = nurseRoster.getEmployeeList();
for (Shift shift : shiftList) {
List<Employee> employeesThatCanWorkThisShift = new ArrayList<>();
String shiftDate = shift.getShiftDate().getDateString();
ShiftTypeDefinition shiftTypeDefinitionForShift = shift.getShiftType().getShiftTypeDefinition();
for (Employee employee : employeeList) {
AgentDailySettings agentDailySetting = SearchThroughSolution.findAgentDailySetting(employee, shiftDate);
List<ShiftTypeDefinition> shiftTypeDefinitions = agentDailySetting.getShiftTypeDefinitions();
if (shiftTypeDefinitions.contains(shiftTypeDefinitionForShift)) {
employeesThatCanWorkThisShift.add(employee);
}
}
shift.setEmployeesThatCanWorkThisShift(employeesThatCanWorkThisShift);
}
}
And the rule that i use:
rule "maxDaysInPeriod"
when
$shiftAssignment : ShiftAssignment(employee != null)
then
int differentDaysInPeriod = MethodsUsedInScoreCalculation.employeeMaxDaysPerPeriod($shiftAssignment.getEmployee());
int maxDaysInPeriod = $shiftAssignment.getEmployee().getAgentPeriodSettings().getMaxDaysInPeriod();
if(differentDaysInPeriod > maxDaysInPeriod)
{
scoreHolder.addHardConstraintMatch(kcontext, differentDaysInPeriod - maxDaysInPeriod);
}
end
How can i fix this error?
This has definitely something to do with the solution cloning that is happening when a "new best solution" is created.
I encountered the same error when i implemented custom solution cloning. In my project i have multiple planning entity classes and all of them have references to each other (either a single value or a List). So when solution cloning is happening the references need to be updated so they can point to the cloned values. This is something that the default cloning process is doing without a problem, and thus leaving the solution in a consistent state. It even updates the Lists of planning entity instances in the parent planning entities correctly (covered by the method "cloneCollectionsElementIfNeeded" from the class "FieldAccessingSolutionCloner" from the OptaPlanner core).
Just a demonstration what i have when it comes to the planning entity classes:
#PlanningEntity
public class ParentPlanningEntityClass{
List<ChildPlanningEntityClass> childPlanningEntityClassList;
}
#PlanningEntity
public class ChildPlanningEntityClass{
ParentPlanningEntityClass parentPlanningEntityClass;
}
At first i did not update any of the references and got the error even for "ChildPlanningEntityClass". Then i have written the code that updates the references. When it comes to the planning entity instances that were coming from the class "ChildPlanningEntityClass" everything was okay at this point because they were pointing to the cloned object. What i did wrong in the "ParentPlanningEntityClass" case was that i did not create the "childPlanningEntityClassList" list from scratch with "new ArrayList();", but instead i just updated the elements of the list (using the "set" method) to point at the cloned instances of the "ChildPlanningEntityClass" class. When creating a "new ArrayList();", filling the elements to point to the cloned objects and setting the "childPlanningEntityClassList" list everything was consistent (tested with FULL_ASSERT).
So just connecting it to my issue maybe the list "employeeAssignedToShiftAssignments" is not created from scratch with "new ArrayList();" and elements instead just get added or removed from the list. So what could happen (if the list is not created from scratch) here is that both the working and the new best solution (the clone) will point to the same list and when the working solution would continue to change this list it would corrupt the best solution.

Create new records when searching for reference object

In my current project I would like to be able to create new objects when searching for a reference object. This happens in several places of the application.
For example, let's assume we have a City Entity and a Country Entity. The City entity has a mandatory reference to the Country entity.
In my use case, I would like to create a new City. When I do this, I will have to assign a Country to the new City. When I click on the lookup icon, I get the selection dialog with all existent countries. But if I don't have the Country I want, I have to abort the operation, get back to the countries list and create the new one I'd like to assign to my new city.
Would it be possible to create that new Country from the selection dialog with all countries?
If it is possible, is the country being added to the list right after it has been created?
Would it be possible to one define a range for the countries list? For example, showing only countries in Europe, if the user is in Europe.
I could imagine, that this would be a lot to ask from the framework. But I am just giving a shot and perhaps also giving a new feature idea, which would be nice to have.
Customization of the LOV dialog :
You can easily customize the LOV dialog by creating your own class of the LOV action that is installed next to the reference fields.
Adding a new action in the dialog (the create action) :
public class LovActionWithCreate<E, F, G> extends LovAction<E, F, G> {
private IDisplayableAction createAction;
#Override
protected void feedContextWithDialog(IReferencePropertyDescriptor<IComponent> erqDescriptor,
IQueryComponent queryComponent, IView<E> lovView, IActionHandler actionHandler,
Map<String, Object> context) {
super.feedContextWithDialog(erqDescriptor, queryComponent, lovView, actionHandler, context);
List<IDisplayableAction> defaultLovDialogActions = (List<IDisplayableAction>) context.get(
ModalDialogAction.DIALOG_ACTIONS);
defaultLovDialogActions.add(1, getCreateAction());
}
/**
* Gets create action.
*
* #return the create action
*/
protected IDisplayableAction getCreateAction() {
return createAction;
}
/**
* Sets create action.
*
* #param createAction
* the create action
*/
public void setCreateAction(IDisplayableAction createAction) {
this.createAction = createAction;
}
}
The key point is to override the feedContextWithDialog method in order to install the new action into the dialog.
Next step is to install your new LOV action. You can either do it globally for whole application or per reference view :
replacing the LOV action globally is just a matter of declaring an action named 'lovAction' into your application frontend.groovy, i.e. :
action('lovAction', parent: 'lovActionBase', class:'test.LovActionWithCreate',
custom: [createAction_ref:'theCreateAction']
)
replacing the LOV action on a certain reference field in a form can be done by using the referencePropertyView (in a form or in a table) and its 'lovAction' property, e.g. :
action('lovActionWithCreate', parent: 'lovActionBase', class:'test.LovActionWithCreate',
custom: [createAction_ref:'theCreateAction']
)
form('ACertainForm'){
fields {
...
referencePropertyView name:'country', lovAction:'lovActionWithCreate'
...
}
}
Creating an entity in the LOV dialog :
In the next step, we create the action that will be responsible for opening an extra dialog in order to create the new entity, persist it and, if successful, add it to the LOV result view. This is a little more complicated but not that much.
First of all, we have to open a new dialog.
For doing this, we will inherit the built-in EditComponentAction. The goal of this action is to edit a model in a modal dialog. The only difficulty here is that our model is only known at runtime. No problem though as we will use the dynamic nature of Jspresso.
public class CreateEntityFromLOVAction<E, F, G> extends EditComponentAction<E,F,G> {
#Override
protected Object getComponentToEdit(Map<String, Object> context) {
IEntityFactory entityFactory = getBackendController(context).getEntityFactory();
IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
Class<IEntity> entityToCreateContract = lovQueryComponent.getQueryContract();
IEntity entityInstance = entityFactory.createEntityInstance(entityToCreateContract);
setActionParameter(Arrays.asList(entityInstance), context);
return entityInstance;
}
#Override
protected IViewDescriptor getViewDescriptor(Map<String, Object> context) {
IEntityFactory entityFactory = getBackendController(context).getEntityFactory();
IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
Class<IEntity> entityToCreateContract = lovQueryComponent.getQueryContract();
IComponentDescriptor<?> entityToCreateDescriptor = entityFactory.getComponentDescriptor(entityToCreateContract);
BasicComponentViewDescriptor formViewDescriptor = new BasicComponentViewDescriptor();
formViewDescriptor.setModelDescriptor(entityToCreateDescriptor);
return formViewDescriptor;
}
}
If you look at the code above, our new action takes care of the following :
Get the type of entity to create from the context. For this, we are just exploring the query component which is the model of the LOV dialog.
Create the entity instance and set it as action parameter in the context for the chain to continue working on it (save, close dialog).
Create a form to display in the creation dialog.
Points 1 and 2 are handled by the getComponentToEdit method and point 3 by the getViewDescriptor method.
Next, when the user clicks Ok, we have to save the entity, add it to the LOV result list and close the creation dialog.
For this, we will create a new action and chain it to the saveAction and closeDialogAction built-in actions.
public class CreateEntityFromLOVPersistAction<E, F, G> extends FrontendAction<E,F,G> {
#Override
public boolean execute(IActionHandler actionHandler, Map<String, Object> context) {
if (super.execute(actionHandler, context)) {
IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
List<IEntity> createdEntityInstance = getActionParameter(context);
lovQueryComponent.setQueriedComponents(createdEntityInstance);
return true;
}
return false;
}
}
And the final wiring in SJS frontend.groovy:
action('createEntityFromLovOkAction', parent: 'okDialogFrontAction',
class:'test.CreateEntityFromLOVPersistAction',
wrapped: 'saveBackAction', next: 'closeDialogAction')
action('createEntityFromLovAction', parent: 'editComponentAction',
class: 'test.CreateEntityFromLOVAction',
name:'add.name', custom: [
okAction_ref: 'createEntityFromLovOkAction'
]
)
action('lovAction', parent: 'lovActionBase',
class:'test.LovActionWithCreate',
custom: [createAction_ref:'createEntityFromLovAction']
)
A long answer for less than 100 lines of code, but now you have a fully generic LOV action where the user can create any missing master data without leaving his current screen.
Presetting some data in the LOV filter depending on the user context :
For this, we generally use the initialization mapping that allows for setting some restrictions (either static or dynamic) on a reference property when it is queried in a LOV. For instance, let's consider the following use case :
You have 2 entities, Contract and Tariff, that are linked together through a 1-N relationship, i.e. a Contract is linked to 1 Tariff.
Contract and Tariff both have a country property and a Tariff can be assigned to a Contract if and only if they belong to the same country.
Tarrif has a status property and can only be used in a Contract if its status is ACTIVE.
You can simply enforce these rules in the LOV by setting the initialization mapping on the reference property the following way :
Entity('Contract', ...) {
...
reference 'tariff', ref: 'Tariff',
initializationMapping: [
'country': 'country',
'status': 'ACTIVE'
]
...
}
Thinking about it, this kind of behavior might very well find its way to the framework, so please, feel free to ope an enhancement request in the Jspresso GitHub.

MVC4 Html.DropDownListFor is not selecting specified value

I have the following classes:
public class PreviewImage_Edit
{
...
public List<GridDetail_Edit> GridDetails { get; set; }
public SelectList GridDetailTypesList { get; set; }
...
}
public class GridDetail_Edit
{
...
public int GridDetailTypeId { get; set; }
...
}
And, I have a partial view that expects a model of type PreviewImage_Edit, which has the following block of code:
#model PreviewImage_Edit
...
#if (Model.GridDetails != null)
{
for (var i = 0; i < Model.GridDetails.Count(); i++)
{
...
#Html.DropDownListFor(model => model.GridDetails[i].GridDetailTypeId, Model.GridDetailTypesList)
...
}
}
I am properly creating the SelectList in GridDetail_Edit and the dropdown is populating as expected. Below is the markup that is generated for the first GridDetails object:
<select data-val="true" data-val-number="The field GridDetailTypeId must be a number." data-val-required="The GridDetailTypeId field is required." id="GridDetails_0__GridDetailTypeId" name="GridDetails[0].GridDetailTypeId">
<option value="1">Top</option>
<option value="2">Bottom</option>
</select>
I've verified that the selected choice is properly saved in the database (even when the selected option isn't the first/default option in the dropdown) when the Save button is clicked. However, when I go back to re-edit, the selected option continues to be the first option in the dropdown.
I stepped through the code and verified that the data is properly retrieved from the database. I've even gone so far as converting the Html.DropDownListFor to Html.EditorFor and confirmed that the value stored in the database is making it to the view as expected.
I've used Html.DropDownListFor when the property associated with it was an integer value but never when it's an integer value that's part of a collection of objects. I would be apprehensive about what I've done so far, but everything appears to be working with this one key issue.
So far, I've tried moving the SelectList in PreviewImage_Edit into GridDetail_Edit and initializing them separately where I've programmatically set the "Selected" value for the appropriate SelectedListItem. That didn't work... same result.
Has anyone come across this issue? Any suggestions on the best way to resolve this?
Update
Below is the snippet of code that populates GridDetailTypesList
var gridDetailTypes = _db.GridDetailTypes.OrderBy(g => g.DisplayOrder).ToList();
return new SelectList(gridDetailTypes, "GridDetailTypeId", "Name");
It's pretty straightforward. The second parameter of the SelectList constructor represents the field whose values should be used in the "value" attribute. I don't believe the issue is related to the fact that the value field is an integer as I have similar code on the same page and that dropdown is functioning properly. The only difference is that my "problem" dropdowns are within a collection of my ViewModel.
The only time I've seen messages on a dropdown about "must be a number" was when I screwed up and the (numeric) value of the OPTIONs were being padded with spaces when I loaded them from a database. This doesn't appear to be your problem (and your example specifically shows no padding) but I would definitely want to look at the value of GridDetails[0].GridDetailTypeId to make sure it was of the correct type/value.
Wish I could add this as a comment rather than an answer - but my rep isn't high enough yet...
The only way it works for me is when my List is a simple IEnumerable<string>, or when I pass the same property of my custom object for both the DataText as the DataValue. As follows:
Html.DropDownListFor(m => m.TypeOfFilter, new SelectList(Model.Filters, "DataText", "DataText")
where TypeOfFilter is an enum and Model.Filters is a List<MySelectItemModel>.
That way you can see in the generated HTML that the right option is selected.

Do need to databind in gridview?

If dt_grid.Rows.Count > 0 Then
dt_grid.DataSource = dt_grid
Else
MessageBox.Show("Not Found Data")
End If
I know that if get datatable in gridview.datasource,ever write gridview.Databind.But I found coding of my friend. He write only get datatable in gridview.datasource but no write gridview.dataBind. Therefore, his coding is not error. Why? Don't need to dataBind?
Are you sure your friend is not using the DataSourceID property?
Here is the difference from MSDN:
When the DataSourceID property is set (instead of the DataSource property), the data-bound control automatically binds to the data source control at run time.
Please take a look at this article and this one.
Hope it helped.
I took the time to do a small example to demonstrate that you need to call DataBind() on a normal asp.net gridview in order to render its data.
If your friend is not calling this, I am guessing that he is binding the grid to a data source in the .aspx code (to a SQLDatasource, on even an ObjectDataSource) and he is modifying that datasource in the code.
Please take a look at the following example:
The default.aspx page:
<%# Page Title="Home Page" Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="GridViewDemo._Default" %>
<form id="form1" runat="server">
<asp:gridview id="GridView1" runat="server">
<Columns>
<asp:BoundField DataField="ID" />
<asp:BoundField DataField="Name" />
</Columns>
</asp:gridview>
</form>
The codebehind for the page: (it is in C# but I think it is relevant to VB as well)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace GridViewDemo
{
public partial class _Default : System.Web.UI.Page
{
public class Entity
{
public int ID { get; set; }
public string Name { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
List<Entity> source = new List<Entity>() { new Entity() { ID = 1, Name = "First" }, new Entity() { ID = 2, Name = "Second" } };
GridView1.DataSource = source;
GridView1.DataBind();
// if you comment this line and run, the gridview is not rendered
}
}
}
Let me know if this answered your question.