Get list on basis of dropdownlist data in asp.net mvc3 - asp.net-mvc-3

I have two dropdownlists in my module.
In one dropdownlist, I have hardcoded all the operators like <,>,<=,>=,==
In second dropdownlist, I have hardcoded salary of employees like 1000,2000,3000,4000....50000
Now if I select < from one list and 2000 from second list and click on submit button I should get list of employees who have salary less than 2000.
I want to do this in asp.net mvc3
How can I accomplish this task? Do I need to write a stored procedure for this?
I have created dropdownlist like:
viewModel.OperatorsList = new[]
{
new SelectListItem { Value = "<", Text = "<" },
new SelectListItem { Value = ">", Text = ">" },
new SelectListItem { Value = "<=", Text = "<=" },
new SelectListItem { Value = ">=", Text = ">=" },
new SelectListItem { Value = "==", Text = "==" }
};
viewModel.SalaryList = new[]
{
new SelectListItem { Value = "1000", Text = "1000" },
new SelectListItem { Value = "2000", Text = "2000" },
new SelectListItem { Value = "3000", Text = "3000" },
// and so on
};
and I have used this to show dropdownlist in view:
<%: Html.DropDownListFor(x => x.Operators, Model.OperatorsList)%>

well, you could do something like that
assuming viewModel is... your viewModel, and you've got an entity Employee with a property Salary (int in this sample, it's probably a decimal in real world)
create a static helper class
public static class MyHelper
{
// a dictionary for your operators and corresponding ExpressionType
public static Dictionary<string, ExpressionType> ExpressionTypeDictionary = new Dictionary<string, ExpressionType>
{
{"<", ExpressionType.LessThan},
{">", ExpressionType.GreaterThan},
{">=", ExpressionType.GreaterThanOrEqual}
//etc
};
//a method to filter your queryable
public static IQueryable<Employee> FilterSalary(this IQueryable<Employee> queryable, int salary, string operatorType)
{
//left part of the expression : m
var parameter = Expression.Parameter(typeof(Employee), "m");
//body is the right part of the expression : m
Expression body = parameter;
//m.Salary
body = Expression.Property(body, "Salary");
//m.Salary <= 1000 (for example)
body = Expression.MakeBinary(ExpressionTypeDictionary[operatorType], body, Expression.Constant(salary));
//m => m.Salary <=1000
var lambda = Expression.Lambda<Func<Employee, bool>>(body, new[] { parameter });
//so it will be queryable.Where(m => m.Salary <= 1000)
return queryable.Where(lambda);
}
}
usage
var queryable = context.All<Employee>();//or something like that, returning an IQueryable<Employee>
queryable = queryable.FilterSalary(viewModel.Salary, viewModel.Operators);

Related

Load multipe sharepoint list item fields in one Go using CSOM c#

***ctx.Load(listItemCollection,
eachItem => eachItem.Include(
item => item,
item => item["Column1"],
item => item["Column2"]
));***
i have list of fields in a array of string instead of column1 and column2, how can i pass it through in include linq, not able to create proper lambda on runtime. i tried following ways but couldn't get success. Static befor loops works but thw fields added in loop fails as it doesn't evaluate string value in loop
***Expression<Func<ListItem, object>>[] paramss = new
Expression<Func<ListItem, object>>[length];
paramss[0] = x => x.ContentType;
paramss[1] = x => x["Title"];
count = 2;
foreach (string item in solConnDefModel.Columns)
{ paramss[count] = x => x[item];
count++;
}***
Please take a reference of below code:
List dlist = context.Web.Lists.GetByTitle("listname");
context.Load(dlist);
context.ExecuteQuery();
string[] fieldNames = { "Id", "Title", "num", "mStartDate" };
// Create the expression used to define the fields to be included
List<Expression<Func<ListItemCollection, object>>> fieldsToBeIncluded = new List<Expression<Func<ListItemCollection, object>>>();
foreach (string s in fieldNames)
{
fieldsToBeIncluded.Add(items => items.Include(item => item[s]));
}
// Initialize the collection of list items
var listItems = dlist.GetItems(new CamlQuery());
context.Load(listItems, fieldsToBeIncluded.ToArray());
context.ExecuteQuery();
You can hover on load method to see what type parameter it requires, then generate a corresponding one and pass it.
i have to create lambda expression at runtime. following code i was able to get expected value
Expression<Func<ListItem, object>>[] paramss = new Expression<Func<ListItem, object>>[length];
foreach (string item in Columns)
{
if (item.ToLower() != "contenttype")
{
ParameterExpression parameter = Expression.Parameter(typeof(ListItem), "x");
var propertyInfo = typeof(ListItem).GetMethod("get_Item");
var arguments = new List<Expression> { Expression.Constant(item) };
var expression = Expression.Call(parameter, propertyInfo, arguments);
var lambda = Expression.Lambda<Func<ListItem, object>>(expression, parameter);
paramss[count] = lambda;
}
else
{
paramss[count] = x => x.ContentType;
}
count++;
}

