How to call object from Controller to display in the View of ASP.net MVC - asp.net-mvc-2

I have one action in my controller :
public ActionResult GiftVochure()
{
if (Request.QueryString["gc"] != "")
{
var obj = from b in context.GiftCards
join cus in context.Customers on b.CustomerID equals cus.ID
where b.ID == int.Parse(Request.QueryString["gc"])
select new
{
b.ID,
b.Date,
b.CardNo,
b.Price,
CustomerName = cus.FirstName + " " + cus.LastName
};
return View(obj.ToList());
}
return View();
}
And I want to take "obj" to loop and display in the GiftVochure Views, Does any one know, how to do this?
Thanks.

You should start by defining a model type to replace the anonymous type projected by the query.
public class CardInfo
{
int ID { get; set; }
DateTime Date { get; set; }
int CardNo { get; set; }
double Price { get; set; }
string CustomerName { get; set; }
}
Modifying your action method:
var obj = from b in context.GiftCards
join cus in context.Customers on b.CustomerID equals cus.ID
where b.ID == int.Parse(Request.QueryString["gc"])
select new CardInfo
{
ID = b.ID,
Date = b.Date,
CardNo = b.CardNo,
Price = b.Price,
CustomerName = cus.FirstName + " " + cus.LastName
};
return View(obj);
Then you should strongly type your GiftVochure view to this type's sequence.
#model IEnumerable<CardInfo>
In the end you can iterate the items in your view.
#foreach(CardInfo current in Model) {
//display info
}
You should probably move your markup for displaying a single object to a partial view. Then render it in your loop.

Related

Entity Framework Core Select Outer Join

is there an easy way to include a nullable navigation inside a select expression for EF Core?
My model looks like this
public class RootVO
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(200)]
public string Description { get; set; }
public int? RelationId { get; set; }
[ForeignKey(nameof(RelationId))]
public RelationVO Relation { get; set; }
}
public class RelationVO
{
[Key]
public int Id { get; set; }
[Required]
[StringLength(200)]
public string Property1 { get; set; }
[Required]
[StringLength(200)]
public string Property2 { get; set; }
public ICollection<RootVO> RootRelations { get; set; }
}
When I load the data I just want to select certain kind of properties. Currently my expression looks like this:
Expression<Func<RootVO, RootVO>> selectExpr = m => new RootVO
{
Id = m.Id,
Description = m.Description,
Relation = m.Relation != null ? new RelationVO
{
Id = m.Relation.Id,
Property1 = m.Relation.Property1
} : null
};
var result = context.Roots.Select(selectExpr).ToList();
Is there an easier way to handle the relation select?
Edit
Maybe some background here will help:
I have a huge object with a lot of columns and relations, some with inner, some with outer joins. This query gets accessed by a datagrid on UI which can have dynamic columns depending on the user selection. To increase the performance I've written a class that will build the select expression dynamicly depending on the selected columns. For now it is working, but I'm having trouble when an outer join is null due to null-reference excepction.
The debug view on the expression could look like this:
.New IVA.Core.Data.Models.StockMovementLogVO(){
SequenceNo = $m.SequenceNo,
PostingPeriodId = $m.PostingPeriodId,
TransactionDate = $m.TransactionDate,
FinancialYear = $m.FinancialYear,
FinancialYearPeriod = $m.FinancialYearPeriod,
VoucherDate = $m.VoucherDate,
ItemQuantity = $m.ItemQuantity,
BuCode = $m.BuCode,
LocationStructure = .New IVA.Core.Data.Models.LocationStructureVO(){
Id = ($m.LocationStructure).Id,
Description = ($m.LocationStructure).Description
},
BookingType = .New IVA.Core.Data.Models.BookingTypeVO(){
Id = ($m.BookingType).Id,
Description = ($m.BookingType).Description
},
PartnerStockLocationType = .New IVA.Core.Data.Models.StockLocationTypeVO(){
Id = ($m.PartnerStockLocationType).Id,
Description = ($m.PartnerStockLocationType).Description
},
StockLocationType = .New IVA.Core.Data.Models.StockLocationTypeVO(){
Id = ($m.StockLocationType).Id,
Description = ($m.StockLocationType).Description
}
}
StockLocationType and PartnerStockLocationType are outer joins and if those are null the query fails to execute.
I've now changed my expression builder that it will take care of the outer joins by including a null reference check. The expression now looks like this:
.New IVA.Core.Data.Models.StockMovementLogVO(){
SequenceNo = $m.SequenceNo,
PostingPeriodId = $m.PostingPeriodId,
TransactionDate = $m.TransactionDate,
FinancialYear = $m.FinancialYear,
FinancialYearPeriod = $m.FinancialYearPeriod,
VoucherDate = $m.VoucherDate,
ItemQuantity = $m.ItemQuantity,
BuCode = $m.BuCode,
LocationStructure = .New IVA.Core.Data.Models.LocationStructureVO(){
Id = ($m.LocationStructure).Id,
Description = ($m.LocationStructure).Description
},
BookingType = .New IVA.Core.Data.Models.BookingTypeVO(){
Id = ($m.BookingType).Id,
Description = ($m.BookingType).Description
},
PartnerStockLocationType = .If ($m.PartnerStockLocationType != null) {
.New IVA.Core.Data.Models.StockLocationTypeVO(){
Id = ($m.PartnerStockLocationType).Id,
Description = ($m.PartnerStockLocationType).Description
}
} .Else {
null
},
StockLocationType = .If ($m.StockLocationType != null) {
.New IVA.Core.Data.Models.StockLocationTypeVO(){
Id = ($m.StockLocationType).Id,
Description = ($m.StockLocationType).Description
}
} .Else {
null
}
}
Edit
If anyone is interessted how it looks, I've created a repository where I use the class.
https://github.com/NQuirmbach/DynamicQueryBuilder

