I have three models like followings,
public class Team
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Document
{
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Application { get; set; }
public ICollection<DocumentResponsible> DocumentResponsibles { get; set; }
public string Pcda { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
public class DocumentResponsible
{
public int Id { get; set; }
public int DocumentId { get; set; }
public int TeamId { get; set; }
}
I want to write an entity framework expression to join three table and select all fields of document table and team names in one row per documents. So basicly I want to join three table use group_concat for team names. Then I want to bind it to a gridview in web form.
What I have tried,
(from dc in DBContext.Document
join dr in DBContext.DocumentResponsible on dc.Id equals dr.DocumentId
join t in DBContext.Team on dr.TeamId equals t.Id
select new
{
Name = dc.Name,
Type = dc.Type,
Application = dc.Application,
Pcda = dc.Pcda,
}).ToList();
and I have just tried it,
var data = DBContext.Dcoument.Include("DocumentResponsibles").Tolist();
It's hard to help without your DbContext and the Entity Mappings, but I'll go out on a limb saying you might just want to mark Document.DocumentResponsibles as virtual.
Also, in DocumentResponsible, maybe you'd want to add a property for Document and one for Team (both marked as virtual too) this way you don't have to do the join keys all the time you want to work with your data, EF would do it for you once properly configured.
If it doesn't work, can you add the following information to your question: First, the context class and the mappings you have. Second, if you do var firstDocument = yoneylemDB.Document.First(), how does firstDocument looks like? Does it have all it's fields and properties filled out? Is there anything weird?
Related
Not sure how to describe this question.
Here is the example:
I have an entity as Tour. Tour table contains static 3 rows(can be more in the future).
public class Tour
{
public int Id { get; set; }
public string Name { get; set; }
public string Location { get; set; }
}
Each user can turn this options keys.
So I have another table called UserTourSetting to store user options.
public class UserTourSetting
{
public int Id { get; set; }
public int UserId { get; set; }
public int TourId { get; set; }
public bool Enabled { get; set; }
public ApplicationUser User { get; set; }
public Tour Tour { get; set; }
}
When the user loads the page it should always see 3 rows with the status on or off.
When I load UserTourSetting table I get no results as there is no record yet on the table for the user first time. I guess I need to do join with Tour table and also include Tour results as I will need the titles.
When the switches are turned on off then individually it will add a new record if not exists or change Enabled key if exists.
What would be the best way to implement this with EF? I struggle the generate linq statement to load the join table.
here is the method I tried:
public IEnumerable<UserTourSetting> GetUserTourSettings(int userId)
{
var q = from tour in DbContext.Tours
join uts in DbContext.UserTourSettings
on tour.Id equals uts.TourId
where uts.UserId == userId
select uts;
return q;
}
But it does not work. And I cannot access Tour names. Where the include can go in this query?
Thanks,
Please try to set virtual on those properties.
public virtual ApplicationUser User { get; set; }
public virtual Tour Tour { get; set; }
p/s: for more information, you can see this https://stackoverflow.com/a/8542879/5771430
I am trying to retrieve a subset of properties in in Entity Framework Core (1.1.1) for an optional one-to-one relationship, but my query attempts result in all columns being retrieved in the query for both tables (verified with SQL Profiler).
For an example, lets say I have these models bound up to my DbContext:
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public string Birthday { get; set; }
public string FavoriteIceCream { get; set; }
public string OtherRandomInfoForExample { get; set; }
public virtual StudentAddress Address { get; set; }
}
public class StudentAddress
{
public int StudentId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public int Zipcode { get; set; }
public string State { get; set; }
public string Country { get; set; }
public virtual Student Student { get; set; }
}
When I try projecting this into a new model choosing only the columns I want like the following:
var studentsCityInfos = _dbContext.Student.AsNoTracking().Select(s => new StudentCityInfo
{
Id = s.StudentId,
Name = s.StudentName,
City = s.Address.City
}).ToList();
The result is a query that returns all columns both tables. I have also tried the following with a null check on the navigation property and that leads to the same results:
var studentsCityInfos = _dbContext.Student.AsNoTracking().Select(s => new StudentCityInfo
{
Id = s.StudentId,
Name = s.StudentName,
City = s.Address == null ? null : s.Address.City
}).ToList();
Is this maybe just a projection bug in EF Core 1.1.1 that should be optimized?
Any alternative approaches anyone else can think of?
As a fall back I can break this up into two queries or use FromSql to write my own, but I would like to know the correct approach to this scenario.
For completeness I have no control over the schema and both tables have many more columns and roughly a million rows.
Thank you for taking the time to read and provide answers!
EDIT: as requested, here is an example of the sql profiler results (manually made to reflect the results from my scenario):
SELECT [s].[StudentId], [s].[StudentName], [s].[Birthday], [s].[FavoriteIceCream], [s].[OtherRandomInfoForExample], [s].[BusinessFullName], [s].[BusinessLastName], [s.Address].[StudentId], [s.Address].[Address1], [s.Address].[Address2], [s.Address].[City], [s.Address].[Zipcode], [s.Address].[State], [s.Address].[Country]
FROM [Student] AS [s]
LEFT JOIN [StudentAddress] AS [s.Address] ON [s].[StudentId] = [s.Address].[StudentId]
ORDER BY [s.Address].[StudentId]
I am using Entity Framework Code First and LINQ to Entities in a Web Api Controller.
I have 3 tables that are related with the following relations/ navigation properties: (the model classes are as follows)
My Reservation class:
[Table("Reservations")]
public class Reservation
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ReservationId { get; set; }
public DateTime Date { get; set; }
public int RoomId { get; set; }
public Room Room { get; set; }
public Customer Customer { get; set; }
public int CustomerId { get; set; }
// create association table ReservationMeals
public virtual ICollection<ReservationMealItems> ReservationMeals { get; set; }
}
Association class:
public class ReservationMealItems
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ReservationId { get; set; }
public int MealId { get; set; }
public virtual Reservation Reservation { get; set; }
public virtual Meal Meal { get; set; }
}
Meals class:
[Table("Meals")]
public class Meal
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
public int MealTypeId { get; set; }
public virtual MealType Type { get; set; }
public virtual ICollection<MenuMealItem> Menus { get; set; }
// create association table ReservationMeal
public virtual ICollection<ReservationMealItems> ReservationMeals { get; set; }
// one-to-one with MealPrice where MealPrice is the dependant
public virtual MealPrice MealPrice { get; set; }
}
And here is my controller to which I am passing a Date and then querying the tables in order to bring back all the meals from all the reservations made on that particular date.
public IHttpActionResult GetReservationMealsForDate(DateDto date)
{
using (var context = new CafeteriaContext())
{
var reservationMeals = from p in context.Reservations
where p.Date == date.Date
join d in context.ReservationMeals
on p.ReservationId equals d.ReservationId
select new SimpleId
{
Id = d.MealId
};
var meals = from p in context.Meals
join d in reservationMeals
on p.Id equals d.Id
select new SimpleMeal
{
Name = p.Name
};
return Ok(meals.ToList());
}
}
The controller works and brings back the list of meals from all reservations made on that date but I am certain that it's not optimal.
I tried not using the JOINs and instead make use of the navigation properties but with no success. I wonder if the relations are set up correctly and if the navigation properties are placed as they should be and if yes, then how can the controller be rewritten to bring back the same result set using navigation properties.
And as a bonus question I would like to know how to write the correct query using LINQ method syntax as I did not succeed in writing it as such.
I am currently learning and any explanations are greatly appreciated. I have read this blog post Coding Abel from where I managed to make it work. But I am still curious to know how correct my solution is and eager to learn better alternatives. Thanks!
You can try use eagerly loading with LINQ and method Include. Your table ReservationMealItems have relationships to Meal and Reservation in this case you need include your entities like :
Lambda
var x = context.ReservationMealItems.Include(res => res.Reservation)
.Where(dt => dt.Reservation.Date == DateTime.Now)
.ThenInclude(meal => meal.Meal)
.Select(d => d.Meal.Name)
.ToList();
Here you find more informations MSDN
Query Syntax
var z = (from resevationMealsItems in context.ReservationMealItems
join reservation in context.Reservation on resevationMealsItems.ReservationId equals
reservation.ReservationId
join meal in context.Meal on resevationMealsItems.MealId equals meal.Id
select meal.Name).ToList();
Using ASP.NET 4.5 and EF 6, I've put together a multilevel data model that looks like this:
Organization, which has an ICollection of:
_____Workspaces, which has an ICollection of:
__________Projects, which has an ICollection of:
_______________Cards
If I've got a Card Id, how do I find the parents above it? I can't even figure out how to get one level of parent. To find the Project that is the parent of a card with Id of myCardId, I want to write something like:
var project = db.Projects.Where(p => p.Cards.Where(c => c.Id == myCardId));
Any guidance? Good tutorials you can point me to?
Update: Here's my Project model:
public class Project
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public virtual ICollection<Card> Cards { get; set; }
}
And here's my Card:
public class Card
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public string Notes { get; set; }
}
When I look at the tables in the database, the Card has a Project_Id column, but that happened magically from something Entity Framework did - I believe. Because the Card model has no Parent object on it, I can't programatically ask for things like Card.Project.Workspace.Organization...
Did I set up the whole thing backward?
Hope you have references for each tables.
so you can get the organization by.
var organization = (from o in Organization
from w in Workspaces
from p in Projects
from c in Cards
where c.Id == myCardId && p.projectid == c.projectid && w.workspaceid == p.workspaceid && o.organizationid == w.organizationid select o).FirstOrDefault();
if its different from your code then post your collection structure here, so that anyone can help.
I imagine that find the parents means go up in the Hierarchy so you should be able to write somethin like
'var project = db.Projects.Where(p => p.Cards.Where(c => c.Id == myCardId));'
var t= db.Cards.where(x=> x.id==myCardId).Select(y=> y.Project.Workspace.Organization);
//this should return the organization
Your Model should be like this:
public class Project
{
public int projectId { get; set; }
public int workspaceId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime Created { get; set; }
public virtual ICollection<Card> Cards { get; set; }
}
public class Card
{
public int cardId { get; set; }
public int projectId { get; set; }
public string Title { get; set; }
public DateTime Created { get; set; }
public string Notes { get; set; }
}
Your Card table should have reference to projectid, and project table should have reference to workspaceid, and workspace table should have reference to organisationid.
Then you can use karthikb2win's query to get Organization or any parent tables.
I have a table containing service announcements. For this table I have a 1:1 POCO - except that it contains one extra field. In my query this is the joined in username of the author, the table contains just the author id.
I thought that I could just tack on an [Ignore] attribute on this field, and then be able to use the POCO for inserts/updates without problems? My problem is that with the [Ignore] attribute, the BrukerNavn field is not filled. And without the attribute, it goes bang on insert/update.
[TableName("tblDriftsmelding")]
[PrimaryKey("DriftID")]
public class Driftsmelding
{
public int DriftID { get; set; }
[Column("tittel")] public string Tittel { get; set; }
public string Tekst { get; set; }
public string HTMLTekst { get; set; }
[Column("gyldigfra")] public DateTime? Fra { get; set; }
[Column("gyldigtil")] public DateTime? Til { get; set; }
[Column("publisert")] public bool Publisert { get; set; }
[Column("CreatedBy")] public int? BrukerID { get; set; }
public string BrukerNavn { get; set; }
}
This is the POCO. The table is a 1:1 mapping, except the "BrukerNavn" field at the end.
select d.DriftID, d.Tekst, d.Created, d.gyldigtil, d.gyldigfra, d.publisert, d.tittel, d.HTMLTekst, d.createdby, b.brukerident as BrukerNavn
from tblDriftsmelding d
left outer join tblbruker b on d.CreatedBy = b.brukerid
order by DriftID desc
This is the query that feeds the POCO. (I have also tried using select d.*, b.brukerid. No difference)
(Note, the actual question is in bold in the above text, since it sort of got intermingled with the rest of the text)
I think what you need is the [ResultColumn] attribute - this will fill the column if your query contains data for it and it will not get used for inserts and updates.
You can see more on it here -> https://github.com/CollaboratingPlatypus/PetaPoco/wiki/Mapping-Pocos