Why does my selected value not get added to my SelectListItem as the “Text” and “Value” properties do?

I am trying to set a default value of a list in a partial view. The partial view is called using this…
#Html.Action("Acton", "Controller", new { department = item.Data.departmentNumber, defaultValue="someValue" })
Then in the controller I have…
[ChildActionOnly]
public ActionResult Categories(int? id, int? department, string defaultValue)
{
var typeList = from e in db.Rubrics where e.DepartmentID == department select e;
var selectedRubrics = typeList.Select(r => r.Category);
List<String> rubricsList = selectedRubrics.ToList();
var categories = new List<SelectListItem>();
for (int i = 0; i < rubricsList.Count(); i++)
{
categories.Add(new SelectListItem
{
Text = rubricsList[i],
Value = rubricsList[i],
Selected = (defaultValue == "defaultValueGetsSentToView")
});
}
var ViewModel = new RubricsViewModel
{
Category = "Select a Category",
Categories = categories
};
return View(ViewModel);
}
Why does my selected value not get added to my SelectListItem as the “Text” and “Value” properties are? Thanks for any help!
Assuming the values in the code are the literal values you are using, "defaultValue" is "someValue" and you are setting selected with the comparison defalutValue == "defaultValueGetsSentToView".
"someValue" == "defaultValueGetsSentToView" evaluates to false.

How to iterate through GroupBy groups using Dynamic LINQ? [duplicate]

I am using Dynamic Linq helper for grouping data. My code is as follows :
Employee[] empList = new Employee[6];
empList[0] = new Employee() { Name = "CA", State = "A", Department = "xyz" };
empList[1] = new Employee() { Name = "ZP", State = "B", Department = "xyz" };
empList[2] = new Employee() { Name = "AC", State = "B", Department = "xyz" };
empList[3] = new Employee() { Name = "AA", State = "A", Department = "xyz" };
empList[4] = new Employee() { Name = "A2", State = "A", Department = "pqr" };
empList[5] = new Employee() { Name = "BA", State = "B", Department = "pqr" };
var empqueryable = empList.AsQueryable();
var dynamiclinqquery = DynamicQueryable.GroupBy(empqueryable, "new (State, Department)", "it");
How can I get back the Key and corresponding list of grouped items i.e IEnumerable of {Key, List} from dynamiclinqquery ?
I solved the problem by defining a selector that projects the Key as well as Employees List.
var eq = empqueryable.GroupBy("new (State, Department)", "it").Select("new(it.Key as Key, it as Employees)");
var keyEmplist = (from dynamic dat in eq select dat).ToList();
foreach (var group in keyEmplist)
{
var key = group.Key;
var elist = group.Employees;
foreach (var emp in elist)
{
}
}
The GroupBy method should still return something that implements IEnumerable<IGrouping<TKey, TElement>>.
While you might not be able to actually cast it (I'm assuming it's dynamic), you can certainly still make calls on it, like so:
foreach (var group in dynamiclinqquery)
{
// Print out the key.
Console.WriteLine("Key: {0}", group.Key);
// Write the items.
foreach (var item in group)
{
Console.WriteLine("Item: {0}", item);
}
}