Project into a (list of) concrete object instead of an (list of) anonymous object

The problem simplified is as follows: in Entity Framework i am doing a join involving 3 tables, and returning the joined result set, which involves (some) fields from the 3 tables.
var query = (
from t1 in dbCtx.TB_Entity1
from t2 in dbCtx.TB_Entity2
.Where(p => p.someCol == t1.someCol && t.IsActive == true)
.DefaultIfEmpty() //LEFT JOIN
from t3 in dbCtx.TB_Entity3
.Where(q => q.someCol == t2.someCol)
where t1.IsLatest == true
&& (t1.istatus == 2
|| t1.istatus == 3
)
select new {
t1.col100,
t1.col101,
t2.col200,
t2.col201,
t3.col300,
t3.col301
}).OrderByDescending(t1 => t1.ID);
var anonObjList = query.ToList();
Thus, at the end of the query I write a projection to select the fields i want.
Finally i run the query with .ToList() and get a list of Anonymous objects.
How do i modify the query to project into a List of MyConcreteClass
i.e. i want to be able to write something similar to
List<MyConcreteClass> myObjList = query.ToList();
You may assume my concrete class looks like
public class MyConcreteClass
{
public string Col100 { get; set; }
public string Col101 { get; set; }
public string Col200 { get; set; }
public string Col201 { get; set; }
public string Col300 { get; set; }
public string Col301 { get; set; }
}
You just use the object initializer syntax:
new MyConcreteClass
{
Col100 = t1.col100,
Col101 = t1.col101,
Col200 = t2.col200,
Col201 = t2.col201,
Col300 = t3.col300,
Col301 = t3.col301
}

Linq Group Join Items into List

It's a master detail scenario, where each TABLE1 has multiple rows from TABLE2 assigned and I want to do something lihe this:
From a In TABLE1
Group Join c In TABLE2 On c.ID2 Equals a.ID Into Group
Select New ViewModel1 With {
.COLUMN1 = a.COLUMN1,
.COLUMN2 = a.COLUMN2,
.SUBTABLE = New ViewModel2 With {
.SUBCOLUMN1 = c.SUBCOLUMN1,
.SUBCOLUMN2 = c.SUBCOLUMN2,
}
}
Is this somehow possible?
Do you mean this:
var foobars = from foo in foolist
join bar in barlist on foo.Fooo equals bar.FooBar into t
select new
{
foo.Baar,
barbar = from bar in t
select new { bar.FooBar, bar.BarFoo }
};
That would be (approximately) how you do the query you described.
Sorry, I had to reread the question a few times to get that it was being mapped to the first element.
Perhaps the following can help you:
class Program
{
public class A
{
public int ID { get; set; }
public string COLUMN1 { get; set; }
public string COLUMN2 { get; set; }
}
public class B
{
public int ID { get; set; }
public int AID { get; set; }
public string SUBCOLUMN1 { get; set; }
public string SUBCOLUMN2 { get; set; }
}
static void Main(string[] args)
{
var listA = new List<A>{
new A() { ID = 1, COLUMN1="COLUMN11",COLUMN2 = "COLUMN12"},
new A() { ID = 2 ,COLUMN1="COLUMN21",COLUMN2 = "COLUMN22"}
};
var listB = new List<B>()
{
new B(){ID=1,AID = 1 },
new B(){ID=2,AID = 1},
new B(){ID=3,AID = 1},
new B(){ID=4,AID = 2},
new B(){ID=5,AID = 2}
};
//Group Join As Method Chain:
var queryAsMethodChain = listA.GroupJoin(listB, a => a.ID, b => b.AID, (a, t) => new
{
ID = a.ID,
COLUMN1 = a.COLUMN1,
COLUMN2 = a.COLUMN2,
SUBTABLE = t.Select(tt => new { tt.SUBCOLUMN1, tt.SUBCOLUMN2 })
});
//Group Join As Standard Method
var queryAsStandardMethod = from a in listA
join b in listB
on a.ID equals b.AID into t
select new
{
ID = a.ID,
COLUMN1 = a.COLUMN1,
COLUMN2 = a.COLUMN2,
SUBTABLE = t.Select(tt => new { tt.SUBCOLUMN1, tt.SUBCOLUMN2 })
};
}

IQueryable.Select to a List type sub POCO

I have an Entity Framework model in which there is a "Customers" and a "CustomerPhones" table. A customer can have multiple phone numbers so the "Customer" entity has a collection of "Phone". I can query the model with no problem :
using (CustomerEntities context = new CustomerEntities())
{
Customer customer = context.Customers.FirstOrDefault();
CustomerPhone phone = customer.Phones.FirstOrDefault();
MessageBox.Show(customer.Name + " " + phone.Number);
}
The model is too complex for what I need to do (even though my example is basic) so I'm trying to boil it down to simpler POCOs. Here are the 2 simple classes :
public class SimplePhone
{
public int Id { get; set; }
public string Number { get; set; }
}
public class SimpleCustomer
{
public int Id { get; set; }
public string Name { get; set; }
//Phones is a list because a single Customer can have multiple phone numbers
public List<SimplePhone> Phones { get; set; }
}
I can populate the simple properties of the object using the "Select" method of "IQueryable" :
using (CustomerEntities context = new CustomerEntities())
{
IQueryable<SimpleCustomer> customers = context.Customers.Select(
c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name
}
);
SimpleCustomer customer = customers.FirstOrDefault();
MessageBox.Show(customer.Name);
}
So my question is pretty simple : how can I populate the "Phones" property which is a list?
using (CustomerEntities context = new CustomerEntities())
{
IQueryable<SimpleCustomer> customers = context.Customers.Select(
c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name
Phones = ///????
}
);
SimpleCustomer customer = customers.FirstOrDefault();
SimplePhone phone = customer.Phones.FirstOrDefault();
MessageBox.Show(customer.Name + " " + phone.Number);
}
Let me know if I'm unclear and/or you need more details.
Thanks!
I'm not sure if there isn't something more to your question, but as far as I understand, you can just call ToList and it will be materialized as a list:
IQueryable<SimpleCustomer> customers =
context.Customers.Select(c => new SimpleCustomer
{
Id = c.Id,
Name = c.Name,
Phones = c.Phones.Select(p => new SimplePhone
{
Id = p.Id, // Unless you want the custom Id, i.e. c.Id
Number = p.Number
}).ToList();
});

