Pass linq query result to viewmodel - c#

In my MVC web application, I have linq query that feth the record from database, I want to display that record on view using viewmodel. I have tried with following code.
[HttpGet]
public ActionResult CreatePDF()
{
RentalAgreementEntities db = new RentalAgreementEntities();
String strSession1 = "39726-10275-6027589725",strStatus = "Y",strUserType = "L";
var q = (from um in db.User_Master
join ut in db.UserType_Master on um.US_SerialNo.ToString() equals ut.UT_UserNo
join pu in db.PropertyUser_Master on ut.UT_SerialNo.ToString() equals pu.PU_UserNo
join pr in db.Property_Master on pu.PU_PropertyNo equals pr.PR_SerialNo.ToString()
where pr.PR_MakerID == strSession1
&& ut.UT_Status == strStatus
&& ut.UT_UserType == strUserType
select new
{
um.US_FirstName,
um.US_LastName
}
).AsEnumerable().Select(um => new User_Master {
US_FirstName = um.US_FirstName.ToString(),
US_LastName=um.US_LastName
}).ToList();
var myviewmodel=new viewmodelPDF()
{
lsusermaster=q.ToList();
}
return View("pdfgenerationvw",myviewmodel);
}
I also created viemodel to manage all model's for to display on a view (Here, Just one model access code).
public class viewmodelPDF
{
public List<User_Master> lsusermaster { get; set; }
}
My model class, for which I am going to fetch record from database.
public partial class User_Master
{
public string US_FirstName { get; set; }
public string US_LastName { get; set; }
public int US_SerialNo { get; set; }
}
//Other Models
Now my problem is that, In my action code , when I am trying to assign query result to the lsusermaster of viewmodel then it gives compiler error as belows.
I don't know, why this compile error is thrown, How can I assign query result to viemodel property?

Try this:
var myviewmodel=new viewmodelPDF()
{
lsusermaster=q.ToList()
};

When you are using an object initializer in C#, you can't use ; between the properties, you use it at the end of the initializer
So just remove the ; (or use a ,, as suggested), and move it to the end of the initializer block
var myviewmodel=new viewmodelPDF()
{
lsusermaster=q.ToList()
};
Using a , works even if there are no more properties... it "looks" bad, but it makes easier to add new properties should you ever need them... if the code is final, I'd not use it, but that's personal preference

Related

Returning neo4j results to a C# object

