Access TreeMap entries by string key in JSTL - jstl

This is pretty similar to some other questions, but nobody else is working with string keys. So here we go.
I've got a TreeMap with a set of category names, keyed by category ID. The ID is a number (as a String).
I build up the TreeMap with values, then expose it to the page, like so:
<%
Map categories = new TreeMap();
...
String categoryId = ...;
String categoryName = ...;
categories.put(categoryId, categoryName);
...
pageContext.setAttribute("categories", categories);
%>
Later, I iterate through a series of items which have been assigned to categories. Each item has a .categories collection which contains the IDs of the categories to which it has been assigned. I want to display the names, so I do something like this:
<c:forEach items="${item.categories}" var="catId">
${categories[“${catId}”}
</c:forEach>
Unfortunately, this doesn't emit anything. Nor does ${categories["${catId}"].value}.
However, this does:
${categories["2"]}
Of course, that line isn't actually driven by item data.
I've checked, and the IDs attached to each item do in fact correspond to category IDs; this isn't a data mismatch problem.
So, how do I get my hands on category names when the data attached to items has only IDs?
P.S. I should mention that I'm not a Java programmer -- at all. LAMP is more my style. So modifying classes isn't really an option.

EDIT: Sorry, I misread the question.
Unwrap your catId variable:
${categories[“${catId}”}
should be
${categories[catId]}
That should fix it.

Related

LINQ query left joining two tables with concatenation

I am using this as a reference -- how concatenate multiple rows in LINQ with two tables?
I have the exact same needs, except that not all "printers" have "resolutions". In my particular case, I have a Lead table, which stores some basic information. Then there is a tag table, which stores tags used for the Lead. Not every lead has a tag.
This is what I have so far based on the above reference:
var leads = _dbRO.Leads.Join(_dbRO.Tags, p => p.LeadId, r => r.EntityId, (p, r) => new
{
LeadId = p.LeadId,
GigDate = p.GigDate,
Location = p.Location,
Tags = String.Join("|", _dbRO.Tags.Where(k => k.EntityId == p.LeadId)
.Select(lm => lm.TagName.ToString()))
}).Distinct();
This works well for me. However, leads without tags are NOT returned. How do I ensure all leads are returned regardless of tags. An empty string or null for Tags field would be fine.
Also if you don't mind, if I want to return the Tags in an object array, how do I do that? The reason is because there could be additional information associated with each tag, like color etc. So a simple concatenated string might not be sufficient.
Thanks a bunch!
I've figured out -- I do not need to join the tag table at all. This causes the problem. I just need to select from my Lead table and in the Select section, get the tags as I was already doing.
If you’ve declared a relationship between Lead and Tag entity types, then EF already supplies your requirements through the Include() extension method.
ctx.Leads.Include(l => l.Tags).ToList()
This requires that Lead declares a navigation property to Tag as shown below.
class Lead
{ ... public List<Tag> Tags { get; set; } }

Linq related items not loading

I have a "task" table, which has a "sub category". The sub category is related to a Category. A category has many sub categories, but my task item only stored the sub category id (The category can be deduced from this).
So, my entity framework seems to understand this relationship.
But, my link is failing.
public TaskObject GetTask(int taskId)
{
var item = (from t in _te.tasks.Include("r_sub_category").Include("r_category").Include("r_priority").Include("r_state").Include("assigned_person").Include("create_person").Include("update_person") where t.task_id == taskId select t).FirstOrDefault();
return Transformer.UnpackTask(item);
}
There is a r_category table, and entity object, but when I run this, it tells me:
A specified Include path is not valid. The EntityType 'taskerModel.task' does not declare a navigation property with the name 'r_category'.
And that's correct - r_category is linked to my r_sub_category table... and not directly to task. Is there a way to load the r_category?
Or, maybe this Include is lazy, and I should be doing some sort of Joining myself? Maybe more efficient?
You need to show the full path with dot Notation so im guessing it would be
"r_sub_category.r_category".
And so forth

How can I use set operations to delete objects in an entitycollection that match a collection of view models?

Here is a very basic example of what I want to do. The code I have come up with seems quite verbose... ie looping through the collection, etc.
I am using a Telerik MVC grid that posts back a collection of deleted, inserted and updated ViewModels. The view models are similar but not exactly the same as the entity.
For example... I have:
Order.Lines. Lines is an entity collection (navigation property) containing OrderDetail records. In the update action of my controller using the I have a List names DeletedLines pulled from the POST data. I also have queried the database and have the Order entity including the Lines collection.
Now I basically want to tell it to delete all the OrderDetails in the Lines EntityCollection.
The way I have done it is something like:
foreach (var line in DeletedLines) {
db.DeleteObject(Order.Lines.Where(l => l.Key == line.Key).SingleOrDefault())
}
I was hoping there was a way that I could use .Interset() to get a collection of entities to delete and pass that to DeleteObject.. however, DeleteObject seems to only accept a single entity rather than a collection.
Perhaps the above is good enough.. but it seemed like there should be an easier method.
Thanks,
BOb
Are the items in DeletedLines attached to the context? If so, what about this?
foreach (var line in DeletedLines) db.DeleteObject(line);
Response to comment #1
Ok, I see now. You can make your code a bit shorter, but not much:
foreach (var line in DeletedLines) {
db.DeleteObject(Order.Lines.SingleOrDefault(l => l.Key == line.Key))
}
I'm not sure if DeleteObject will throw an exception when you pass it null. If it does, you may be even better off using Single, as long as you're sure the item is in there:
foreach (var line in DeletedLines) {
db.DeleteObject(Order.Lines.Single(l => l.Key == line.Key))
}
If you don't want to re-query the database and either already have the mapping table PK values (or can include them in the client call), you could use one of Alex James's tips for deleting without first retrieving:
http://blogs.msdn.com/b/alexj/archive/2009/03/27/tip-9-deleting-an-object-without-retrieving-it.aspx

LINQ to IEnumerable<MyObj>

I have a class MyObj and a collection IEnumerable.
Some of the columns are wholly empty (i.e. == NULL) across all rows and therefore I want to create an IEnumerable<> of the members of MyObj which hold a non-null value.
If I could predict the members of MyObj which would be of interest I'd do something like:
var part =
from entry in iList
select new {entry.a, entry.c, entry.s};
...but I don't know which members of MyObj I'm interested in at design time - I only know that at runtime.
How can I construct my list??
Thanks,
Tamim Sadikali.
Your question does not make sense.
You're trying to create a type whose members are only known at runtime.
What would you do with the results?
You would not be able to access any properties of the result objects because they might not exist.
If you want to display the data in a grid, and you don't want to display columns which are entirely null, then you should bind the original collection to the grid, then hide some of the columns in the grid.
Wait for release of VS2010, C# 4.0 with it's 'dynamic' type should solve your problem. (Or maybe help you shoot yourself in the foot).
If you are doing this for UI, better hide columns that contain all nulls. For DataGridView in WinForms it may look like this:
foreach (DataGridViewColumn column in dataGridView.Columns)
if (dataGridView1.Rows.Cast<DataGridViewRow>().All(r => r.Cells[column.Name].Value == null))
column.Visible = false;

best practice Treeview populating from differents kinds of objects

I would like to populate a Treeview.
Here is what I have in DB :
table : Box
BoxID
BoxName
table Book :
BookID
BookName
BoxID (fk Box.BoxID)
table Chapter:
ChapterID
ChapterName
BookID (fk Book.BookID)
As you may know a treeview is made up of treenode object.
A treenode object have a text property and a tag property.
The "text" property is the text that it's display on the screen for this node and the "tag" is an "hidden" value (usually uses to identify a node)
So in my case; the fields ending with ID will be used in the "tag" property and the fields ending with Name will be used in the "text" property
example :
so for a book; I will use the BookID field for the "tag" property and BookName field for the "text" property
note : I use a dbml so I have a Book object, Box object and Chapter object and I use linq to get them from the db.
So my question is; what is the best practice to build this tree?
I have a solution but it's really ugly because it looks like I'm duplicating the code.
The problem is that the values I need to extract for the text and tag properties are identified by differents fields name in the db
So for the book level, I need to get the BookID field to populate the tag property of my node; for the box level, I need to get the BoxID field to populate the tag property , ....
How can I make a kind of generic way to do it ?
I hope I made myself clear enough, don't hesitate to ask me questions :)
Thx in advance
Here is what I have for the moment
I get the list of box with a linq (dbml) request.
List<Box> MyListofBox = getMyListofBox();
Treenode tnBox = null;
Treenode tnBook =null;
foreach(Box b in MyListofBox )
{
tnBox = new TreeNode();
tnBox.tag = b.BoxID;
tnBox.text = b.BoxName;
List<Book> MyListofBook = getMyListofBookByBoxID(b.BoxID)
foreach(Book boo in MyListofBook )
{
tnBook = new TreeNode();
tnBook.tag = boo.BookID;
tnBook.text = boo.BookName;
tnBox.nodes.add(tnBook);
}
mytreeview.nodes.add(tnBox);
}
but of course I don't like this solution...
do you have a better way ?
I would extract the you need from the database in the form of a struct, possibly via the anonnoumous type that has been added to C# together with linq. Then I would populate insert this data into the place in the tree.
From what I get, you are trying to get each property separately, which will not work so well, because then you will have to make a call to the database for each separate property, which is very wasteful.
Addition based on what you have added
I do not believe the code can be more compact - the names you call are similar, but not the same and the way you do it was what I was trying to explain earlier.
You could
Define an key/value interface that both Box and Book implement
Define a delegate that returns a TreeNode and create delegate methods that accept Box and Book
However, I think the code is fine as written. Sometimes you just have to code it and there's little point in further abstracting or optimizing it.
The only issue I see in the code is that you're making a database call in a loop. Whether or not that's a problem depends on the application.

Resources