I am using Code First Entity Framework.
I am using the following simple classes:
public class Users
{
public ICollection<Projects> Projects{get;set;}
}
public class Projects
{
public ICollection<Users> Users{get;set;}
}
I am using linq for data retrieval. When performing the following query: (Note that lstProjects is a List<Project>)
var lstUsers = (from users in lstProjects
where users.ProjectId == pId
select users.Users).ToList();
I have a List<Users> object and want to populate this List with items. Like,
var lstUsersToDisplay = new List<Users>();
lstUsersToDisplay = (List<Users>)lstUsers; //This can't be cast.
What's the approach to convert ICollection<T> to List<T>?
Secondly, I have List<Users> and want to convert it into ICollection<Users> how achieve this?
Edited:
Scenario, more clearly is that
All Projects are loaded in lstProjects and we need to select the Users which were mapped to a specific project. These Users are also are contained inside Projects as collection. Every Project has its Users collection like if I decomposed the lstProjects it would be like:
lstProjects --> [0]-->//other Properties
ICollection[Users]-->[0]//Contains User class Properties
[1]....
[1] ... same procedure
Hope it clears the scenario
If your query is genuinely this:
var lstUsers = (from users in lstProjects
where users.ProjectId == pId
select users.Users).ToList();
then that's equivalent to:
List<ICollection<Users>> lstUsers = (from users in lstProjects
where users.ProjectId == pId
select users.Users).ToList();
If you're trying to get the list of uses from a single project, I'd write that as:
var lstUsers = lstProjects.Single(project => project.ProjectId == pId)
.Users
.ToList();
If there could be multiple projects with the same ProjectId, you want to flatten the users. For example:
var lstUsers = lstProjects.Where(project => project.ProjectId == pId)
.SelectMany(project => project.Users)
.ToList();
Or in query expression syntax:
var lstUsers = (from project in lstProjects
where project.ProjectId == pId
from user in project.Users
select user).ToList();
Note the fact that my range variable is called project, because it refers to a project, not a user. Naming is important - pay attention to it. I would also rename the Projects and Users types to just Project and User, assuming each is really only meant to represent a single entity.
lstUsers isn't a List<User>. It's a List<ICollection<User>>. You map each project to a sequence of users, not to a single user. To flatten a collection of collections into just a collection of the inner items you would use SelectMany, or, in query syntax, you'd write out your query like so:
var lstUsers = (from project in lstProjects
where project.ProjectId == pId
from user in project.Users
select user).ToList();
Now you have a List<User> for lstUsers. You can assign that as is to a List<User> or an ICollection<User>
using System.Linq; //include extension method OfType<> for ICollection
...
List<Projects> userList = lstUsers.OfType<Projects>().ToList();
Related
want to retrieve data from multiple tables to service layer as I have to write database logic into service layer into my project
'KeysPlus.Service.Models.QuoteModel' to 'System.Collections.Generic.IEnumerable'.
An explicit conversion exists (are you missing a cast?)
Any help is highly appreciated!
public static IEnumerable<QuoteModel> GetJobQuotes(Login login, QuoteModel model)
{
using (var db = new KeysEntities())
{
var quotes = db.JobQuote.Where( x=> x.ProviderId == login.Id);
model = (from q in db.JobQuote
join j in db.Job on q.JobId equals j.Id
join p in db.Property on j.PropertyId equals p.Id
join a in db.Address on p.AddressId equals a.AddressId
select new QuoteModel
{
JobDescription=j.JobDescription,
QuoteAmount=q.Amount,
PropertyAddress= a.City
}).ToList();
return model;
}
}
You have a parameter in your method named model which is a single QuoteModel and you trying to set its value to a collection of QuoteModel. Remove that parameter (you not using it) and change the code to
using (var db = new KeysEntities())
{
var quotes = db.JobQuote.Where( x=> x.ProviderId == login.Id);
IEnumerable<QuoteModel> model = (from q in db.JobQuote
....
}
You have a model instance:
QuoteModel model
And you're trying to set it to a collection of model instances:
model = (from q in db.JobQuote
...
).ToList();
An apple is not a basket of apples. So you need to do one of two things, depending on what you actually want this method to do...
Return one model?
If you're looking for a specific instance from that list, then you need to add a clause to the query to return just that instance. Methods like .First() or .FirstOrDefault() can do that (or the .Single() equivalents). For example, if you want an instance which matches a specific value, it might look something like this:
model = (from q in db.JobQuote
...
).First(j => j.ID == someIdentifier);
Where of course someIdentifier is some value you have which you can use in the query. Perhaps model.ID or something like that? Depends on how you want to query your data, which we don't know here. But the point is that you need to return one model, not many models.
Additionally, you'd need to change the method's return type to QuoteModel, since you'd just be returning that one model instance.
Return many models?
Conversely, if you do want to return multiple models, then you can't put them in a variable which holds only one model. Just return the value directly:
return (from q in db.JobQuote
...
).ToList();
(Of course, then you're not even using the model variable, so why require it?)
So I am trying to filter the modules object list by userID of the currently logged in user. After that I am trying to take the moduleID of those selected object.
Using that I want to filter the reports list to only those that contain a moduleID that matches any of the the previously obtained list of moduleID.
I'm not that particularly knowledgeable on Linq and this is what I came up with:
var name = User.Identity.GetUserName();
//gets the currently logged in user:
ApplicationUser currentUser =
(ApplicationUser)db.Users.Single(x => x.UserName == name);
//gets moduleID's for modules owned by current user:
var modules = (from i in db.Modules
where i.User == currentUser
select i.ModuleID);
var Reports = from u in db.Reports
where u.moduleID == modules
select u;
I'm having problems with the last portion trying to incorporate the contains method into the statement.
Any help would be appreciated.
You could simplify the multiple queries to one if I'm inferring your table structure correctly:
var name = User.Identity.GetUserName();
var reports = from r in db.Reports
join m in db.Modules on r.moduleID equals m.ModuleID
where m.User.UserName == name
select r;
You can't compare a int to a IEnumerable<int>. However you can check if the moduleID is found within the modules like this :
where modules.Contains(u.moduleID)
You're on the right track.
var Reports = from u in db.Reports
where modules.Contains(u.moduleID)
select u;
Or using lambda:
var reports = db.Reports.Where(u => modules.Contains(u));
You're close. In Linq its a little backwards from standard SQL. In its case you want to see if the report's module id is contained in the list of modules, so it would look like this:
var Reports = from u in db.Reports
where modules.Contains(u.moduleID)
select u;
Use the navigation properties if you have a one to many relation you could do directly in your Where clause:
var name = User.Identity.GetUserName();
var Reports = db.Reports.Where(x => x.Module.User.Name == name);
I supposed in the process developed is such that it must show all the movies that are into film tablen and showing off, but this is how I have tried to do this:
it must find out which genres have in users tablen where after to show the users who like the first.
//As I said, I have a session at the top of the code.
int brugerid = Convert.ToInt16(Session["id"]);
var result = (from f in db.films
//it must find out which genres have in users tablen where after to show the users who like the first.
//brugere are users
//gener It is the genes users like.
join usersgenerId in brugere.Fk_generId on gener.generId equals usersgenerId.BrugereId
select new
{
image_navn = ((f.imgs.FirstOrDefault(i => i.feature == true)).navn == null ? "default.png" : (f.imgs.FirstOrDefault(i => i.feature == true)).navn),
image_feature = f.imgs.Where(A => A.feature == true),
film_navn = f.navn,
film_id = f.filmId,
film_tekst = f.tekst,
film_gener = f.gener.navn
}).ToList();
RepeaterFilmList.DataSource = result;
RepeaterFilmList.DataBind();
Table information
Brugere the name
id = BrugereId
Fk_generId belonging to the genes that user has selected.
and many other
Gener is the name
has generId as id
As mentioned in the comment, the question really is: show all movies that is in the same genre that the user preferred and then show everything else.
Although the following approach might not be db efficient (too lazy to create the db for this, so I am simulating everything in memory and using Linq to Object to solve the issue), it can certainly be resolved by the following steps:
Get the recommendation (matching the user's movie genre preference) like so:
var recommendation =
from f in films
from ug in userGenres
where ug.UserId == user.Id && ug.GenreId == f.GenreId
select f;
Now that we know what the user preferred, we can further filter this to just the preferred films' Id... and use that to get the rest of the unpreferred films (basically anything not matching the preferred film Ids):
var recommendedFilmIds = recommendation.Select(f => f.Id);
var everythingElse =
from f in films
where !recommendedFilmIds.Contains(f.Id)
select f;
Finally, join them together using Union and injecting the nessary fields for display purpose like Genre.Name, etc. like so:
var filmList = recommendation.Union(everythingElse).Select(f => new {
f.Id,
f.Title,
Genre = genres.Where(g => g.Id == f.GenreId).Select(g => g.Name).First()
});
And there you have it, the combined list will now contains both preferred films first (at top), followed by unpreferred films afterward.
The simulated tables are as follows: films which contains its own Id and genreId and userGenres which contains many to many relationship between user and genre and a particular user object which contains the user id.
An example of this can be found at: https://dotnetfiddle.net/Skuq3o
If you use EF, and you have a navigation property to genre table and you want to include those table as part of the query, use .Include(x => x.genre) or whatever you call your genre table after from f in films to avoid n+1 select if you wish to include the genre info in the final select clause.
Hi I'm using linq to entity in my application. I need to get distinct records based on one column value "Name"
So I have a table similar like you can see below:
(User)
ID
Name
Country
DateCreated
I need to select all this items but uniques based on Name (unique). Is it possible to accomplish using linq, if so please show me how.
var items = (from i in user select new {i.id, i.name, i.country, i.datecreated}).Distinct();
The Distinct() method doesn't perform well because it doesn't send the DISTINCT SQL predicate to the database. Use group instead:
var distinctResult = from c in result
group c by c.Id into uniqueIds
select uniqueIds.FirstOrDefault();
LINQ's group actually creates subgroups of entities keyed by the property you indicate:
Smith
John
Mary
Ed
Jones
Jerry
Bob
Sally
The syntax above returns the keys, resulting in a distinct list. More information here:
http://imar.spaanjaars.com/546/using-grouping-instead-of-distinct-in-entity-framework-to-optimize-performance
The purely LINQ way that occurs is to group by name, select distinct groups by key, then select based on that.
from i in user
group new {i.ID, i.Country, i.DateRecord} by i.Name into byNmGp
select byNmGp.First();
Edit: Entity Framework is of course a very popular linq provider, but it doesn't handle First() well here, though the logically equivalent (in this case) FirstOrDefault() will work fine. I prefer First() when not forced into FirstOrDefault() by EF's limitations, because its meaning better matches what is sought here.
Another way is to define a helper class:
private class MyRecord : IEquatable<MyRecord>
{
public int ID;
public string Name;
public string Country;
public DateTime DateCreated;
public bool Equals(MyRecord other)
{
return Name.Equals(other.Name);
}
public override bool Equals(object obj)
{
return obj is MyRecord && Equals((MyRecord)obj);
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
/*...*/
var items = (from i in user select new MyRecord {i.ID, i.Name, i.Country, i.DateRecord}).Distinct();
This simply defines distinct differently. Performance will differ by whether the query provider can interpret that definition of equality or not. Convenience will differ based on whether you've similar LINQ queries doing much the same thing or not.
You can use something like this:
var distinctReports = reports.Select(c => c.CompanyCode)
.Distinct()
.Select(c => reports.FirstOrDefault(r => r.CompanyCode == c))
.ToList();
Here's another variation I ended up using which was based off the response from Svetlana. Shows an example of populating a GridView control with unique values. Thanks!
dataGridView_AnalyzeTestSuites.DataSource = (
from tr in _db.TestResults
where tr.TaskId == taskId
select new { TestSuiteName = tr.Test.TestSuite.Name }
).Distinct().ToList();
Hi here is how you can select distinct records with inner join. Hope it helps
var distinctrecords =
(entity.Table.Join(entity.Table2, x => x.Column, y => y.Column, (x, y) => new {x, y})
.Select(#t => new {#t.x.Column2, #t.y.Column3}))
.GroupBy(t => t.Column2)
.Select(g => g.FirstOrDefault());
I'm trying to create a linq query based on some dynamic/optional arguments passed into a method.
User [Table] -> zero to many -> Vehicles [Table]
User [Table] -> zero to many -> Pets
So we want all users (including any vechile and/or pet info). Optional filters are
Vehicle numberplate
Pet name
Because the vehicle and pet tables are zero-to-many, i usually have outer joins between the user table and the vehicle|pet table.
To speed up the query, i was trying to create the dynamic linq and if we have an optional argument provided, redfine the outer join to an inner join.
(The context diagram will have the two tables linked as an outer join by default.)
Can this be done?
I'm also not sure if this SO post can help me, either.
I think you are heading in the wrong direction. You can easily use the fact that LINQ queries are composable here.
First, you would always use the outer join, and get all users with the appropriate vehicles and pets:
// Get all the users.
IQueryable<User> users = dbContext.Users;
Then you would add the filters if necessary:
// If a filter on the pet name is required, filter.
if (!string.IsNullOrEmpty(petNameFilter))
{
// Filter on pet name.
users = users.Where(u => u.Pets.Where(
p => p.Name == petNameFilter).Any());
}
// Add a filter on the license plate number.
if (!string.IsNullOrEmpty(licensePlateFilter))
{
// Filter on the license plate.
users = users.Where(
u => u.Cars.Where(c => c.LicensePlace == licensePlateFilter).Any());
}
Note that this will not filter out the pets or cars that don't meet the filter, as it is simply looking for the users that have pets with that name, or cars with that plate.
If you are trying to change tables or joins of a LINQ to SQL query at runtime you need to do that with reflection. LINQ expressions are not special; same as working with any other object call - you can change the value of properties and variables at runtime, but choosing which properties to change or which methods to call requires reflecting.
I would add to that by pointing out dynamically creating LINQ expressions via reflection is probably a little silly for most (all?) cases, since under the hood the expression is essentially reflected back into SQL statements. Might as well write the SQL yourself if you are doing it on-the-fly. The point of LINQ is to abstract the data source from the developer, not the end-user.
This is how I do what you are asking...
var results = u from dc.Users
join veh from dc.vehicles on u.userId equals v.userId into vtemp from v in vtemp.DefaultIfEmpty()
join pet from dc.pets on u.userId equals p.userId into ptemp from p in ptemp.DefaultItEmpty()
select new { user = u, vehicle = v, pet = p };
if ( !string.IsNullOrEmpty(petName) )
{
results = results.Where(r => r.pet.PetName == petName);
}
if ( !string.IsNullOrEmpty(licNum) )
{
results = results.Where(r => r.vehicle.LicNum == licNum);
}