Two dimensional list in a Grid - asp.net-mvc-3

My case: I have a bunch of variables. These variables are shared between all Environments. In each Environment these variables have several values, each value connected to a "EnvironmentVariableSet". The amount of EnvironmentVariableSets vary from Environment to Environment. The number of variables are fixed.
For a given Environment I want to display, in a Grid, all the variables, and for each EnvironmentVariableSet, the value of each variable. Something like this:
Column 1 : The variables
Column 2 : The values of the variable in set1
...
Column N : The values of the variable in setN
The goal is that for each variable, the user can edit the value of that variable in a given EnvironmentVariableSet for a given Environment.
My Models:
public class VariableValues
{
public int VariableID { get; set; }
public string VariableName { get; set; }
public List<EnvironementVariableSetValue> environmentSetValues { get; set; }
}
public class EnvironementVariableSetValue
{
public String EnvironmentVariableValue { get; set; }
public int VariableID { get; set; }
}
My Grid
#(Html.Telerik().Grid(variableValues)
.Name("EnvironmentVariables")
//blabla
.Columns(columns =>
{
columns.Bound(v => v.VariableName).Width(50).ReadOnly();
//I NEED A WAY TO BIND EACH COLUMN TO THE UNDEFINED NUMBER ENVIRONMENTVARIABLESETS WITH VALUES HERE! SOMETHING LIKE THIS
//columns.Bound(v => v.ValueForSetN).Whitd(50);
})
//blabla
)
Maybe Im just stupid, but i cant find a good solution for this.
Thanks

Related

Count the occurrences of an object in a list where multiple criteria are matching using LINQ

I have a list of Cutdetails. I am trying to write a function using LINQ that will return the count of bars in the list where the CODE , BRAND, CODE and LENGTH all match. I want to be able to specify all these parameters and return a number for the number of matches.
I have tried using foreach statements which is fine but i'm sure there is an neater and smarter way to do it using LINQ. Any suggestions?
List<Bar> bars = new List<Bar>();
public class Bar
{
public string Brand { set; get; }
public string System { set; get; }
public string Code { set; get; }
public string Length { set; get; }
}
Thanks in advance!
Will
You can filter using the match and then do a count.
var occurences = bars.Where(x => x.Brand == "Brand" && x.Code == "code").Count();

Combining Linq Expressions for Dto Selector

