I have two tables:
public class Game
{
public int GameId { get; set; }
public int FirstTeamId { get; set; }
public int GoalsFirstTeam { get; set; }
public int GoalsSecondTeam { get; set; }
public int SecondTeamId { get; set; }
public Team Team { get; set; }
}
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Game> Games { get; set; }
}
Then, using:
OperationDataContext dt = new OperationDataContext();
public ActionResult Scores()
{
List<Games> model = dt.Games.ToList();
var query = (from g in dt.Games
join t1 in dt.Teams on g.FirstTeamId equals t1.Id
join t2 in dt.Teams on g.SecondTeamId equals t2.Id
select new Games(){g.GameId,
t1.Name,
g.GoalsFirstTeam,
g.GoalsSecondTeam,
t2.Name
}
).ToList();
model = query;
return View(model);
What I am trying to ultimately achieve in View is this:
Game FirstTeam Goals Goals SecondTeam
1 Roma 1 3 Manchester
2 Inter 0 0 Milan
Can somebody help me with this, because I'm getting error notifications ?
PS. When I try this:
OperationDataContext dt = new OperationDataContext();
public ActionResult Scores()
{
var games = dt.Games.ToList();
return View(games);
}
The result is:
Game FirstTeam Goals Goals SecondTeam
1 Roma 1 3 Roma
2 Inter 0 0 Inter
Change:
select new Games(){ g.GameId,
t1.Name,
g.GoalsFirstTeam,
g.GoalsSecondTeam,
t2.Name
}
To an anonymous type:
select new { GameId = g.GameId,
Team1 = t1.Name,
Team2 = t2.Name,
Team1Goals = g.GoalsFirstTeam,
Team2Goals = g.GoalsSecondTeam
}
You can also define a new type - GameResult that consists the fields above.
As Erik suggested you can improve your model
public class Game
{
public int Id { get; set; }
public int FirstTeamId { get; set; }
public virtual Team FirstTeam { get; set; }
public int GoalsFirstTeam { get; set; }
public int GoalsSecondTeam { get; set; }
public int SecondTeamId { get; set; }
public virtual Team SecondTeam { get; set; }
//What does this mean??
public Team Team { get; set; }
}
public class Team
{
public int Id { get; set; }
public string Name { get; set;}
}
Then you can query your data this way
OperationDataContext dt = new OperationDataContext();
public ActionResult Scores()
{
var query = dt.Games.Select(g=> new
{
Game = g.Id,
FirstTeam = g.FirstTeam.Name,
Goals_FT = g.GoalsFirstTeam,
Goals_ST = g.GoalsSecondTeam,
SecondTeam = g.SecondTeam.Name
}
return View(query.ToList());
}
Hope it is clear and helpful,
Alessandro
Related
I want to retrieve all players from db for one club where they are in M:M relationship using PlayerClubs join table. My code is working but really doesn't want that approach for example, first I am retrieving all players from db
var players = await _context.PlayerClubs.Where(pc => pc.ClubId == id).Select(p => p.Player).ToListAsync();
then I retrieve the club based on id which I receive from controller
var club = await _context.Clubs.Where(z => z.Id == id).FirstOrDefaultAsync();
and lastly populate ClubViewModel with this data
return new ClubViewModel()
{
Players = players,
Club = club,
};
Now I want to populate this new ClubViewModel with just one db call i.e. one query using linq expression.
Things that I have tried
var query = (from c in _context.Clubs
join pc in _context.PlayerClubs on c.Id equals pc.ClubId
join player in _context.Players on pc.PlayerId equals player.Id
where c.Id == id
select new ClubViewModel
{
Players = player,
Club = c,
}).ToListAsync();
but I got stuck.
PlayerClubs table
Club
public class Club
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[EnumDataType(typeof(Gender))]
public Gender GenderType { get; set; }
public int SeasonId { get; set; }
public virtual Season Season { get; set; }
[Required]
public string YearOfEstablishment { get; set; }
[Required]
public string YearOfEntryIntoLeague { get; set; }
public string Note { get; set; }
[ForeignKey("League")]
public int LeagueId { get; set; }
public virtual League League { get; set; }
public virtual ICollection<PlayerClub> PlayerClubs { get; set; }
public virtual ICollection<CoachClub> CoachClubs { get; set; }
}
Player
public class Player
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string FullName { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime Birth { get; set; }
public int LicenseNumber { get; set; }
public string Note { get; set; }
public virtual List<string> Clubs { get; set; }
public virtual List<Club> Klubovi { get; set; }
public virtual List<string> ClubNames { get; set; }
[StringLength(13, ErrorMessage = "Матичниот број не може да биде подолг од 13 цифри")]
public string Embg { get; set; }
public virtual ICollection<PlayerClub> PlayerClubs { get; set; }
public Player()
{
Clubs = new List<string>();
ClubNames = new List<string>();
Klubovi = new List<Club>();
}
}
PlayerClub
public class PlayerClub
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey("Club")]
public int ClubId { get; set; }
[ForeignKey("Player")]
public int PlayerId { get; set; }
public virtual Club Club { get; set; }
public virtual Player Player { get; set; }
}
ClubViewModel
public class ClubViewModel : Club
{
public Club Club { get; set; }
public List<Player> Players { get; set; }
public ClubViewModel()
{
Players = new List<Player>();
}
}
Your query:
var query =
from c in _context.Clubs
where c.Id == id
select new ClubViewModel
{
Players = c.PlayerClubs.Select(pc => pc.Player).ToList(),
Club = c,
};
var result = await query.ToListAsync();
I have Order model And OrderDetails model like that:
public class Order
{
public int ID { get; set; }
public int ClientID { get; set; }
public int ShippingID { get; set; }
public int SharepointID { get; set; }
public int CallStatuID { get; set; }
[DataType(DataType.Date)]
public DateTime Date { get; set; }
// public int OrderStatusID { get; set; }
public decimal ShippingCost { get; set; }
public string purchasetype { get; set; }
public string Notes { get; set; }
public decimal Total { get; set; }
public virtual List<OrderDetail> orderdetails { get; set; }
public virtual Client Client { get; set; }
public virtual Shipping shipping { get; set; }
public virtual Sharepoint sharepoint { get; set; }
public virtual CallStatu callStatu { get; set; }
}
and
public class OrderDetail
{
public int ID { get; set; }
public int OrderID { get; set; }
public int ItemID { get; set; }
public int SizeID { get; set; }
public decimal Price { get; set; }
public int orderStatuID { get; set; }
public int Quantity { get; set; }
public decimal Total { get; set; }
public virtual Order order { get; set; }
public virtual Item item { get; set; }
public virtual Size size { get; set; }
public virtual OrderStatu orderStatu { get; set; }
}
i want to select Client name, Governorate, Total of the Order and Items count
So i wrote this code:
public JsonResult ShareSearchDetails(SharepointANVM ANVM)
{
var SHR = from O in db.Orders
where O.SharepointID == ANVM.Id
join OD in db.OrderDetails
on O.ID equals OD.OrderID
where OD.orderStatuID == ANVM.NameOfStutes
select new
{
ClientName = O.Client.RealName,
Governorate = O.Client.Region.RegionName,
Total = O.Total,
Items = O.orderdetails.Count(),
Orderstatu = OD.orderStatu.NameOfStutes
};
return Json(SHR.ToList(), JsonRequestBehavior.AllowGet);
}
the problem is that the result is right, but its ordering by OrderDetails model.
that's the code get all rows from sub model (orderdetails) but i want it come ordering by Main model (Orders)
the result:The wrong result
but the correct Result should be like that :
The correct result
Please help
You could use Distinct to get not duplicated rows, like the following code:
var SHR = (from O in db.Orders
join OD in db.OrderDetails on O.ID equals OD.OrderID
where O.SharepointID == ANVM.Id && OD.orderStatuID == ANVM.NameOfStutes
select new
{
ClientName = O.Client.RealName,
Governorate = O.Client.Region.RegionName,
Total = O.Total,
Items = O.orderdetails.Count(),
Orderstatu = OD.orderStatu.NameOfStutes
})
.Distinct()
.ToList();
Note that, you don't need to use where twice.
I hope you find this helpful.
You can use grouping in your linq just like in SQL :
var SHR = from O in db.Orders
join OD in db.OrderDetails on O.ID equals OD.OrderID
where OD.orderStatuID == ANVM.NameOfStutes && O.SharepointID == ANVM.Id
group new { O, OD } by new {
ClientName = O.Client.RealName,
Governorate = O.Client.Region.RegionName,
Total= O.Total,
Orderstatu = OD.orderStatu.NameOfStutes
} into grp
select new
{
grp.ClientName,
grp.Governorate,
grp.Total,
grp.Orderstatu,
Items = grp.Count()
};
After i finished my SimpleMembership Step on my Application, there is another problem...
namespace Korbball.Models
{
public class GamesContext : DbContext
{
public GamesContext()
: base("KorbballDBContext")
{
}
public DbSet<Games> Games { get; set; }
public DbSet<Teams> Teams { get; set; }
}
public class Games
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int GameId { get; set; }
public int TeamA { get; set; }
public int TeamB { get; set; }
public int ResultA { get; set; }
public int ResultB { get; set; }
public int League { get; set; }
public DateTime StartDate { get; set; }
public Boolean Finished { get; set; }
}
public class Teams
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int TeamId { get; set; }
public string TeamName { get; set; }
}
}
My target is, to create Games with Results etc.
The TeamA & TeamB column shoukd be the TeamID from the Teams Table.
Whats steps i have to do to set the correct relationship.
Additional Informations:
Games Table ->
GamesID = 1
TeamA = 1
TeamB = 2
ResultA = 10
ResultB = 8
Teams Table ->
TeamId = 1
TeamName = "Manchester"
TeamId = 2
TeamName = "Zurich"
On the view ->
Manchester 10 : 8 Zurich
I'm not sure if this is what you want to do, but if you create it like this, with the public virtual Team, the entity framework will automatically take care of the mapping for you and you can just access these "navigation properties" like normal objects.
namespace Korbball.Models
{
public class GamesContext : DbContext
{
public GamesContext()
: base("KorbballDBContext")
{
}
public DbSet<Games> Games { get; set; }
public DbSet<Teams> Teams { get; set; }
}
public class Games
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int GameId { get; set; }
public virtual Team TeamA { get; set; }
public virtual Team TeamB { get; set; }
public int ResultA { get; set; }
public int ResultB { get; set; }
public int League { get; set; }
public DateTime StartDate { get; set; }
public Boolean Finished { get; set; }
}
public class Teams
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int TeamId { get; set; }
public string TeamName { get; set; }
}
}
EDIT:
Ok, this is how I usually do this:
I create virtual fields for all navigation properties, which in your case would only be the Teams as I already pointed out.
Then, when you create the Teams (which have to be there before the game can exist), you just add them like:
var teamM = new Team(){TeamName = "Manchester"};
var teamZ = new Team(){TeamName = "Zurich"};
// 'db' is your DbContext
db.Teams.Add(teamM);
db.Teams.Add(teamZ);
// This could also happen through some user form or something.
db.SaveChanges();
// this is important, because only after you've safed entities to you db,
// the [DatabaseGenerated] key will be set.
var game1 = new Game();
game1.ResultA = 10;
game1.ResultB = 8;
//etc.
game1.TeamA = teamM;
game1.TeamB = teamZ;
// we still have those from up when we created an db.SaveChanges'd them
// now save everything and the Entity Framework will take care of all the relationships
db.SaveChanges();
If you have already saved the Teams and they exist in you database, you can do something like:
var team1 = db.Teams.Find(0); // 0 beeing the [Key] => Manchester
// or
var team2 = db.Teams.Where(m => m.Name.Contains("Zu"); // => Zurich
// Now do the same thing with game1:
game1.TeamA = team1;
game1.TeamB = team2;
db.SaveChanges();
I hope this is what you want to know.
If this won't work, you need to take a look at some up-to-date tutorials about entity framework code first. Lots of things can go wrong with all the initialization / database creation.
Ok, i changed the code into this:
public class GamesContext : DbContext
{
public GamesContext()
: base("KorbballDBContext")
{
}
public DbSet<Games> Games { get; set; }
public DbSet<Teams> Teams { get; set; }
}
public class Games
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int GameId { get; set; }
public virtual Teams TeamA { get; set; }
public virtual Teams TeamB { get; set; }
public int ResultA { get; set; }
public int ResultB { get; set; }
public int League { get; set; }
public DateTime StartDate { get; set; }
public Boolean Finished { get; set; }
}
public class Teams
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int TeamId { get; set; }
public string TeamName { get; set; }
}
My Controller looks like this:
public class GamesController : Controller
{
GamesContext db = new GamesContext();
//
// GET: /Games/
public ActionResult Index()
{
var games = from game in db.Games
join teama in db.Teams on game.TeamA.TeamId equals teama.TeamId
join teamb in db.Teams on game.TeamB.TeamId equals teamb.TeamId
select game;
return View(games.ToList());
}
}
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.TeamA.TeamName)
</td>
<td>
#Html.DisplayFor(modelItem => item.ResultA)
</td>
<td>
#Html.DisplayFor(modelItem => item.ResultB)
</td>
<td>
#Html.DisplayFor(modelItem => item.TeamB.TeamName)
</td>
</tr>
}
I'm using a typical invoice system as a test for developing MVC and ViewModel knowledge, before tackling migrating my employers inhouse systems from asp to asp.net MVC.
I know ViewModels are the recommended way to display info in the view - so I was hoping for some help "flattening" the viewmodel for the following:
tables: Invoice, InvoiceItem, Payment, PaymentInvoice
Invoice and InvoiceItem are linked, and Payment (which records an overall payment), and PaymentInvoice (which lists which invoices the Payment covers) are also linked.
I would like a ViewModel to show me:
InvoiceId
CustomerName
Total of Invoice (quantity X UnitPrice plus VAT)
AmountAllocated (from the PaymentInvoice table)
Outstanding (TotalofInvoice - AmountAllocated)
So I think my ViewModel should be:
public class InvoiceViewModel
{
public Int InvoiceId { get; set; }
public string CustomerName { get; set; }
public decimal TotalofInvoice { get; set; }
public decimal AmountAllocated { get; set; }
public decimal Outstanding { get; set; }
}
My domain models are:
public class Invoice
{
public int InvoiceId { get; set; }
public int CustomerId { get; set; }
public string CustomerName { get; set; }
public string Email { get; set; }
public DateTime InvDate { get; set; }
public IList<InvoiceItem> InvoiceItems { get; set; }
}
public class InvoiceItem
{
public int InvoiceItemId { get; set; }
public int InvoiceId { get; set; }
public string Item { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal VAT { get; set; }
public virtual Invoice Invoice { get; set; }
// calculated fields
public decimal Total
{
get { return Quantity * UnitPrice; }
}
public decimal VATAmount
{
get { return TotalPlusVAT - Total; }
}
public decimal TotalPlusVAT
{
get { return Total * (1 + VAT / 100); }
}
}
public class Payment
{
public int PaymentId { get; set; }
public int CustomerId { get; set; }
public DateTime DateReceived { get; set; }
public decimal TotalReceived { get; set; }
public IList<PaymentInvoice> PaymentInvoices { get; set; }
}
public class PaymentInvoice
{
public int PaymentInvoiceId { get; set; }
public int PaymentId { get; set; }
public decimal AmountAllocated { get; set; }
public int InvoiceId { get; set; }
public virtual Payment Payment { get; set; }
}
My problem is in how to link the Payment and PaymentInvoice table to the Invoice and InvoiceItem table, so I can use a LINQ query in my controller to populate the viewmodel with the "flattened data".
I'm lost with the LINQ query too - in LinqPad I've got:
from c in Invoices
join i in InvoiceItems on c.InvoiceId equals i.InvoiceId
join pi in PaymentInvoices on c.InvoiceId equals pi.InvoiceId
select new {...into ViewModel????...}
...but not sure where to go after that.
EDIT - The closest I've got is the Sql to do this is:
SELECT Invoices.InvoiceId,
Invoices.CustomerName,
(SUM(InvoiceItems.Quantity * InvoiceItems.UnitPrice)) AS TotalOfInvoice,
(SELECT SUM(AmountAllocated) AS Expr1
FROM PaymentInvoices
WHERE (InvoiceId = Invoices.InvoiceId)) AS AmountAllocated,
SUM(InvoiceItems.Quantity * InvoiceItems.UnitPrice)
- (SELECT SUM(AmountAllocated) AS Expr1
FROM PaymentInvoices
WHERE (InvoiceId = Invoices.InvoiceId)) AS Outstanding
FROM Invoices LEFT OUTER JOIN
InvoiceItems ON Invoices.InvoiceId = InvoiceItems.InvoiceId
GROUP BY Invoices.InvoiceId, Invoices.CustomerName
Thank you,
Mark
I think your Linq query is almost perfect you just need to select new ViewModels:
from c in Invoices
join i in InvoiceItems on c.InvoiceId equals i.InvoiceId
join pi in PaymentInvoices on c.InvoiceId equals pi.InvoiceId
select new InvoiceViewModel {
InvoiceId = c.InvoiceId,
CustomerName = c.CustomerName,
TotalofInvoice = c.InvoiceItems.Sum(invoiceitem => invoiceitem.Total(),
AmountAllocated = ...
Outstanding = ...
};
I'm using ASP.NET MVC 3 with Entity Framework CodeFirst
I have two classes as follows:
Question:
public class Question
{
public int ID { get; set; }
public Target Target { get; set; }
public string QuestionText { get; set; }
public Category Category { get; set; }
public QuestionType QuestionType { get; set; }
public virtual ICollection<Answer> Answers { get; set; }
public Unit Unit { get; set; }
}
Answer:
public class Answer
{
public int ID { get; set; }
public virtual Question Question { get; set; }
public string AnswerText { get; set; }
public int Value { get; set; }
}
I also have this ViewModel:
public class QuestionViewModel
{
public int ID { get; set; }
public string Question { get; set; }
public string QuestionType { get; set; }
public string Target { get; set; }
public string Category { get; set; }
public string Unit { get; set; }
public List<Answer> Answers { get; set; }
}
I want to query the questions table and include the answers, if there are any.
I've been trying this style
var question = (from q in hontgen.Questions
where q.ID == id
join qt in db.QuestionTypes on q.QuestionType equals qt
join t in db.Targets on q.Target equals t
join c in db.Categories on q.Category equals c
join u in db.Units on q.Unit equals u
join a in db.Answers on q.Answers equals a
select new QuestionViewModel() {
ID = q.ID,
Question = q.QuestionText,
QuestionType = qt.Type,
Category = c.CategoryName,
Unit = u.UnitName,
Target = t.TargetName,
Answers = a
}).Single();
But this of course doesn't roll, because a isn't a list of answers, but only one answer.
How do I rewrite the query to take all answers in the collection, or all answers with the correct question in "Question", while at the same time accepting an empty answers-list?
What about a sub query like the following
public class DataRepository
{
public List<Question> Questions { get; set; }
public IEnumerable<Answer> Answers { get; set; }
}
public class QandA
{
DataRepository dr = new DataRepository();
public void QueryQuestion(int id)
{
var question = (from q in dr.Questions
where q.ID == id
select new QuestionViewModel()
{
ID = q.ID,
Question = q.QuestionText,
Answers = (from a in dr.Answers
where a.Question == q
select a)
});
}
}
}