NHibernate .SelectList() with List<string> in C# - c#

I have a database request which looks as follows:
var userHasProfessions = xy.GetUserProfessions();
var users = sessionService.GetDefaultSession()
.Query<User>()
.Where(a => userProfessions.Contains(a.Profession.Id))
.ToList();
It gets all users that the requesting user is allowed to see, depending on his own profession. Now I wanna restrict that a little more, that he can only see some attributes of the users. Let's say for example:
id -> yes
firstname -> yes
lastname -> yes
address -> no!
Now I tried t change the query to something like:
var userHasProfessions = xy.GetUserProfessions();
var users = sessionService.GetDefaultSession()
.QueryOver<User>()
.SelectList(list => list
.Select(a => a.id)
.Select(a => a.firstname)
.Select(a => a.lastname))
.Where(a => userProfessions.Contains(a.Profession.Id))
.ToList();
Now my question... Is there a way to, for example, make a new List with these attributes and then loop through it? Something like that:
List<string> attributes = new List<string>(){"id", "firstname", "lastname"}
var userHasProfessions = xy.GetUserProfessions();
var users = sessionService.GetDefaultSession()
.QueryOver<User>()
.SelectList(
//loop through attributes
)
.Where(a => userProfessions.Contains(a.Profession.Id))
.ToList();
Thanks in advance :-)
EDIT
To make my question a little bit more clear. I wanna have the attributes that the user is allowed to see, dynmically changeable from a List<string> outside the query.
How can a achieve that?

You could do
.Where(a => userProfessions.Contains(a.Profession.Id))
.Select(c => new User {
id = c.id,
firstname = c.firstname,
lastname = c.lastname,
address c.address
}).ToList();
I am assuming list is type of User. Other wise you could use anonymous return i.d. c => new { id="id",... }

Related

LINQ efficiency

Consider the following LINQ statements:
var model = getModel();
// apptId is passed in, not the order, so get the related order id
var order = (model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId));
var orderId = 0;
var orderId = order.LastOrDefault();
// see if more than one appt is associated to the order
var apptOrders = (model.getMyData
.Where(x => x.OrderId == orderId)
.Select(y => new { y.OrderId, y.AppointmentsId }));
This code works as expected, but I could not help but think that there is a more efficient way to accomplish the goal ( one call to the db ).
Is there a way to combine the two LINQ statements above into one? For this question please assume I need to use LINQ.
You can use GroupBy method to group all orders by OrderId. After applying LastOrDefault and ToList will give you the same result which you get from above code.
Here is a sample code:
var apptOrders = model.getMyData
.Where(x => x.ApptId == apptId)
.GroupBy(s => s.OrderId)
.LastOrDefault().ToList();
Entity Framework can't translate LastOrDefault, but it can handle Contains with sub-queries, so lookup the OrderId as a query and filter the orders by that:
// apptId is passed in, not the order, so get the related order id
var orderId = model.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => y.OrderId);
// see if more than one appt is associated to the order
var apptOrders = model.getMyData
.Where(a => orderId.Contains(a.OrderId))
.Select(a => a.ApptId);
It seems like this is all you need:
var apptOrders =
model
.getMyData
.Where(x => x.ApptId == apptId)
.Select(y => new { y.OrderId, y.AppointmentsId });

How to select data only with a unique email field?

I need to select data from a table. The data has an Email field which is not unique. Now i only want to select the first item with an Email of its kind and ignore the others.
I tried:
var users = _context.Appointments.Where(p => (p.userId == userId))
.Select(p => new MyUserModel
{
Id = p.Id,
Email = p.User.Email
});
return users.ToList();
I wanted to use Distinct(), but my elements are not unique, they have a different id.
How could I go about doing that?
However, if this field is repeated, then I do not need to select this
element
You can group by the email and then perform a filter to retain the objects that don't repeat by email and then follow it with your current logic. Example:
var users = _context.Appointments
.Where(p => p.userId == userId)
.GroupBy(p => p.User.Email)
.Where(g => g.Count() == 1) // if there is only one object with this email, then retain it otherwise discard it
.Select(g => g.First())
.Select(p => new MyUserModel
{
Id = p.Id,
...
Email = p.User.Email
...
});
return users.ToList();

Add a Join to this LINQ Query?

