I have some simple classes that looks like this:
Class Favorites
Guid UserId
Guid ObjectId
Class Objects
Guid Id
String Name
With Entity Framework I want to select all the Objects which has been marked as a favorite by a user.
So I tried something like this
context.Objects.Where(
x => x.Id ==
context.Favorite.Where(f => f.UserId == UserId)
.Select(f => f.ObjectId).Any()
);
But I don't get it. I also tried with intersect, but what I understand it most be the same type. One User can have many Favorite objects
you could use join clause:
context.Favorite
.Where(f => f.UserId == UserId)
.Join(context.Objects, t => t.ObjectId, u => u.Id, (t, u) => t);
I'd do a join, my linq would look like:
var matches = from o in context.Objects
join f in context.Favorite on o.Id equals f.ObjectId
where f.UserId == UserId
select o;
from o in context.Objects
join f in context.Favorites on o.Id equals f.ObjectId
where f.UserId == #userId
select //whatever you wants
Use FirstOrDefault() instead of Any()
your favorites class needs a property that links it back to the objects, and instead of the double where clauses you can use an Include
Classes
Class Favorites
Guid UserId
Guid ObjectId
[ForeignKey("Id")]
Objects objs
Class Objects
Guid Id
String Name
Linq
context.Favorites.Include(objs).Where(x => x.UserID == UserID)
Then you Favorites object would have a collection of objects under it.
Related
I want to load from a specific id the list include details with lambda.
I tried it with following code:
// Load User Visitor list
var list = await Context.UserVisitors
.Where(s => s.UserId.Equals(userOwner.Id))
.Select(s => s.UserVisitorId)
.ToListAsync();
foreach (var t in list)
{
UserOwnerVisitors.Add(await Context.User
.Include(u => u.Details)
.Include(u => u.Settings)
.FirstAsync(u => u.Id.Equals(t)));
}
The code works, but it is not efficient. How I can do it in one request with lambda?
Thanks in advance.
I am a little bit blind, as I don't know all your model's relationship, but below you can find what I think is your model, if you edit your question I can perhaps give you an exact answer:
var UserOwnerVisitorsList = from uv in Context.UserVisitors
join u in Context.User
on uv.UserId equals u.Id
join det in Context.Details
on det.UserId equals u.Id
join set in Context.Settings
on set.UserId equals u.UserId
where uv.UserId == userOwner.Id
select u;
I need to get NewsImage field and list of categories Ids that associated with the news in Many to Many relationship ... but it gives me error:
The type of one of the expressions in the join clause is incorrect.Type inference failed in the call to 'Join'.
My code looks like this
var Result1 = (from c in db.News
join d in db.Categories
on c.NewsId equals d.News.Select(l => l.NewsId)
where c.NewsId == 1
select new { c.NewsImagePath, d.CategoryId }).ToList();
Assuming you have a navigation property defining the n-n relation I would write:
var result = db.News
.Where(x => x.NewsId == 1)
.SelectMany(x => x.Categories,
(news, category) => new { news.NewsImagePath, category.CategoryId })
.ToList();
The problem is inside the on statement.
on c.NewsId equals d.News.Select( l => l.NewsId )
The Select on the right-hand side will return a IEnumerable of news, which is not what you want.
Something like this would technically work:
on c.NewsId equals d.News.Select( l => l.NewsId ).FirstOrDefault()
But it does not make sense logically.
I suspect the whole query should be built differently. I think you want to join when the category list of news contains the news item. In that case, you can't use the join statement, it would look somewhat like this:
from n in db.News
from c in db.Categories
where c.News.Select( ne => ne.NewsId ).Contains( n.NewsId )
select new { n.NewsImagePath, c.CategoryId }
I have a entity relation diagram as follows.
ClassEntity:
public int id
public int std
public virtual ICollection<StudentEntity> students
StudentEntity:
public int id
public string name
public string gender
public virtual ClassEntity class
public virtual StudentAddressEntity studentAddress
StudentAddressEntity:
public int id
public string address
I need to get the class and its male children.
var classEntity = dbContext.Set<ClassEntity>().Where(t => t.id == classId);
var query = classEntity.Include(c => c.students.Select(s => s.studentAddress))
.FirstOrDefault(c => c.students.Any(s => s.gender == GenderEnum.Male));
But it is returning the class with all the students. How to filter only male students?
I have used joins to accomplish similar results in the past. For eg I've accounts that have addresses nested (1:M). If I want to get, say, all the accounts that belong to a particular country, I would use joins as below:
(from a in accountRepo.GetAll()
join aa in accountAddressRepo.GetAll() on a.AccountId equals aa.AccountId
join ad in addressRepo.GetAll() on aa.AddressId equals ad.AddressId
where ad.CountryId == codeCountryId
select a).ToList();
If you are not using repository pattern you can simply replace accountRepo.GetAll() with DbContext.Set().
In your case you should be able to join Student, Address and Class entities and get similar results. Something like below should work for you:
(from s in DbContext.Set<StudentEntity>
join a in DbContext.Set<StudentAddressEntity> on s.studentAddress.id equals a.id
join c in DbContext.Set<ClassEntity> on s.class.id equals c.id
where c.std == classId && s.gender== GenderEnum.Male
select s).ToList();
please note this is a simple representation based on my understanding of your database and entity names. You may need to tweak this query a bit to make it compilable but the underlying idea should work for you. Please let me know how did it work for you.
You intentionally "can't" do this directly with the EF proxies. For example, consider what would happen when you tried to call SaveChanges() and all of the female students are missing from ClassEntity.Students!
Instead, the usual thing to do if you're just displaying data is to project onto an anonymous type or a DTO, e.g.:
var classOnlyMale = dbContext.Set<ClassEntity>()
.Where(x => x.Id == classId)
.Select(x => new // I'm using an anonymous type here, but you can (and usually should!) project onto a DTO instead
{
// It's usually best to only get the data you actually need!
Id = x.Id
Students = x.Students
.Where(y => y.Gender == GenderEnum.Male)
.Select(y => new { Name = y.Name, ... })
});
Or, if you desperately need to make changes and save them:
var classOnlyMale = dbContext.Set<ClassEntity>()
.Where(x => x.Id == classId)
.Select(x => new
{
Class = x,
MaleStudents = x.Students.Where(y => y.Gender == GenderEnum.Male)
});
I quite strongly recommend the former unless there's no way around it. It's really easy to introduce bugs if you're making changes to filtered data and trying to save it.
The below should load only the male students for each class.
var classEntity = testContext.Set<ClassEntity>().Where(t => t.Id == classId);
var classes = classEntity.ToList().Select(c =>
{
testContext.Entry(c)
.Collection(p => p.Students)
.Query()
.Where(s => s.Gender == GenderEnum.Male)
.Load();
return c;
});
I think join is the right way to go about it as suggested by Manish Kumar.
(from s in DbContext.Set<StudentEntity>
join a in DbContext.Set<StudentAddressEntity> on s.studentAddress.id equals a.id
join c in DbContext.Set<ClassEntity> on s.class.id equals c.id
where c.std == classId && s.gender== GenderEnum.Male
select s).ToList();
Suppose I have this data structure in my db.
Parent_table
ParentID
someOtherProp
having 1:N relation with Child_table as shown below
ChildID
ParentID
This Child_table further has a child table with 1:N relationship as SubChild_table
SubChildID
ChildID
Now, I have SubChildID. How can I get access to Parent_table's someOtherProp? I tried with .Include(), but I am really not sure how to write. So far I have something like this:
var foo = _db.Parent_table
.Include(c => c.Child_table
.Select(d => d.SubChild_table
.Where(f => f.SubChildID == subChildID)))
.Select(r => r.someOtherProp)
.SingleOrDefault();
The error I get is:
The Include path expression must refer to a navigation property
defined on the type. Use dotted paths for reference navigation
properties and the Select operator for collection navigation
properties. Parameter name: path
You don't need .Include unless you want to return the included properties. You're free to access all properties of all objects in the hierarchy while constructing the query.
So, I think what you want is:
var foo = (from p in _db.Parent_table
join c in _db.Child_table on p.ParentId equals c.ParentId
join s in _db.SubChild_table on c.ChildId equals s.ChildId
where s.SubChildId == subChildId
select p.someOtherProp).SingleOrDefault();
Providing you have the foreign key relationships set
var foo = _db.SubChild_tables.Where(sc => sc.SubChildId == id).Single().Child_table.Parent_Table.SomeOtherProp;
A guess ..
var foo = from pt in Parent_table
join ct in Child_table
on pt.ParentID equals ct.ParentID
join sct in SubChild_table
on ct.ChildID equals sct.ChildID
where sct.SubChildID == "YourValue"
select new {
pt.SomeOtherProp
};
Or
var foo = Parent_table
.Join(Child_table, p => p.ParentID, c => c.ParentID, (p, c) => new { p, c })
.Join(SubChild_table, sc => sc.c.ChildID, c => c.ChildID, (sc, c) => new { sc, c })
.Where(sc.SubCHildID == "YourValue")
.Select(m => new {
m.p.someOtherProp
});
This collection contains the entire database of products:
IList<Products> allProducts;
This contains just the guids of all the products for this user:
IList<Guid> usersProducts;
Below is the psuedo code of what I need, i.e. all the product classes in a IList for a given user and the product is also of type == 1.
var filteredProducts = (p from allProducts
where p.Id in usersProducts && p.Type == 1).List();
I can't figure out how to do the SQL query "WHERE IN (..., ...,)
var filteredProducts = (from p in allProducts
where usersProducts.Contains(p.Id) && p.Type == 1
select p).ToList();
#Samich's answer is correct. It's just a personal preference, but I prefer the method syntax...
var filteredProducts = allProducts.Where(p => p.Type == 1 && userProducts.Contains(p.Id)).ToList();
Also, for performance reasons, I swapped the order of your conditionals. If p.Type doesn't equal 1, the Contains won't execute.
Sounds like you just want a join.
var filteredProducts = (from p in allProducts
join u in usersProducts on p.Id equals u.Id
where p.Type == 1
select p).ToList();