Indirection with linq : Change query expression "Select" according users parameters

I use a table "TLanguage" to record lable results of my site. I have 4 columns in this table: French, English, German and Spanish.
In a MVC application I use this query:
var req = (from TYP in context.TYP_TypeMission
join ML in context.TLanguage on TYP.IDTMultiLanguage equals ML.IDTMultiLanguage
where TYP.IDTFiliale == idFiliale
orderby TYP.LibTypeMission
select new SelectListItem
{
Selected = TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)TYP.IdTypeMission),
Text = ML.French
}).ToList();
How can I change ML.French by ML.English or ML.German in my query according the language of my site?
Is it possible to create an indirection in the query?
It is possible to parametrize the mapping like this:
public class TLanguageMap : EntityTypeConfiguration<TLanguage>
{
public TLanguageMap(string language)
{
this.HasKey(t => t.TLanguageId);
this.Property(t => t.Translation).HasColumnName(language);
}
}
In the context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new TLanguageMap(this._language));
}
and its constructor:
public LocalizableContext(string language)
{
this._language = language;
}
Now when constructing a context you can determine for which language it is:
var context = new LocalizableContext("French");
And the query will always be:
...
select new SelectListItem
{
Selected = TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)TYP.IdTypeMission),
Text = ML.Translation
})
You may want to make it more robust by using an enum for the languages and a switch statement to get the database column names.
You can save the beginning of your query into variable and change only the last part later:
var query = from TYP in context.TYP_TypeMission
join ML in context.TLanguage on TYP.IDTMultiLanguage equals ML.IDTMultiLanguage
where TYP.IDTFiliale == idFiliale
orderby TYP.LibTypeMission
select new { ML, TYP };
List<SelectListItem> req;
if(Site.Lang == "DE")
{
req = (from item in query
select new SelectListItem
{
Selected = item.TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)item.TYP.IdTypeMission),
Text = item.ML.German
}).ToList();
}
else if(Site.Lang == "FR")
{
req = (from item in query
select new SelectListItem
{
Selected = item.TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)item.TYP.IdTypeMission),
Text = item.ML.French
}).ToList();
}
else
{
req = (from item in query
select new SelectListItem
{
Selected = item.TYP.IdTypeMission == idTypeMission,
Value = SqlFunctions.StringConvert((double)item.TYP.IdTypeMission),
Text = item.ML.English
}).ToList();
}
Query won't be executed until ToList() is called.

MVC 3 + knockoutjs: adding the data-bind attribute when using EditorFor for a boolean field

