I'm quite new in Vaadin and have faced next issue. I'm trying to represent my list of entities using Tree with grouping by some properties. Everything was fine till the first level of items. What I've done:
MyEntity myEntity1 = new MyEntity(1l, "prop1", "sub_prop0")
MyEntity myEntity2 = new MyEntity(2l, "prop1", "sub_prop1")
MyEntity myEntity3 = new MyEntity(3l, "prop2", "sub_prop2")
BeanContainer<Long, MyEntity > entityContainer = new BeanContainer<>(MyEntity .class);
marketContainer.setBeanIdProperty("prop"); // prop is property name for the second value in constructor
entityContainer.addBean(myEntity1);
entityContainer.addBean(myEntity2);
entityContainer.addBean(myEntity3)
Tree markets = new Tree("Markets");
markets.setContainerDataSource(entityContainer);
as a result I've got the Tree with 2 items: prop1 and prop2 but nothing else. Actually the only I need additional is to have sup-elements with values form another property as a child items.
Thanks in advance.
Have a look at the documentation and example found here.
In short:
Set the parent of the child object
// Set it to be a child.
tree.setParent(l2, l1);
If no children are allowed, tell it so
/* Make the moons look like leaves. */
tree.setChildrenAllowed(l2, false);
If you wish to define the Hierachie in the Container, then use one of the Containers implementing the HierarchicalContainer.
There you also use the setParent(...) method to specify relationships.
Related
This is a pretty basic problem and I'm pretty sure I'm doing something wrong or making some assumption. Here goes.
I'm writing a Jira plugin, which uses the Velocity template system. I have a list of ResultRow objects where ResultRow is a class with a single member variable: String key:
public class ResultRow {
public String key;
}
I have a list of these ResultRows:
List<ResultRow> rows = new ArrayList<ResultRow>();
ResultRow row = new ResultRow();
row.key = "foo";
rows.add(foo);
Map<String, Object> velocityParams = new HashMap<String, Object>();
velocityParams.put("rows", rows);
return descriptor.getHtml("view", velocityParams);
and I am trying to list these rows in a template with the following:
#foreach ($row in $rows)
<tr><td>$row.key</td></tr>
#end
I want the output to be: foo. Maddeningly, the template system simply prints the literal string "$row.key" instead of the contents of key. To verify that "$row" is indeed an object, I used the template:
#foreach ($row in $rows)
<tr><td>$row</td></tr>
#end
and the result was as expected: com.domain.jira.ResultRow#7933f2c6.
I think maybe I'm missing some requirement for the class. Does it need to be defined in some special way to suggest to Velocity that certain members are usable in templates? Does Jira use some special funky version of Velocity that only works with certain objects?
I guess the answer is you cannot do what I was trying to do. You can call member methods but you can't access member variables, which means you'll need to add getters to your class. (Could've sworn I tried that. Ah well.)
Velocity does not expose fields, only methods. There are ways to change that:
You can create your own Uberspect class that allows access to public fields.
You can wrap the instance with a modified version of Velocity's FieldMethodizer that gives access to non-static fields.
You can add and use an instance of a "tool" class to your context, such as a subclass of VelocityTool's ClassTool.
I have this code in a Windows Service targeted to .Net 4.5 that uses a database-first Entity Framework layer:
var existingState = DataProcessor.GetProcessState(workerId);
existingState.ProcessStatusTypeId = (int)status;
existingState.PercentProgress = percentProgress;
existingState.ProgressLog = log;
DataProcessor.UpdateProcessState(existingState);
And this code in a data processing class in the same solution:
public ProcessState GetProcessState(int id)
{
using (var context = new TaskManagerEntities())
{
var processes = (from p in context.ProcessStates.Include("ProcessType").Include("ProcessStatusType")
where p.IsActive && p.ProcessStateId == id
select p);
return processes.FirstOrDefault();
}
}
public ProcessState UpdateProcessState(ProcessState processState)
{
using (var context = new TaskManagerEntities())
{
context.ProcessStates.Add(processState);
context.Entry(processState).State = System.Data.EntityState.Modified;
context.SaveChanges();
}
return processState;
}
ProcessState is a parent to two other classes, ProcessStatusType and ProcessType. When I run that code in the windows service, it retrieves a record, updates the entity and saves it. Despite the fact that the ProcessType child is never used in the above code, when the save on the ProcessState entity is performed, EF does an insert on the ProcessType table and creates a new record in it. It then changes the FK in the ProcessStatus entity to point it at the new child and saves it to the database.
It does not do this in the ProcessStatusType table, which is set up with an essentially identical FK parent-child relationship.
I now have a database full of identical ProcessType entries that I don't need, and I don't know why this is occurring. I feel like I'm making some obvious mistake that I can't see because this is my first EF project. Is the issue that I'm allowing the context to expire in between calls but maintaining the same entity?
Using Add will set the state of all elements to Added, which is causing the child elements to be inserted. The parent element is not inserted as you specify EntityState.Modified for this element.
Try using the following in the UpdateProcessState rather than using Add.
context.ProcessStates.Attach(processState);
context.Entry(processState).State = EntityState.Modified;
context.SaveChanges();
Attach will set the state of all elements to Unchanged and by specifying Modified for the parent element you are indicating that only this element should be updated.
On another note. You should use the strongly-typed Include(x => x.ProcessType) rather than Include("ProcessType").
I am new to MVC, so please excuse me if my question sounds silly or too simple. I am using Entity Data Model for database access. So in my Models folder, I have added an EDMX file and I can access the model classes from my controllers and strongly typed views. The problem arises when I access more than one table in my controller e.g.
If I have following tables in my DB :
Departments(DepartmentID, DepartmentName, DepartmentPhone)
Insurances(InsuranceID, InsuranceName, InsuranceAddress)
Employees(EmployeeID, EmpFName, EmpLName, DepartmentID, InsuranceID)
And I want to display a list of Employees with their department and insurance information.
In my Controller's Action Method I access the DB using EDM and get the information in an anonymous type:
using (var context = new MyEntities())
{
var model = (from d in context.Departments
join e in context.Employees on d.DepartmentID equals e.DepartmentID
join I in context.Insurances on I.InsuranceID equals e.InsuranceID
select new
{
DepartmentID = d.DepartmentID,
EmployeeID= e.EmployeeID,
EmpFName= e.EmpFName,
EmpLName= e.EmpLName,
DepartmentName= d.DepartmentName,
InsuranceName= I.InsuranceName
}).ToList();
return View(model);
}
I don't have a class of this anonymous type in my Model folder so I can't create a strongly typed view. So what is the best way to pass this list to the View?. Using viewbag will be an overkill if the collection is too large. Creating a new Model for this anonymous class doesn't sound right as it needs to be updated all the time if I change my selection in Controllers Action Method.
All suggestions are welcomed. I tried looking through other questions on SO but couldn't find anything relevant.
Thanks.
I don't have a class of this anonymous type in my Model folder so I
can't create a strongly typed view
Right click on your project, Add New Class ... and now you have a type in your Model folder. This is the way to go in ASP.NET MVC => view models.
And then obviously you pass this type to your view:
select new MyViewModel
{
DepartmentID = d.DepartmentID,
EmployeeID = e.EmployeeID,
EmpFName = e.EmpFName,
EmpLName = e.EmpLName,
DepartmentName = d.DepartmentName,
InsuranceName = I.InsuranceName
}).ToList();
And of course now your view becomes strongly typed to this view model:
#model IEnumerable<MyViewModel>
...
I'm afraid that predefined strongly-typed ViewModels are the way to go. It is a pain to have to update seemingly duplicate code in multiple places but in my experience it's only a problem for smaller projects. As the project grows you begin to see differences between database model objects (entities) and the viewmodels passed to your views, such as Validation and processing attributes and view-specific data, and when you get to that point you begin to prefer having separate Entity and ViewModel definitions.
However, back on-topic: an alternative solution to your problem is to use reflection to convert an anonymous type into a Dictionary<String,Object> object. Note that ASP.NET MVC does this for converting new { foo = "bar" }-syntax expressions into dictionaries for Route Values and HTML attributes already. Performance is acceptable, but don't try to do it for 10,000 objects for a single HTTP request otherwise you might get bogged down.
Here's what the code for that would look like:
Object anonymousType = new { whatever = "foo" };
Dictionary<String,Object> dict = new Dictionary<String,Object>();
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(anonymousType )) {
Object value = descriptor.GetValue(anonymousType );
dict.Add( descriptor.Name, value );
}
Of course this means that your Views won't benefit from compile-time type-checking and you'll have to maintain a documented list of dictionary keys (assuming you aren't iterating over keys in your view).
I'll note that I am surprised Microsoft didn't make anonymous types automatically implement IDictionary because it seems natural.
dynamic type is your friend.
You can declare your view as loosely typed, having a dynamic as your model
#model dynamic
You will access model properties as you do in strongly typed view
<h1>Model.DepartmentId</h1> - <h2>Model.DepartmentName</h2>
<span>Model.EmployeeId</span>
The problem thought, that dynamics contains internal properties, if you are using MVC2 you need a little trick to make it work. But seems for MVC3 and higher, it's not longer required.
I'm using a customized method for tracking individual modified properties of an n-tier disconnected entity class. I extracted it from
Programming Entity Framework: DbContext by Julia Lerman and Rowan
Miller (O’Reilly). Copyright 2012 Julia Lerman and Rowan Miller,
978-1-449-31296-1.
The code is:
public void ApplyChanges<TEntity>(TEntity root) where TEntity : class, IObjectWithState {
// bind the entity back into the context
dbContext.Set<TEntity>().Add(root);
// throw exception if entity does not implement IObjectWithState
CheckForEntitiesWithoutStateInterface(dbContext);
foreach (var entry in dbContext.ChangeTracker.Entries<IObjectWithState>()) {
IObjectWithState stateInfo = entry.Entity;
if (stateInfo.State == RecordState.Modified) {
// revert the Modified state of the entity
entry.State = EntityState.Unchanged;
foreach (var property in stateInfo.ModifiedProperties) {
// mark only the desired fields as modified
entry.Property(property).IsModified = true;
}
} else {
entry.State = ConvertState(stateInfo.State);
}
}
dbContext.SaveChanges();
}
The purpose of this method is to let the EF know only a predefined set of entity fields are ready for update in the next call of SaveChanges(). This is needed in order to workaround the entity works in ASP.NET MVC 3 as follows:
on initial page load: the Get action of the controller is loading the
entity object and passing it as a parameter to the view.
The View generate controls for editing 2 of the fields of the entity,
and holds the ID of the record in a hidden field.
When hitting [save] and posting the entity back to the controller all
of the fields excepting the 3 preserved in the view comes with a null
value. This is the default behavior of the MVC binding manager.
If i save the changes back to the database the update query will of course overwrite the non mapped fields with a sentence as follows:
UPDATE non_mapped_field_1 = NULL, ..., mapped_field_1 = 'mapped_value_1', mapped_field_2 = 'mapped_value_2', ... non_mapped_field_n = NULL WHERE ID = mapped_field_3
This is the reason i'm trying to track the fields individually and update only those fields i'm interested in. before calling the custom method with ApplyChanges() i'm adding the list of fields i want to be included in the update to the IObjectWithState.ModifiedProperties list, in order to get a SQL statement as follows:
UPDATE mapped_field_1 = 'mapped_value_1', mapped_field_2 = 'mapped_value_2' WHERE id = mapped_value_3
The problem is, when marking one of the fields as modified in ApplyChanges, i.e.:
entry.Property(property).IsModified = true;
the system is throwing the following exception:
{System.InvalidOperationException: Member 'IsModified' cannot be called for property 'NotifyCEDeadline' on entity of type 'User' because the property is not part of the Entity Data Model.
at System.Data.Entity.Internal.InternalPropertyEntry.ValidateNotDetachedAndInModel(String method)
at System.Data.Entity.Internal.InternalPropertyEntry.set_IsModified(Boolean value)
at System.Data.Entity.Infrastructure.DbPropertyEntry.set_IsModified(Boolean value)
...
So the question is. There's a way to bypass this EF validation or let the context know of the existance of this system property (IsModified) that i'm trying to change?
Summary of the architeture:
EF Code first (annotation + Fluent API)
Oracle .NET EF Data provider (ODAC)
Context is injected to a cutom business context with nInject.MVC => this is the reason i customized the ApplyChanges() method from
using (var context = new BreakAwayContext()){
context.Set().Add(root);
to a simple call to the already initialized dbcontext
dbContext.Set().Add(root);
Oracle Database is created manually i.e. without the help of EF, so no EF metadata tables are used.
Thanks,
Ivan.
Very good description, however I can't find any information on why you need a transient property called "IsModified" in the object and/or why you need to tell EF about it being modified (EF won't be able to persist it anyway).
The value of the IsModified property should be set by the model binder if the property was incldued in the view anyway.
You could just add code in your ApplyChanges method to skip a property named "IsModified", or even better, filter only known properties using entry.CurrentValues.PropertyNames, e.g.:
foreach (var property in stateInfo.ModifiedProperties) {
// mark only the desired fields as modified
if (entry.CurrentValues.PropertyNames.Contains(property)) {
entry.Property(property).IsModified = true;
}
}
Update: Ivan, very sorry I did not understand the problem better when you posted it several months ago and that I did not follow up after your added these clarifying comments. I think I understand better now. That said, I think the code snippet that I offered can be part of the solution. From looking at the exception you are getting again, I understand now that the problem that EF is detecting is that NotifyCEDDealine is not a persistent property (i.e. it is not mapped in the Code First model to a column in the database). IsModified can only be used against mapped properties, therefore you have two options: you change the code of the implementation of IObjectWithState in your entities so that non-mapped properties are not recorded in ModifiedProperties, or you use my code snippet to prevent calling IsModified with those.
By the way, an alternative to doing all this is to use the Controller.TryUpdateModel API to set only the modified properties in your entities.
Hope this helps (although I understand it is very late).
I'm trying to have a View where the user can add items in a collection without having to go to a new View (the scenario is a sort of CV site where the user adds info about work experience, skills, etc, and it would seem absurd to go to a new View to add each little thing).
So I have an edit View that shows a number of text boxes for the already added items, and there's an ajax call to go to a method to fetch the collection fresh if the user adds an item.
Here are the methods in question:
public ActionResult Edit(int id)
{
Consultant consultant = _repository.GetConsultant(id);
var vm = GetViewModel(consultant);
return View(vm);
}
private DetailsViewModel GetViewModel(Consultant consultant)
{
return new DetailsViewModel
{
Programs = consultant.Programs.ToList(),
Consultant = consultant
};
}
public ActionResult NewProgram(int id)
{
//TODO: ordering is rather strange, because the entitycollection adds at the beginning rather than the end...
Consultant consultant = _repository.GetConsultant(id);
consultant.Programs.Add(new Program());
_repository.Save();
var vm = GetViewModel(consultant);
return PartialView("ProgramList", vm);
}
Now to the question: When the NewProgram method is called, it adds a new program to the Consultant object and creates a new ViewModel to send back, but it adds the new program to the start of the EntityCollection, not at the end. But then when you post the entire form, and you open the Edit View again, the list will have placed the new added program at the end. This is very strange. The user will think he/she adds an item at the start of the list, but if they go back to the page again, they will find the new item at the end.
Why does it do this, and is there any way I can make NewProgram() have the new program added at the end directly?
And if anyone is thinking "he should be using a ViewModel" with DTOs instead of working directly with EF objects, well, I've been down that road for quite a while now ( Entity Framework and MVC 3: The relationship could not be changed because one or more of the foreign-key properties is non-nullable ), and so far no one has shown me explicitly how to achieve this and still be able to both add and remove items in the same View. There is either a problem with maintaining the indexes of the collections or the Entity Framework won't let me save... And the code became a nightmare.
This way I at least have understandable code, and the only thing is I need to have this adding done in the "normal" order, i.e. add at the end of the collection...
Any ideas?
BTW:
This works, but it seems very unnecessary to first have to add the new program to the Consultant object, create the ViewModel without the new program, and then add it to the ViewModel separately...
public ActionResult NewProgram(int id)
{
//TODO: ordering is rather strange, because the entitycollection adds at the beginning rather than the end...
Consultant consultant = _repository.GetConsultant(id);
var vm = GetViewModel(consultant);
var program = new Program();
consultant.Programs.Add(program);
_repository.Save();
vm.Programs.Add(program);
return PartialView("ProgramList", vm);
}
According to http://blogs.msdn.com/b/adonet/archive/2009/12/22/poco-proxies-part-1.aspx , your navigation property Programs is overridden to invoke some kind of DoLazyLoad() method. Since the property instance itself isn't necessarly changed, DoLazyLoad() might actually by asynchronous, which could account for the behavior you're noticing.
Since you are evaluating the list anyhow, you could call ToList() before adding the new program. It would require you to only change the line a bit:
consultant.Programs.ToList().Add(new Program());
If this doesn't work, try:
consultant.Programs.ToList();
consultant.Programs.Add(new Program());
This actually doesn't work well with my "asynchronous" theory, but might help you out.