We have a lot of Dto classes in our project and on various occasions SELECT them using Expressions from the entity framework context. This has the benefit, that EF can parse our request, and build a nice SQL statement out of it.
Unfortunatly, this has led to very big Expressions, because we have no way of combining them.
So if you have a class DtoA with 3 properties, and one of them is of class DtoB with 5 properties, and again one of those is of class DtoC with 10 properties, you would have to write one big selector.
public static Expression<Func<ClassA, DtoA>> ToDto =
from => new DtoA
{
Id = from.Id,
Name = from.Name,
Size = from.Size,
MyB = new DtoB
{
Id = from.MyB.Id,
...
MyCList = from.MyCList.Select(myC => new DtoC
{
Id = myC.Id,
...
}
}
};
Also, they cannot be reused. When you have DtoD, which also has a propertiy of class DtoB, you would have to paste in the desired code of DtoB and DtoC again.
public static Expression<Func<ClassD, DtoD>> ToDto =
from => new DtoD
{
Id = from.Id,
Length = from.Length,
MyB = new DtoB
{
Id = from.MyB.Id,
...
MyCList = from.MyCList.Select(myC => new DtoC
{
Id = myC.Id,
...
}
}
};
So this will escalate pretty fast. Please note that the mentioned code is just an example, but you get the idea.
I would like to define an expression for each class and then combine them as required, as well as EF still be able to parse it and generate the SQL statement so to not lose the performance improvement.
How can i achieve this?
Have you thought about using Automapper ? You can define your Dtos and create a mapping between the original entity and the Dto and/or vice versa, and using the projection, you don't need any select statements as Automapper will do it for you automatically and it will project only the dto's properties into SQL query.
for example, if you have a Person table with the following structure:
public class Person
{
public int Id { get; set; }
public string Title { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
public string Initial { get; set; }
public string PreferredName { get; set; }
public string FormerTitle { get; set; }
public string FormerFamilyName { get; set; }
public string FormerGivenName { get; set; }
}
and your dto was like this :
public class PersonDto
{
public int Id { get; set; }
public string Title { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
}
You can create a mapping between Person and PersonDto like this
Mapper.CreateMap<Person, PersonDto>()
and when you query the database using Entity Framework (for example), you can use something like this to get PersonDto columns only:
ctx.People.Where(p=> p.FamilyName.Contains("John"))
.Project()
.To<PersonDto>()
.ToList();
which will return a list of PersonDtos that has a family name contains "John", and if you run a sql profiler for example you will see that only the PersonDto columns were selected.
Automapper also supports hierachy, if your Person for example has an Address linked to it that you want to return AddressDto for it.
I think it worth to have a look and check it, it cleans a lot of the mess that manual mapping requires.
I thought about it a little, and I didn't come up with any "awesome" solution.
Essentially you have two general choices here,
Use placeholder and rewrite expression tree entirely.
Something like this,
public static Expression<Func<ClassA, DtoA>> DtoExpression{
get{
Expression<Func<ClassA, DtoA>> dtoExpression = classA => new DtoA(){
BDto = Magic.Swap(ClassB.DtoExpression),
};
// todo; here you have access to dtoExpression,
// you need to use expression transformers
// in order to find & replace the Magic.Swap(..) call with the
// actual Expression code(NewExpression),
// Rewriting the expression tree is no easy task,
// but EF will be able to understand it this way.
// the code will be quite tricky, but can be solved
// within ~50-100 lines of code, I expect.
// For that, see ExpressionVisitor.
// As ExpressionVisitor detects the usage of Magic.Swap,
// it has to check the actual expression(ClassB.DtoExpression),
// and rebuild it as MemberInitExpression & NewExpression,
// and the bindings have to be mapped to correct places.
return Magic.Rebuild(dtoExpression);
}
The other way is to start using only Expression class(ditching the LINQ). This way you can write the queries from zero, and reusability will be nice, however, things get harder & you lose type safety. Microsoft has nice reference about dynamic expressions. If you structure everything that way, you can reuse a lot of the functionality. Eg, you define NewExpression and then you can later reuse it, if needed.
The third way is to basically use lambda syntax: .Where, .Select etc.. This gives you definitely better "reusability" rate. It doesn't solve your problem 100%, but it can help you to compose queries a bit better. For example: from.MyCList.Select(dtoCSelector)

How to update hierarchical ViewModel?

I am stuck with this problem.
I have a model AssessmentModel defined like this:
public class AssessmentModel
{
public Respondent Respondent { get; set; }
public List<CompetencyModel> Competencies { get; set; }
}
public class CompetencyModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<ResultModel> Results { get; set; }
}
public class ResultModel
{
public int Id { get; set; }
public int Score { get; set; }
}
All I need is to set value to the Score property of ResultModel.
Score is the only editable property here.
And I have just 1 View only, this view has a #model List, it displays a list of CompetencyModel items with Edit button for each one.
When I click the Edit button, the Id of CompetencyModel is passed to the same View, and the View draws an Edit form for ResultModel items that belong to the selected CompetencyModel.
However the form for ResultModel items exists on the same View, and the model of the View is still #model List.
How can I get to the Score property by using bindable Html.EditorFor(m=>m.Score) helper for each ResultModel item?
The View is defined like this:
#model List<CompetencyModel>
#foreach(var comp in Model)
{
<p>#comp.Name</p>
Edit
}
In the controller I set ViewBag.CurrentId = comp.Id, and at the bottom of the View:
if(ViewBag.CurrentId != null) //draw a form for ResultModel items
{
// What should I do now?
// how cant I use Html.EditorFor(m=>...) if the Model is still List<CompetencyModel>
}
I need to get to a single ResultModel entity to set a value to a Score property.
Thank you.
You should be able to get this done using Linq. Consider having the following code segment in the your last if statement
var result = Model.Results.FirstOrDefault(r => r.Id == ViewBag.CurrentId);
I dont have a IDE with me, so watchout for syntext errors

Using LINQ to combine similar rows of grouped data

I've got some data in a table that looks like so:
Recipe | Category | Email
What I'd like to do is pull this data back from the source and put it into something that looks like so:
public class RecipeItem
{
public long Recipe { get; set; }
public long Category { get; set; }
public List<string> Names {get; set; }
}
Grouping by the Recipe and Category ids and putting all the emails that into the list.
So, what I've tried is to do something like this:
var recipeItems =
from entry in list
group entry by new { entry.Recipe, entry.Category}
into aRecipe
select new RecipeItem()
{
Recipe = aRecipe.Key.Recipe,
Category = aRecipe.Key.Category,
// ? Not sure how to stick the list of names in here
};
list is the data pulled back via entity framework.
But this isn't quite right - I think I'm close here (maybe). What am I missing here on this?
Follow-up:
Thanks to Aducci for clearing this up. The answer is that you can do this:
Names = aRecipe.Select(x => x.Name)
and this will add all those Names which are in each group into the Names collection for that group. Pretty nifty.
I would modify your class to look like this
public class RecipeItem
{
public long Recipe { get; set; }
public long Category { get; set; }
public IEnumerable<string> Names {get; set; }
}
And your link to entities query to:
var recipeItems =
from entry in list
group entry by new { entry.Recipe, entry.Category}
into aRecipe
select new RecipeItem()
{
Recipe = aRecipe.Key.Recipe,
Category = aRecipe.Key.Category,
Names = aRecipe.Select(x => x.Name)
};

how to fill missing values from a list

I have an object containing a date and a count.
public class Stat
{
public DateTime Stamp {get; set;}
public int Count {get; set ;}
}
I have a Serie object that holds a list of thoses Stat plus some more info such as name and so on...
public class Serie
{
public string Name { get; set; }
public List<Stat> Data { get; set; }
...
}
Consider that I have a List of Serie but the series don't all contain the same Stamps.
I need to fill in the missing stamps in all series with a default value.
I thought of an extension method with signature like this (please provide better name if you find one :) ) :
public static IEnumerable<Serie> Equalize(this IEnumerable<ChartSerie> series, int defaultCount)
this question seems to treat the same problem, but when querying directly the DB. of course I could loop through the dates and create another list. But is there any more elegant way to achieve this?
i.e.:
Serie A:
01.05.2010 1
03.05.2010 3
Serie B:
01.05.2010 5
02.05.2010 6
I should get :
Serie A :
01.05.2010 1
02.05.2010 0
03.05.2010 3
Serie B:
01.05.2010 5
02.05.2010 6
03.05.2010 0
Not sure if this is elegant enough for you ;-) but since I like Linq, this is what I would have done (using your naming scheme):
public static IEnumerable<Serie> Equalize(
this IEnumerable<Serie> series,
int defaultCount)
{
var allStamps = series
.SelectMany(s => s.Data.Select(d => d.Stamp))
.Distinct()
.OrderBy(d => d)
.ToList();
return series.Select(serie => new Serie(
serie.Name,
allStamps.Select(d =>
serie.Data.FirstOrDefault(stat => stat.Stamp == d)
??
new Stat(d, defaultCount))
));
}
For this code to compile, your classes needs a couple of constructors:
public class Stat
{
public Stat() {}
public Stat(DateTime stamp, int count)
{
Stamp = stamp;
Count = count;
}
public DateTime Stamp { get; set; }
public int Count { get; set; }
}
public class Serie
{
public Serie() {}
public Serie(string name, IEnumerable<Stat> data)
{
Name = name;
Data = new List<Stat>(data);
}
public string Name { get; set; }
public List<Stat> Data { get; set; }
}
When calling series.Equalize(0) the code above will leave the original instances intact, and return a sequence of newly created Serie-instances with their Data padded with defaults.
Nothing magic about it. Just the sweetness of Linq... (and the null coalescing operator!)
I haven't tried this with loads and loads of data, so your milage may vary.

Resources