Using #Html.EditorFor(model =>model.IsClient), where IsClient is a boolean, renders a drop down list with Not Set, Yes and No as the options.
All well and good.
Now I want to use knockoutjs with the resulting dropdownlist, that I like, so how do I add the data-bind attribute using #Html.EditorFor, that I need for knockoutjs to work with this drop down?
I have tried:
#Html.EditorFor(model => model.IsClient, new Dictionary<string, object> { { "data-bind", "value: Account.IsClient" } })
However, this uses the object additionalViewData parameter, and it doesn't render the data-bind attribute. Which is probably quite natural, as this parameter is probably nothing to do with Html Attributes for the rendered tag.
However, can't find any reasonable documentation, and none of the other overloads look likely candidates for what I want.
TIA any suggestions.
Brad Wilson blogged about display and editor templates in ASP.NET MVC 2. So you could modify the default template for boolean and add the attributes you need (~/Views/Shared/EditorTemplates/MyTemplate.cshtml):
#{
bool? value = null;
if (ViewData.Model != null)
{
value = Convert.ToBoolean(ViewData.Model, System.Globalization.CultureInfo.InvariantCulture);
}
var triStateValues = new List<SelectListItem>
{
new SelectListItem
{
Text = "Not Set",
Value = String.Empty,
Selected = !value.HasValue
},
new SelectListItem
{
Text = "True",
Value = "true",
Selected = value.HasValue && value.Value
},
new SelectListItem
{
Text = "False",
Value = "false",
Selected = value.HasValue && !value.Value
},
};
}
#if (ViewData.ModelMetadata.IsNullableValueType)
{
<!-- TODO: here you can use any attributes you like -->
#Html.DropDownList(
"",
triStateValues,
new {
#class = "list-box tri-state",
data_bind="value: " + ViewData.TemplateInfo.GetFullHtmlFieldName("") // you could also use ViewData.ModelMetadata.PropertyName if you want to get only the property name and not the entire navigation hierarchy name
}
)
}
else
{
#Html.CheckBox("", value ?? false, new { #class = "check-box" })
}
and finally:
#Html.EditorFor(model => model.IsClient, "MyTemplate")
or decorate the IsClient property on your view model with the UIHint attribute:
[UIHint("MyTemplate")]
public bool? IsClient { get; set; }
and then:
#Html.EditorFor(x => x.IsClient)
will automatically pick the custom editor template.
Addendum for knockoutjs users:
#Darin Dimitrov's answer is great, but slightly too rigid to use with knockoutjs, where complex views may lead to viewModels that don't entirely map to the #Model parameter.
So I have made use of the object additionalViewData parameter. To access the additionalViewData parameter from your Custom EditorTemplate, see the following SO question:
Access additionalViewData from Custom EditorTemplate code
Digression:
The additionalViewData param is confusing in that it does nothing with the default editor. It only comes into its own with a custom editor template.
Anyway, my amendments to Darin's code are as follows:
#if (ViewData.ModelMetadata.IsNullableValueType)
{
var x = ViewData["koObservablePrefix"];
if ((x != "") && (x != null)) { x = x + "."; }
#Html.DropDownList(
"",
triStateValues,
new {
#class = "list-box tri-state",
data_bind="value: " + x + ViewData.TemplateInfo.GetFullHtmlFieldName("") // or you could also use ViewData.ModelMetadata.PropertyName if you want to get only the property name and not the entire navigation hierarchy name
}
)
}
else
{
#Html.CheckBox("", value ?? false, new { #class = "check-box" })
}
Note the lines:
var x = ViewData["koObservablePrefix"];
if ((x != "") && (x != null)) { x = x + "."; }
koObservablePrefix is there so that I can add an arbitrary prefix to my viewModel ko.observable. You could do other things if you so choose.
I use the variable x as follows:
data_bind="value: " + x + ViewData.TemplateInfo.GetFullHtmlFieldName("")
That way, if I don't pass in the additionalViewData "koObservablePrefix" it all still works.
So, now I can write:
#Html.EditorFor(model => model.IsClient, "koBoolEditorFor", new { koObservablePrefix = "Account" })
that will render as:
<select class="list-box tri-state" data-bind="value: Account.IsBank" id="IsBank" name="IsBank">
Note the "value: Account.IsBank" data-bind attribute value.
This is useful if, for example, your views strongly typed model is of type Account, but in your accountViewModel for your page, you have a more complex structure, so you need to package your observables in an account object. EG:
function account(accountId, personId, accountName, isClient, isProvider, isBank) {
this.AccountId = ko.observable(accountId);
this.PersonId = ko.observable(personId);
this.AccountName = ko.observable(accountName);
this.IsClient = ko.observable(isClient);
this.IsProvider = ko.observable(isProvider);
this.IsBank = ko.observable(isBank);
}
function accountViewModel() {
var self = this;
this.selectedCostCentre = ko.observable('');
this.Account = new account(#Model.AccountId, #Model.PersonId, '#Model.AccountName', '#Model.IsClient','#Model.IsProvider', '#Model.IsBank');
// etc. etc
}
If you don't have this kind of structure, then, the code will pick up the structure. It is just a matter of tailoring your viewModel js to this, uhmmm, flexible convention.
Hope this isn't too confusing...

Resources