I have two linq queries in my controller that are both designed to return a string. However, my view displays the entire SQL query generated from the Linq query.
Model:
public class DummyClass
{
public string myMessage { get; set; }
public string myInitials { get; set; }
}
Controller:
public ActionResult EmployeeSignature()
{
using (MessageInfo db = new MessageInfo())
{
var message = db.SiteMessage_MyPay
.Where(x => x.active)
.Select(x => x.msgText).ToString();
using (DocumentReviewed database = new DocumentReviewed())
{
var document = database.Document_Reviewed
.Where(x => x.FileNumber == "whatever")
.Select(x => x.Initials).ToString();
var model = new DummyClass()
{
myMessage = message,
myInitials = document
};
return View(model);
}
}
}
View:
#model MyPayTC.Models.DummyClass
#{
ViewBag.Title = "EmployeeSignature";
}
#Model.myInitials
#Model.myMessage
Website displays:
SELECT [Extent1].[Initials] AS [Initials]
FROM [dbo].[Document_Reviewed] AS [Extent1]
WHERE '105057' = [Extent1].[FileNumber]
Instead of using .ToString( ), you should use .FirstOrDefault(), ToList(), etc like this:
var message = db.SiteMessage_MyPay
.Where(x => x.active)
.Select(x => x.msgText).FirstOrDefault();
Or, if you want to retrieve some columns, you can use ToArray() or ToList().
Related
I have an entity like this:
public class Event
{
public string Code;
public DateTimeOffset DateTime;
}
I want to filter by Code and then group by DateTime.Date. I tried this:
var results = session
.Query<Event>()
.Where(e => e.Code == "123")
.GroupBy(e => e.DateTime.Date)
.ToList();
But I get the following error:
Raven.Client.Exceptions.InvalidQueryException: Field 'Code' isn't neither an aggregation operation nor part of the group by key
Query: from Events group by DateTime.Date where Code = $p0
Parameters: {"p0":"123"}
It can be seen from the resulting query that the where clause is being added after the group by clause, which explains the error.
So how do I perform this query in RavenDB?
EDIT:
The code "123" that I used was just an example. I need it to be a variable that is passed to the query, like this:
var results = session
.Query<Event>()
.Where(e => e.Code == code)
.GroupBy(e => e.DateTime.Date)
.ToList();
To start with, learn about the dynamic aggregation query syntax in:
https://demo.ravendb.net/demos/auto-indexes/auto-map-reduce-index
But, in your case you need to define a Static Map-Reduce Index to calculate this for you:(Sum up the number of (filtered) documents per unique Date)
i.e.
public class Result
{
public string Date { get; set; }
public int NumberOfDocs { get; set; }
}
Map = events => from event in events
where event.Code == "123"
select new Result
{
Date = event.DateTime.Date
NumberOfDocs = 1
}
Reduce = results => from result in results
group result by result.Date into g
select new Result
{
Date = g.Key,
Count = g.Sum(x => x.NumberOfDocs )
}
==> Learn about Static Map-Reduce Index in:
https://demo.ravendb.net/demos/static-indexes/map-reduce-index
Follow the detailed Walkthrough..
----------
Update:
You can use the following map-reduce index that aggregates the number of documents per Code & Date 'couple', and then you can query with 'Code'
public class Result
{
public string Code { get; set; }
public string Date { get; set; }
public int NumberOfDocs { get; set; }
}
Map = events => from event in events
select new Result
{
Code = event.Code
Date = event.DateTime.Date
NumberOfDocs = 1
}
Reduce = results => from result in results
group result by new
{
result.Code,
result.Date
}
into g
select new Result
{
Code = g.Key.Code
Date = g.Key.DateTime.Date,
NumberOfDocs = g.Sum(x => x.NumberOfDocs )
}
and then query
List<Result> queryResults = session.Query< Result, <Index_Name> >()
.Where(x => x.Code == "some-code-number")
.ToList();
and then you can also do in your code
queryResults.GroupBy(x => x.Date)
I have an entity framework generated class like this.
public partial class TBLM_PRODUCT
{
public string PRODUCT_CODE { get; set; }
public string PRODUCT_DESC { get; set; }
public string PRODUCT_ISBN { get; set; }
public string PRODUCT_SUPPLIER { get; set; }
public string PRODUCT_PROGROUP { get; set; }
}
Normally I select items list like this using a LINQ query.
using ( AEntities RAEntity = new AEntities())
{
RAEntity.TBLM_PRODUCT.ToList<DataControllers.TBLM_PRODUCT>();
}
I want to select an item list with two fields like this like as in following query
select PRODUCT_CODE,PRODUCT_DESC from TBLM_PRODUCT where PRODUCT_PROGROUP='GG';
How can I achieve that?
using ( AEntities RAEntity = new AEntities())
{
var all = RAEntity.TBLM_PRODUCT.ToList<DataControllers.TBLM_PRODUCT>();
var yourList = all
.Where(x => x.PRODUCT_PROGROUP == "GG")
.Select(p => new { p.PRODUCT_CODE, p.PRODUCT_DESC })
.ToList();
}
Don't select all records first and then filtered your data.
If you use .ToList<DataControllers.TBLM_PRODUCT>() then it can select all records. So instead of this you can select your columns at the time of query fired to database.
If your TBLM_PRODUCT is of any collection type like IEnumerable<> or IQueryable<> then,
using ( AEntities RAEntity = new AEntities())
{
var result = RAEntity.TBLM_PRODUCT.Where(x => x.PRODUCT_PROGROUP == "GG").Select(x => new { x.PRODUCT_CODE, x.PRODUCT_DESC }).ToList();
}
using (AEntities RAEntity = new AEntities())
{
var list= RAEntity.TBLM_PRODUCT
.Where(p => p.PRODUCT_PROGROUP == "GG")
.Select(p => new TBLM_PRODUCT { PRODUCT_CODE = p.PRODUCT_CODE, PRODUCT_DESC = p.PRODUCT_DESC })
.ToList();
}
My model:
public class StatusDetailsViewModel
{
public string Status { get; set; }
public long CountNo { get; set; }
}
And my function to get the data:
public List<StatusDetailsViewModel> CheckMeetingStatus(long actionId)
{
List<StatusDetailsViewModel> statusDetails;
var statuses = _igniteDb.myTable.Where(a => a.actionId == actionId)
.GroupBy(a => new { a.Status, a.ElectionGroup }).GroupBy(c => new { c.Key.Status})
.Select(b => new { Status = b.Key.Status, CountNo = b.Count()}).ToList();
//How to Map statuses to statusDetails??
return statusDetails;
}
I've being trying to use auto mapper to achieve this. But I am not sure how to configure my mapper. Any ideas?
Why do you have to map at in your code. Instead of creating anonymous type, you can create the object of StatusDetailsViewModel. Change the select statement as Select(b => new StatusDetailsViewModel() { Status = b.Key.Status, CountNo = b.Count()}
If you want to use AutoMapper then you should define the source and target types while defining the Map/profile. You can not map the anonymous type with AutoMapper.
Your code to create the object of StatusDetailsViewModel (without using Automapper as you don't require for the code you have asked for)
public List<StatusDetailsViewModel> CheckMeetingStatus(long actionId)
{
List<StatusDetailsViewModel> statusDetails;
var statuses = _igniteDb.myTable.Where(a => a.actionId == actionId)
.GroupBy(a => new { a.Status, a.ElectionGroup }).GroupBy(c => new { c.Key.Status})
.Select(b => new StatusDetailsViewModel () { Status = b.Key.Status, CountNo = b.Count()}).ToList();
//How to Map statuses to statusDetails??
return statusDetails;
}
Just because you're returning a List<StatusDetailsViewModel>, you don't need AutoMapper here just project your data by using directly your view model like below:
List<StatusDetailsViewModel> statusDetails = _igniteDb.myTable.Where(a => a.actionId == actionId)
.GroupBy(a => new { a.Status, a.ElectionGroup })
.GroupBy(c => new { c.Key.Status})
.Select(b => new StatusDetailsViewModel { /* <--- Here you instantiate your view model */
Status = b.Key.Status,
CountNo = b.Count()}
).ToList();
I have used a lot of SQL in the past but am new to LINQ. I have the following query which selects the otherID from the relevant table successfully, however when I try to select multiple columns I am unable to do so.
This is my following query:
var getQ = db.Requests.Where(x => temp.Contains(x.carID)).Select(x => x.otherID).ToList();
I have tried
var getQ = db.Requests.Where(x => temp.Contains(x.carID)).Select(x => x.otherID && x.dayID).ToList();
I am unable to get it to work, any help appreciated, thanks
You can use anonymous type to return multiple columns
var getQ = db.Requests.Where(x => temp.Contains(x.carID))
.Select(x => new { OtherID = x.otherID, DayID = x.dayID).ToList();
You can make a custom class, as the anonymous type could not be returned from method.
class YourClass
{
public int OtherID { get; set; }
public int DayID { get; set; }
}
var getQ = db.Requests.Where(x => temp.Contains(x.carID))
.Select(x => new YourClass { OtherID = x.otherID, DayID = x.dayID).ToList();
make the change is the select statement:
var getQ = db.Requests.Where(x => temp.Contains(x.carID)).Select(x => new{x.otherID, x.dayID}).ToList();
I obtain a list of data through docs which has a list of every single department and function the currently logged in user has access to. I need to populate a distinct list of Departments for a DropDownList and a distinct list of Functions for a DropDownList on the View page. I am currently not even using docs to do this but a different LINQ query to acheive this. Is there a way I can use the current model I am passing?
var docs = (Long LINQ query that joins in four different tables and returns a model)
ViewBag.DepartmentList = db.Department.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Department's from the table.
ViewBag.FunctionList = db.Function.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Function's from the table.
Code on View: (Strongly Typed Model)
#model IEnumerable<DB.Models.MasterList>
#Html.DropDownList("DepartmentList", "Select a Department")
#Html.DropDownList("FunctionList", "Select a Function")
Define a model that will be used in your view.
public class MyViewModel
{
public string SelectedDepartment { get; set; }
public string SelectedFunction { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
public IEnumerable<SelectListItem> Functions { get; set; }
// Your old model
public IEnumerable<MasterList> Master { get; set;}
}
In your controller, populate these collections and return your model to view.
[HttpGet]
public ActionResult ActionMethodName()
{
var model = new MyViewModel();
model.Departments = db.Departments.Where(x => (x.name != null))
.Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct();
model.Functions = db.Functions.Where(x => (x.name != null))
.Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct();
return View(model);
}
Inside your view, use strongly typed html helpers.
#model MyViewModel
#Html.DropDownListFor(m => m.SelectedDepartment, Model.Departments)
#Html.DropDownListFor(m => m.SelectedFunction, Model.Functions)
When you post back your form to server, SelectedDepartment and SelectedFunction should have the values selected in your view.
You could create a ViewModel and put all this data in this ViewModel:
ViewModel
public class MyViewModel{
public object DepartmentList{get; set;}
public object FunctionList{get; set;}
public IEnumerable<MasterList> Master {get; set;}
}
Controller
var docs = (Long LINQ query that joins in four different tables and returns a model)
MyViewModel vm = new MyViewModel();
vm.Master = docs; // I guess docs is a list of Masterlist
vm.DepartmentList = db.Department.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Department's from the table.
vm.FunctionList = db.Function.Where(x => (x.name != null)).Select(s => new SelectListItem
{
Value = s.name,
Text = s.name
})
.Distinct(); // Fill the viewbag with a unique list of 'Function's from the table.
return View(vm);
View
#model MyViewModel
#Html.DropDownList("DepartmentList", "Select a Department")
#Html.DropDownList("FunctionList", "Select a Function")
You can always create a ViewModel class for your view and put all the necessary view information in it.
You can use a framework like AutoMapper (https://github.com/AutoMapper/AutoMapper) to help you with the mapping between your database model and your view model (I belive it's best that the view won't know the database model at all), and beside the model information you can also add those lists (That's what I do, I have a property for the entity, and properties for those kinds of lists).
If you need this information in many of your views you can always create a BaseViewModel and polpulate that information in a BaseController.