So after what felt like a lot of head banging, I have this query:
var widgets = db.Updates
.Where(c => c.Sold.Equals(false))
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).First()).ToList();
widgetGrid.DataSource = widgets;
widgetGrid.DataBind();
Now that I have all the sold widgets I need to add a join, let's say for instance that I want to join the the "Owner" table on ID in Owner equals ID in Widgets and then select Owner.Name and Widget.Style
For the life of me, I seem to be getting nowhere fast... anyone?
As always... I'm deeply grateful for anyone's time in helping me clear out my cobwebs.
If I understand you correctly, you have two sequences:
a sequence of Widgets, where each widget has a property Id.
You have a sequence of Owners, where each owner has a property Id
And you want the combination of sequences and owners that have a matching Id.
By the way, probably your widget will have an ownerId or your owner will have a widgetId, but that won't influence the solution.
The join will be as follows:
var joinedTable = widgets.join(owners, // join table widgets with table owners
w => w.Id // from widgets take the Id
o => o.Id // from owners also take the Id
(widget, owner) => new // where those Ids match, take the owner and the widget
{ // and take the properties you want
Id = widget.Id,
MyXProperty = owner.X,
MyYProperty = widget.Y,
Widget = widget, // or take the complete widget and owner
Owner = owner,
});
By the way, you write "Now that I have all the sold widgets". From your piece of code I understand that each Update has a Boolean property Sold and that you want all Updates where !Sold. I'd assume you end up with items that are not sold?
What is the advantage of your predicate in the where clause. Why isn't it:
var widgets = db.Updates.Where(c => !c.Sold)
.GroupBy // etc.
You could do this:
var widgets = db.Updates
.Where(c => !c.Sold)
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).FirstOrDefault());
var result= (from w in widgets
join o in db.Owners on w.OwnerId equals o.Id
select new {o.Name, w.Style}).ToList();
you may also try:
var widgets = db.Updates
.Where(c => c.Sold.Equals(false))
.GroupBy(c => c.widgetType)
.Select(x => x.OrderByDescending(y => y.TimeStamp).First())
.Join( db.Owners,
u => u.ID,
o => o.ID,
(u, o) => new { o.Name, u.Style }).ToList();

LINQ: join between results of two separate contexts

I know LINQ doesn't support two diff contexts in a standard 'join'.
Having said that, what I'm trying to do is, pull together a list of, shall we say, 'employees', from a 'user' and 'contact' contexts.
(These are edmx's that are from an old project, that I'm not about to mess with.)
Thing is, 'users' is WHO I want to get, but their demographics reside inside the 'contacts'. Here's the two current LINQ's:
var users = _pets_dc.Users
.Select(p => p)
.Where(x => x.Active)
.ToList();
var contacts = _poems_dc.Contacts
.Select(p => p)
.Where(x => x.Active)
.ToList();
I need contacts where 'user.Contact_GUID' equals 'contacts.Contact_GUID'.
I have tried:
var query = contacts
.Where(x => x.Contact_GUID == users
.Select(y => y.Contact_GUID)
.FirstOrDefault());
to no avail... this only brings back one contact, but won't work without .FirstOrDefault(). Any ideas?
If you are using Contact_GUID in both tables if you have FK in users table try using first query with include
var users = _pets_dc.Users.Include("Contacts")
.Where(x => x.Active)
.ToList();
you can try the following anyway:
var joined = from list1 in users
join list2 in contacts
on list1.Contact_GUID equals list2.Contact_GUID
select new { list1, list2 };
ref : https://stackoverflow.com/a/2724018/1166597
You can use below code:
var result = users.Select(e => contacts.Where(x => x.Contact_GUID == e.Contact_GUID));
Joining is one of the option that would work here, but you can modify your current solution as follows:
var query = contacts
.Where(x => users
.Select(y => y.Contact_GUID).Contains(x.Contact_GUID)
).FirstOrDefault());
Contains will check the Guid in a given list, in original solution you are comparing Guid with List<Guid>, which would fail
Option 1:
var query = from person in users
join contact in contacts on person.Contact_GUID equals contact.GUID into employees
from employee in employees.DefaultIfEmpty()
select new Employee() { User = person, Demographic = employee.Demographic };
var employees = query.ToList();
Option 2:
var query = from person in users
join contact in contacts on person.Contact_GUID equals contact.GUID into employees
from employee in employees.DefaultIfEmpty()
select new { person.FirstName, person.LastName, employee.Demographic };
var employees = query.ToList();

Compare in Linq

I have a bunch of data in a database that i want to write a search function for. The problem is that i'm getting many duplicates.
The data is structured in Names and Surnames and i want to only send one unique of both so if i have two people with the first name Foo, and surname Bar only one will show.
No matter how I think of it I always come back to that I need to compare them.
var names = db.People
.Where(r => r.Name.Contains(q))
.OrderBy(r=> r.Name)
*Psuedo-Code*
if((this.Name==next.Name)&&(this.surSame==next.Surname)
toss next data and loop to next
*Psuedo-Code*
.Take(5);
Maybe a bit messy, but you get the idea what I want to achieve. Can I do this in some way or is there any better way to go about it?
You could do this:
var names = db.People
.Where(r => r.Name.Contains(q))
.Select(r => new { Name = r.Name, Surname = r.Surname })
.Distinct()
.Take(5);
But if that won't work because you need the whole People record, you just want the first, I've done something like this with success:
var names = db.People
.Where(r => r.Name.Contains(q))
.GroupBy(r => new { Name = r.Name, Surname = r.Surname })
.Select(g => g.First())
.Take(5);
Distinct utilizing Equals on People class would be the correct way, but here's an alternative that is more "inline":
var names = db.People
.Where(r => r.Name.Contains(q))
.GroupBy(r => new { r.Name, r.Surname })
.Select(g => g.First())
.OrderBy(r => r.Name)
.Take(5);
Use Distinct() and implement the method Equals in People class, or use an auxiliary class to compare them:
public class PeopleComparer : IEqualityComparer<People>
{
public bool Equals(People x, People y)
{
return x.Name == y.Name && x.Surname == y.Surname;
}
public int GetHashCode(People obj)
{
unchecked
{
return (obj.Name.GetHashCode() * 31) + obj.Surname.GetHashCode();
}
}
}

Categories

Resources