convert Data between ActionResult and View - c#

In my project i use kendo grid to show data and in my ActionResult i use this code to get data :
public ActionResult ShowData([DataSourceRequest] DataSourceRequest request, long studentid)
{
IQueryable<Models.Registration.RegistrationModel>
query =
from financeItem in db.RegistrationItems
select new Models.Registration.RegistrationModel
{
RegisterId = financeItem.RegistrationId,
Id = financeItem.Registration.Id,
Date = financeItem.Registration.Date,
StudentName = financeItem.Registration.Student.FirstName + " " + financeItem.Registration.Student.LastName
};
DataSourceResult dsr = query.ToDataSourceResult(request);
return Json(dsr, JsonRequestBehavior.AllowGet);
}
so . I need convert date to local date and I have a problem.
this is my problem :
when I want convert date inside query I get many error that linq2sql can't find converter function. so I change query type from IQueryable to list and try convert . but I get time out error because I've got a lot of records.
after this error I try convert data inside get and set property in viewmodel like this code :
public string DateSs
{
get
{
return DateConvertor(Date.ToString());
}
set { value.ToString(); }
}
and I use this property inside view and show converted data.
Everything works fine so far but when I want use filter part in kendo grid and filter data base on input date I get and error that this filed not exited in query.
so I have a Headache and I don't know what must I do and how can I convert this dame date

For Kendo Grid your Date column is representation for DateSs instead of Date. When it tries to apply filter on Date, it is applying filter on DateSs which doesn't exist in database table and throws error if defined in your query.
I think the solution for that would be to intercept the DataSourceRequest before applying ToDataSourceResult and change the value and filter name accordingly
UPDATE
The filter Kendo Grid sent is in request.Filters but the structure is hierarchical to support multiple Filters in one request. So, first of all you might want to flatten the filter out, you can use this code to that,
public static IEnumerable<IFilterDescriptor> FlattenFilters(this DataSourceRequest request)
{
return request.Filters
.RecursiveSelect(
descriptor => (descriptor as CompositeFilterDescriptor)?.FilterDescriptors ?? Enumerable.Empty<IFilterDescriptor>(),
descriptor => descriptor as FilterDescriptor)
.Where(x => x != null);
}
This function will return an Enumerable of all the filters currently applied. Then you can change the name of filter like this
request.FlattenFilters().Each(x =>
{
FilterDescriptor filter = x as FilterDescriptor;
if (filter != null && filter.Member == "DateSs")
{
filter.Member = "Date";
//Change the filter.Value property according to your case
//i.e. It would be in String and you might want to convert it to date too.
}
});

Related

C# Notmapped field not "Set" when value is null

We have a notmapped conversion field with a kendo control bound to it. When we delete all entries from the control, it posts a null to the controller.
The created model is not running the setter for that field, according to the breakpoints I set in it.
Here's the two fields in question:
[NotMapped]
[Display(Name="Execute Time(s)")]
[DCRequired]
public IList<int> ExecuteTimes {
get
{
return ExecuteHourUTC?.Split(',').Select(s => GetUtcHour(s)).ToList();
}
set
{
if (value != null)
{
// Special code here to ensure the times are numerically in order by local time
// and saved that way for viewing on next load or in the grid.
var values = value.ToList() // convert to List to be sortable/linqable
.OrderBy(x => x) // sort numerically so they are stored in chronological order
.Select(x => new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, x, 0, 0)) // use the integer value to create a DateTime
.Select(d => Core.DateHelper.ToUTC(d, UserTimeZone).Hour); // convert the generated DateTime into a UTC DateTime and return the Hour value
ExecuteHourUTC = string.Join(",", values); // join these Hour (int) values as a CSV
}
}
}
[Display(Name="Execute Times")]
public string ExecuteHourUTC { get; set; }
execute hour utc is bound to the database.
Note: I fixed the problem this was causing (it was leaving the old values in the db field) by bind excluding the db field from the post. I just want to know what the actual reason I'm having this issue is.
I also tried changing the datatype to iList<int?>. That didn't help.

How to store a Linq query and use it later?