ASP NET MVC How to call Count on an attribute then print out a sorted list?

Say I had a class:
public class Post
{
public int PostId { get; set; }
public string Topic { get; set; }
public int UserId { get; set; }
[StringLength(5000)]
public string Body { get; set; }
public DateTime DateCreated { get; set; }
public string Name { get; set; }
public int Votes { get; set; }
}
And for each post, a user could input a topic. for example, if the topics were "Red" "Green" "Blue" and "Yellow", how could I create a list based on how many times those were used?
An example output:
Red | 70
Blue | 60
Green | 40
Yellow| 35
EDIT: How come this doesn't work and gives me an error where I cannot implicitly convert the type?
public List<string> GetPopularTopics(int count)
{
var posts = from p in db.Posts
group p by p.Topic into myGroup
select new
{
Topic = myGroup.Key,
Count = myGroup.Count()
};
return posts.ToList();
}
EDIT 2:
So I tried your solution out Dustin, and I'm getting an error. This is what I used:
public IEnumerable<IGrouping<string,int>> GetPosts()
{
var posts = from p in db.Posts
group p by p.Topic into topicCounts
select new
{
Topic = topicCounts.Key,
Count = topicCounts.Count()
};
return posts.ToList();
}
This is giving me an error under posts.ToList():
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.IEnumerable>'. An explicit conversion exists (are you missing a cast?)
To create the grouping you create an anonymous type such as:
var posts = from p in context.Posts
group p by p.Topic into topicCounts
select new
{
Topic = topicCounts.Key,
Count = topicCounts.Count()
};
Then to work with the date, lets say iterate over it:
foreach(var p in posts)
{
Response.Write(String.Format("{0} - {1}", p.Topic, p.Count));
}
You must create a new type if you do a projection and return it form method!
public class MyCounts
{
public string Topic { get; set; }
public int Count { get; set; }
}
public List<MyCounts> GetPopularTopics(int count)
{
var posts = from p in db.Posts
group p by p.Topic into myGroup
select new MyCounts
{
Topic = myGroup.Key,
Count = myGroup.Count()
};
return posts.ToList();
}
The problem is that you need to use an non anonymous type for your return value.
This query creates an IEnumerable of anonymous types.
var posts = from p in context.Posts
group p by p.Topic into topicCounts
select new
{
Topic = topicCounts.Key,
Count = topicCounts.Count()
};
It's the select new statement that creates the anonymous objects.
What you need to do is to create something that is non anonymous - an object that can be shared within and outside this method.
Like this:
public IEnumerable<TopicAndCount> GetPosts()
{
var posts = from p in context.Posts
group p by p.Topic into topicCounts
select new TopicAndCount
{
Topic = topicCounts.Key,
Count = topicCounts.Count()
};
}
Note the select new TopicAndCount statement and the return value of the enclosing method.
That will solve your problem.