I have a query that returns a list of object with properties. Consider a C# object with like this structure:
public class Neo4jResult {
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
The query returns a column called "mycollection" and I can store the results to something like this:
public async Task<IEnumerable<Neo4jResult>> MyNeo4jQuery() {
var cypher = client.Cypher
.Match(matchQuery)
.WithParams(myParams);
cypher =
cypher.ReturnDistinct<Neo4jResult>("mycollection")
.OrderBy("toLower(object.Prop1)");
var query = (IOrderedCypherFluentQuery<Neo4jResult>)cypher;
return await query.ResultsAsync;
}
This code works well. However, I had to get the count of this record as another property so my query now returns two columns - "mycollection", and "totalRecords". To facilitate this, I created a new object that reflects this:
public class Neo4jResultNew {
public int TotalRecords { get; set; }
public IEnumerable<Neo4jResult> Results { get; set; }
}
I have then changed my neo4j query to something like:
public async Task<IEnumerable<Neo4jResult>> MyComplexNeo4jQuery() {
var cypher = client.Cypher
.Match(matchQuery)
.WithParams(myParams);
cypher =
cypher.Return<Neo4jResultNew>( (mycollection, totalRecords) => {
{
Results = mycollection.As<IEnumerable<Neo4jResult>>(),
TotalRecords = totalRecords.As<int>()
});
var query = (IOrderedCypherFluentQuery<Neo4jResultNew>)cypher;
return await query.ResultsAsync;
}
The error returned by neo4j is: "Neo4j returned a valid response, however Neo4jClient was unable to deserialize into the object structure you supplied". I just followed the examples online but there's something missing in my projection maybe?
I think the problem is your:
Results = mycollection.As<IEnumerable<Neo4jResult>>(),
Bit. What you're actually wanting is a COLLECT so something like:
Results = mycollection.CollectAs<Neo4jResult>()
mycollection isn't actually an IEnumerable - and you can see it if you run the query in the browser - you don't put it here, so this is a 'rough' version.
If you executed:
MATCH (m:Movie)
RETURN m.title, count(m)
You'll get:
Title1, 1
Title2, 1
Title3, 1
etc
If you execute:
MATCH (m:Movie)
RETURN COLLECT(m.title), count(m)
You'll get:
[title1, title2, title3], 3
for example.

Convert EF6 to EF core with the ObjectResult

I have some code I am trying to convert. I don't have these ObjectResult and ObjectContext anymore
This is what I did have:
public virtual ObjectResult<string> GetTransData(string iN_MEM_ID)
{
var iN_MEM_IDParameter = iN_MEM_ID != null ?
new ObjectParameter("IN_MEM_ID", iN_MEM_ID) :
new ObjectParameter("IN_MEM_ID", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<string>("GetTransData", iN_MEM_IDParameter);
}
Since I need a List to be returned from a caller ( it is sent back as json data )
This is what I am trying to build
public virtual List<string> GetTransData(string iN_MEM_ID)
{
var iN_MEM_IDParameter = iN_MEM_ID != null ?
new SqlParameter("IN_MEM_ID", iN_MEM_ID) :
new SqlParameter("IN_MEM_ID", typeof(string));
Clinical_CaseTrakker_Context clinical = new Clinical_CaseTrakker_Context();
List<string> offLine = clinical.string.FromSql("EXECUTE CT.GetTransData {0}", iN_MEM_IDParameter);
return offLine;
}
Notice that I am stuck with clinical.string i can't do that , but I am not sure how to take dbcontext instance and run FromSql to execute sql and return to List
In EF Core, it is not possible to use the FromSql method to return a subset of properties (a projection) directly from the database.
You are required to define a some model and a DbSet for that class
public class Foo
{
public string Bar { get; set; }
}
then declare in your context
public DbSet<Foo> Foos { get; set; }
and use it like:
using (var context = new Clinical_CaseTrakker_Context())
{
var offLine = context.Foos
.FromSql($"EXECUTE CT.GetTransData {iN_MEM_IDParameter}")
.Select(x => x.Bar)
.ToList();
return offLine;
}
Your Context needs a virtual DbSet<string> ResultStrings { get; set; } that you can call upon and put the result in. (This does not work, see this post or Roman Marusyk comment below)
EDIT: Your Context needs a virtual DbSet<ResultEntity> ResultEntities { get; set; } that you can call upon and put the result in.
Then you can do return clinical.ResultEntities.FromSql("EXECUTE CT.GetTransData {0}", iN_MEM_IDParameter").toList() to fill the set.
Considering the ResultEntity has an Id and a value property, you can do ResultEntities.Select(e => e.value).toList() to extract a list of strings from the set.

Missing a cast in a linq query for a controller

I am new with c# controllers and I am trying to join two entities with a LINQ query. But I am getting a 'missing a cast' error message as shown below that I don't understand and it does not help me to correct the error.
The controller looks like:
public class SoonDueReportsController_simple : BaseODataController
{
public SoonDueReportsController_simple(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public SoonDueReportsController_simple Get()
{
var falligkeiten = UnitOfWork.GetAll<Fälligkeiten>();
var betriebe = UnitOfWork.GetAll<Betriebe>();
var query = (from betrieb in betriebe.AsQueryable()
join fallig in falligkeiten.AsQueryable()
on betrieb.ID equals
fallig.Betrieb_ID
where fallig.Fälligkeit_Erledigt_Datum == null
&& betrieb.Aktiv == true
select new
{
BetriebId = betrieb.ID,
FalligkeitObject = fallig.Fälligkeit_Objekt
});
return query;
}
}
This type of controller I have used with success for single entities (tables from an sql db) to display static data in a kendo grid. But I fail when I try to join two tables as shown above. If someone could help me with this problem I'd appreciate it very much.
Regards, Manu
You select a collection of anonymous objects
select new
{
BetriebId = betrieb.ID,
FalligkeitObject = fallig.Fälligkeit_Objekt
});
And want the method to return a instance of certain type. C# is the strongly typed language without type inference, which means you have to specifically create objects of a certain type or interface if you want to return them.
Also, you are have the controller type itself to be returned from the Get method. This makes no sense. I actually do not know what you want to do but may be this would work:
public class SoonDueReportsController_simple : BaseODataController
{
public SoonDueReportsController_simple(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<SomeModel> Get()
{
var falligkeiten = UnitOfWork.GetAll<Fälligkeiten>();
var betriebe = UnitOfWork.GetAll<Betriebe>();
var query = (from betrieb in betriebe.AsQueryable()
join fallig in falligkeiten.AsQueryable()
on betrieb.ID equals
fallig.Betrieb_ID
where fallig.Fälligkeit_Erledigt_Datum == null
&& betrieb.Aktiv == true
select new SomeModel
{
BetriebId = betrieb.ID,
FalligkeitObject = fallig.Fälligkeit_Objekt
});
return query;
}
}
public class SomeModel
{
public int BetriebId { get; set; }
public string FalligkeitObject { get; set; }
}
Please bear in mind that there are no such things as "C# controllers". You are working with OData, so I would recommend you to look at some OData resources, there are plenty of examples out there.
And one last thing, don't get me wrong, but it does not help giving properties, types and other identifiers German names. People would have hard time trying to understand your code.
The exception explains to you the problem exactly. You're wanting to return a type of 'SoonDueReportsController_simple' and yet you are returning a Queryable where a' is your new { ..., ... } object.
I like the suggestion given to make a strong typed object and fill it but you can also return a dynamic type.
This code works to explain:
private dynamic Get() => new { Name = "SomeName", Age = 31 };
private void TestGet()
{
var obj = Get();
var name = obj.Name;
var age = obj.Age;
}

MVC model properties returning default value

Something weird is happening and I am not able to understand why.. here's the scenario -
I have a model with few properties when I populate the model the properties in model does have values set (checked by putting breakpoints). It comes on the view also but it is not being shown on textbox. It is showing the default value (guessing by seeing the item textbox on the page as it has 0).
Below is my model -
public class PriceEnquiryModel
{
[DisplayName("Item")]
public int item { get; set; }
[DisplayName("Description")]
public string description { get; set; }
[DisplayName("UOP")]
public string uop { get; set; }
[DisplayName("UOS")]
public string uos { get; set; }
[DisplayName("Pack Description")]
public string pack_description { get; set; }
[DisplayName("Pack Size")]
public string PackSize { get; set; }
}
This is the controller;s code -
public ActionResult Search(PriceEnquiryModel price)
{
var priceEnquiryModel = new PriceEnquiryModel();
// Read parameter values from form.
int item = Convert.ToInt32(Request.Form["txtSearch"].ToString());
int maxrow = Convert.ToInt32(Request.Form["txtmaxrow"].ToString());
string priceType = !string.IsNullOrWhiteSpace(price.priceType) && price.priceType.ToUpper().Equals("STA") ? "N" : "Y";
// Get the price information
var operationResult = priceBal.SearchPriceEnquiry(0, item, price.price_scheme, priceType, maxrow);
var priceEnquiryDomList = (List<PriceEnquiryDom>)operationResult[0].Result;
// Check if we have something
if (priceEnquiryDomList != null && priceEnquiryDomList.Count > 0)
{
// Parse the model.
priceEnquiryModel = helper.ConvertDomToModel(priceEnquiryDomList[0]);
// Prepare the list.
priceEnquiryModel.PriceEnquiryModelList = new List<PriceEnquiryModel>();
foreach (var priceEnquiryDom in priceEnquiryDomList)
{
var priceEnquiryModelListItem = helper.ConvertDomToModel(priceEnquiryDom);
priceEnquiryModel.PriceEnquiryModelList.Add(priceEnquiryModelListItem);
}
Session["mainModel"] = priceEnquiryModel;
}
// Prepare product drop down list items if searched by product desc
if (TempData.Count > 0 && TempData["Products"] != null)
{
var products = TempData["Products"] as List<ProductSearchByDescModel>;
ViewBag.Products = products;
}
return View("Index", priceEnquiryModel);
}
This is the model on the View (while debugging) -
This is how I am rendering the model on the view -
This is the page after running -
Does anyone has any idea what is going on ? I have done the same thing on multiple pages and all run as expected.
Thanks in Advance.
Rohit
The issue is that your method has parameter PriceEnquiryModel price but then you return a new instance of PriceEnquiryModel (named priceEnquiryModel). The process of model binding includes binding your model and adding its values to ModelState (along with any validation errors).
When you return the view, the html helper methods use the values from ModelState (not the models values) so attempting to change the values (which I assume is what priceEnquiryModel = helper.ConvertDomToModel(priceEnquiryDomList[0]); is doing) is ignored by the helpers.
For an explanation of why this is the default behavior, refer the second part of this answer
One option to call ModelState.Clear() before setting new values for the properties of PriceEnquiryModel

Why my Generic List is always null?

I have class like this:
public class Lugar
{
[Key]
public int LugarId { get; set; }
public List<Review> Reviews { get; set; }
public int SumReviews { get; set; }
public double AverageReviews { get {
if (Reviews == null)
return 0;
else if (Reviews.Count == 0)
return 0;
else
return (double)SumReviews/(Reviews.Count); } }
}
And in my controller I have this:
[HttpPost, Authorize]
public ActionResult WriteReview(int id, FormCollection formCollection)
{
Lugar lugar = db.Lugares.Find(id);
Review review=new Review();
review.User = User.Identity.Name;
review.Rating=Convert.ToInt32(formCollection["Rating"]);
review.Texto = formCollection["Review"];
if (lugar != null)
{
if( lugar.Reviews==null)
lugar.Reviews=new List<Review>();
lugar.Reviews.Add(review);
lugar.SumReviews += review.Rating;
db.SaveChanges();
}
else
return RedirectToAction("Index");
return RedirectToAction("Index");
}
}
The problem is in the line:
if( lugar.Reviews==null)
lugar.Reviews=new List();
Everytime I execute I am getting ( lugar.Reviews==null) as true.....
Even if I already added a Review for that place, the if statement returns true.....
Try using the 'virtual' keyword where you declare your List and see if you have any more luck.
You might want to introduce a constructor in your Lugar class and instantiate the list there.
Something like this:
public void Lugar()
{
Reviews = new List<Review>();
}
Hope this helps. of not please let me know.
P.S. another thing that is not related to your specific question, but certainly an improvement is to use view model rather than FormCollection.
It will simplify your life in a major way. For example of how to use it please take a look at this successfully answered question: What is ViewModel in MVC?
You have 2 options here, lazy loading (which is enabled by putting virtual on navigation properties) This will pull down your second entitiy when you access the property in C#
or eager loading by using a .Include(/*lambda or string property name*/) statement in your query.
Personally i perfer eager loading as you have more control over when entities are loaded

Categories