I'm doing a wpf App and i've got a bit of an issue i would like to ask you about.
I'm querying a database on the window level and i pass the result of the query to a method in my object like this :
Window level code :
payrollEmailManager.SetListOfSalariesToEmailTo(
from Record in SqlInfo.SqlTable.T_SALs
where Record.EtatPaie == 3
select new {
Matricule = Record.MatriculeSalarie,
Nom = Record.Nom,
Prenom = Record.Prenom,
Email = Record.EMail });
This is my Method Definition :
public void SetListOfSalariesToEmailTo(object _ListOfSalaryToRecieveMail)
{
ListOfSalary = _ListOfSalaryToRecieveMail;
}
Where ListOfSalary is also of type object.
Now here is the issue for me, I have another method where I want to go trough each record of listofsalary and get the information I selected in query like Matricule or Email, something like this :
public void SendEmail()
{
foreach(var Salary in (dynamic)ListOfSalary)
{
Mail.To.Add(Salary.????
}
}
I can't reference the Nom column or the Email column any advice ??
If you consider your following query:
var query = from Record in SqlInfo.SqlTable.T_SALs
where Record.EtatPaie == 3
select new {
Matricule = Record.MatriculeSalarie,
Nom = Record.Nom,
Prenom = Record.Prenom,
Email = Record.EMail
};
After running this line the query is not yet executed to database. Only when you materialize it (using functions like ToList()/ToArray()/FirstOrDefault etc.) it is actually being executed in the database and information is returned.
Therefore if you just do SomeFunction(query); it does not execute the query and you can store it for later execution.
However you do need to change your code a bit:
The function should not get object but IQueryable<T>
public void SetListOfSalariesToEmailTo(IQueryable<T> query)
As you want to store the query you need to later on know the type of each item. To do so do not use an anonymous object (new { }) in the select. Use instead a custom object or use c# 7.0 named tuples and then the function will look like:
var query = from Record in SqlInfo.SqlTable.T_SALs
where Record.EtatPaie == 3
select new SomeType {
Matricule = Record.MatriculeSalarie,
Nom = Record.Nom,
Prenom = Record.Prenom,
Email = Record.EMail
};
public void SetListOfSalariesToEmailTo(IQueryable<SomeType> query)
{
ListOfSalary = query;
}
You can still use object and dynamic as you did, and just access the properties, but you will not have the intellisense showing you the properties and options, as it does not know the concrete type.

Why does adding a Selected value to my SelectList cause a model change / migration error?

The following code runs perfectly for creating a SelectList of my Categories.
var categoryList = _context.Category.Select(f => new SelectListItem
{
Value = f.ID.ToString(),
Text = f.CategoryName
});
Now I wanted to default the SelectList with the current category when editing an item.
var categoryList = _context.Category.Select(f => new SelectListItem
{
Value = f.ID.ToString(),
Text = f.CategoryName,
Selected = (f.ID == itemModel.category.ID) // <- added this line
});
But I get this error:
If I just shortcut it for testing purposes like this: Selected = (true) the code runs again without error.
Why would adding the bool check f.ID == itemModel.category.ID cause a model change? Both left and right hand values are int. How can I fix this?
P.S. Just for grins I tried adding a migration and I still get the same error.
LINQ-to-SQL always tries to build a SQL query from your clauses, statements and conditions, and then it runs that query. But in this case it can't convert your code to SQL, because the code refers to an object not available in that context.
Solution:
Replace _context.Category.Select(...) with _context.Category.ToList().Select(...).
The condtions are now evaluated on the List of objects, instead of on the database.
It is because EF is unable to translate that expression in SQL.
The simplest way is to create a SelectList using its constructor overload like:
var categoryList = new SelectList(_context.Category.ToList(),
"ID", // data value field
"CategoryName", // data text field
itemModel.category.ID // selected value
);

MVC4 - Linq Lambda expression to query multiple association tables

Am trying to create a cascading drop down and have been following this tutorial here
My database is more complex than the one in the tutorial and I need help with creating a lambda expression
Here are my database tables
The cascading drop down I want to create, will allow a user to select a
RiskType and then depending on the selection will display the associated GroupMembers for the selected RiskType.
Here is the code I have in my controller
public ActionResult AddNewRisk()
{
ViewBag.RiskTypeID = new SelectList(_DBContext.RiskTypes, "ID", "Description");
ViewBag.GroupMembers = new SelectList(new List<GroupMember>(), "ID", "Name");
return View();
}
public IList<GroupMember> GetGroupMember(int SelectedRiskTypeID)
{
return _DBContext
.RiskTypeHasGroups
}
public JsonResult GetJsonGroupMember(int ID)
{
var GroupMemberListT = this.GetGroupMember(Convert.ToInt32(ID));
var GroupMemberList = GroupMemberListT.Select(x => new SelectListItem()
{
Text = x.Name,
Value = x.ID.ToString()
});
return Json(GroupMemberList, JsonRequestBehavior.AllowGet);
}
It's in the method named GetGroupMember that am having trouble and don't know how to write the correct lambda expression in order to pull back only the group members which have a matching RiskGroup.ID followed by a matching RiskType.ID. If anyone could show me the correct way to do this, I'd really appreciate it.
Thanks in advance.
Once the model is simplified as I suggested, then your query becomes:
public IQueryable<GroupMember> GetGroupMember(int SelectedRiskTypeID)
{
return _DBContext.GroupMembers
.Where(g=>g.RiskGroups.Any(rg=>rg.ID=SelectedRiskTypeID));
}
If you decide to keep the IDs, then this would be your query:
public IQueryable<GroupMember> GetGroupMember(int SelectedRiskTypeID)
{
return _DBContext.GroupMembers
.Where(gm=>gm.RiskGroupHasGroupTypes
.Any(rghgt=>rghg‌​t.RiskGroup.ID==SelectedRiskGroupTypeID))
}

ORDER BY sort key(s) type must be order-comparable

Hope someone may be able to help. Trying to implement a jqGrid in ASP.NET MVC 4 C#. I keep getting the following error when trying to sort a column. This column is actually a field from an object using the foreign key. Not sure how the code should be changed to account for this. The grid sorts correctly for the fields that are in the model that I'm using, just not the field that is from the foreign key. Should I be using a ViewModel instead? I'm using the code from Oleg's examples. item.Name is the object and item.Name.FullName is the column I'm trying to sort that is throwing the error below. Thanks!
The ORDER BY sort key(s) type must be order-comparable. Near member access expression, line 6, column 3.
public JsonResult DynamicGridData(string sidx, string sord, int page, int rows, bool search, string filters)
{
var context = new TeamContext();
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
var set = objectContext.CreateObjectSet<Team>();
var serializer = new JavaScriptSerializer();
Filters f = (!search || string.IsNullOrEmpty(filters)) ? null : serializer.Deserialize<Filters>(filters);
ObjectQuery<Team> filteredQuery =
(f == null ? (ObjectQuery<Team>)set : f.FilterObjectSet((ObjectQuery<Team>)set));
filteredQuery.MergeOption = MergeOption.NoTracking; // we don't want to update the data
var totalRecords = filteredQuery.Count();
var pagedQuery = filteredQuery.Skip("it." + sidx + " " + sord, "#skip",
new ObjectParameter("skip", (page - 1) * rows))
.Top("#limit", new ObjectParameter("limit", rows));
// to be able to use ToString() below which does NOT exist in the LINQ to Entity
var queryDetails = (from item in pagedQuery
select new { item.TeamId, item.Year, item.Name }).ToList();
return Json(new
{
total = (totalRecords + rows - 1) / rows,
page,
records = totalRecords,
rows = (from item in queryDetails
select new[] {
item.TeamId.ToString(),
item.Year,
item.Name.FullName
}).ToList()
});
}
This can fail for various reasons:
item.Name.FullName is a binary field in the database?
to access to the Name object through item, lazy loading has to be enabled. are you sure it is?
Anyway using a viewmodel with only data that you need is always a good idea, and is a good way to separate your data Access layer from your controller.

Categories

Resources