LINQ - select query in related objects Entity Framework (EF4) - linq

For the following (I'm using EF4) I need to select all messages in a Thread (ContactThreadId) that were NOT yet read given LoginId
So, i based on ContactThreadId and LoginId I need to know if this LoginId has already read all messages in a Thread. If not I need to update ContactReadState with all messages from the thread with his/her LoginId and when she/he read it.
I've tried these but am stuck:
// Update read state
var thread = this.contactMessageThreadRepository.GetRow(id);
var loginEntity = this.loginRepository.GetRow(ProfileContext.LoginId);
var unreadMsg = loginEntity.Contact
.Where(x => x.ContactThread.Any(y => y.ContactThreadId == id))
.Select(b => b.ContactMessage.FirstOrDefault())
.Where(q => q.ContactReadState.Count() == 0);
var unreadMsg = loginEntity.Contact
.Where(x => x.ContactThread.Any(y => y.ContactThreadId == id))
.Where(y => y.ContactReadState.Any(q => q.ContactId != loginEntity.ContactId));
var msg = thread.Contact
.Where(x => x.LoginId == loginEntity.LoginId)
.Where(y => y.ContactReadState.Count() == 0);
please help.
thanks
EDIT:
Login - this table hols logins/admin records
Contact - this table holds all contacts (including Login items because Logins can also participate in a conversation-can reply to messages etc.) When a LoginId in a contact table is NOT NULL, it means it's a Login user otherwise it's a public user submitting a message.
QUESTION -> Each Login can have only 1 Contact record (I have a trigger that creates a Contact record upon Login creation). How do I make it so that it's 1 to 1.??
I've added a FK from Contact to Login table but for some reason EF created 0..1 -> * association. And it should be 1 to 1. For a given Login there can be only 1 Contact with that LoginId.
Whenever Login is viewing a list of messages a new record is inserted to ContactReadState for that Login (marking a message read by that Login (with ContactId for that Login).

I have a fragment, but can't put it completely together. Especially I don't know how you would set the ContactId in the new ContactReadState objects (see ??? below) because apparently a given loginId can have many contacts. So, which one to set in the new read states? Probably I misunderstood something in your model, because all those relationships look very complicated to me.
...based on contactThreadId and loginId...
I'm using a context directly, you need to translate this into your repository structure:
using (var context = new MyContext())
{
var unreadMsgs = context.ContactMessages
.Where(cm => cm.ContactThreadId == contactThreadId
&& !cm.ContactReadState
.Any(crs => crs.Contact.LoginId == loginId))
.ToList();
// These should be the unread messages you want to select.
// Now, updating ContactReadState:
foreach(var unreadMsg in unreadMsgs)
{
var newContactReadState = new ContactReadState
{
ContactMessageId = unreadMsg.ContactMessageId,
ContactId = ???,
ReadDate = DateTime.Now
};
context.ContactReadStates.AddObject(newContactReadState);
}
context.SaveChanges();
}
Edit
If I understand correctly there can be contacts without login but if there is a login it is uniquely assigned to a contact.
Creating such a one-to-one relationship in EF correctly requires the following:
You must remove the LoginId column and the corresponding relationship from your Contact table (it's the reason for the one-to-many relationship EF creates).
The LoginId primary key column in the Login table must not be an autogenerated identity.
You must create a foreign key relationship between Contact and Login table where the foreign key column in Login is the primary key column LoginId at the same time. So, the relationship is between Login.LoginId (the "dependent" with the FK) and Contact.ContactId (the "principal" with the PK).
This would mean that a Login with LoginId=x refers to a Contact with ContactId=x (same value) which finally makes it easy to fill the ??? in the code snippet above: ??? is simply = loginId.
Edit 2
...and of course you can replace then in the query ...
.Any(crs => crs.Contact.LoginId == loginId)
...by...
.Any(crs => crs.ContactId == loginId)
(which avoids an unnessacary join to the Contact table)

Related

Entity Framework model.edmx and many to many relationships

In the database I have 3 tables, User, Group and a lookup table UserGroup which contains UserID and GroupId.
I create a model.edmx and this allows me to:
var users = context.User
var groups = context.Group
but does not create an object for context.UserGroup.
what is the syntax for getting all the users in a group, and all the groups that a user belongs to?
var results = from groups in db.Groups.Where(t => t.Users(u => u.UserID ==1))
select groups;
If you have the proper keys setup, EF will hide away your junction table, and create a navigation property to make the connection between the tables
For getting all the groups a user belongs to:
var groupResults = db.Groups.Where(g => g.Users.Select(u => g.UserId).Contains(userId));
and for getting all the Users:
var userResults = db.Users.Where(u => u.Groups.Select(g => g.GroupId).Contains(groupId));
The junction table will not be created. You'll get two navigation collection properties. Groups in User entity and Users in Group entity.
To get all users from a group:
var usersInGroup = context.Groups.Where(g => g.ID == groupId).SelectMany(g => g.Users);
To get all groups the user belongs to:
var groupsOfUser = context.Users.Where(u => u.ID == userId).SelectMany(u => u.Groups);

How to update with Entity Framework in asp.net mvc3?

I Have a table in my databse that one of the columns named NumOfView shows the number of clicks on a link. That link shows some info from a row in this table. I used onclick event in anchor tag like this:
onclick=#Url.Action("NumOfClicks", "AdvertiseHelper",new { id = Model.id[i] })
In NumOfClicks function I used this code
public void NumOfClicks (int id)
{
Ad ad1 = new Ad();
var advert = (from ad in storedb.Ads where ad.AdId == id select ad.NumOfView).First();
advert += 1;
}
advert
is the amount of
NumOfView
in table that I want to increase it 1 unit. but I don't know how to continue coding for update this value in table. Can anybody help me please?
This is the basics of how it should be done. First you have to select the record itself from the database rather than the number of clicks. Increment the number of clicks on that record, then submit the changes to the DataContext.
public void IncrementClickCount(int id)
{
var advert =
(from ad in storedb.Ads
where ad.AdId == id
select ad).Single(); // Select the row in the database represented by "ad"
advert.NumOfView++; // Perform the increment on the column
// SubmitChanges is how an update is done in Linq2Sql
// This requires a .dbml file for the database object file
// storedb.SubmitChanges(); // Assumes storedb is a valid DataContext, updates
// SaveChanges is how an update is done in EntityFramework
// It is recognizable because it uses an .edmx file for its database object
storedb.SaveChanges();
}
This was similarly asked in SO question: Entity Framework - Update a row in a table

Entity Framework Many-To-Many Join Query

I've got a standard social networking paradigm where a User has a collection of friends who are also users.
I'm using Entity Framwork Code First, and my Friend Relationship is defined as follows:
modelBuilder.Entity<User>()
.HasMany(u => u.Friends)
.WithMany()
.Map(m =>
{
m.ToTable("Friendships");
m.MapLeftKey("UserId");
m.MapRightKey("FriendId");
});
What I want to do is to search my users table returning all users with an indicator of whether each returned user is friends with the current user. To be clear, I want to return Users who are Friends and Users who are not friends, but also with a boolean indicating whether each user is a friend. I know how to do this in TSQL its a basic left outer join.
I've seen examples of how to do a left join in LINQ, but all the examples I've seen are joining to a mapped type. My Friendships column doesn't have a Mapped type.
How do I do this in EntityFramework?
var list = context.Users
.Where(u => u.Age >= 20) // sample condition, if you want ALL remove the line
.Select(u => new
{
User = u,
FriendOfCurrentUser = u.Friends.Any(f => f.UserId == currentUserId)
})
.ToList();
Result is a list of anonymous objects containing the user and the boolean friendship indicator. You can also create a helper class UserWithFriendship and project into it (Select(u => new UserWithFriendship { ... }) instead of an anonymous type.

Can I filter the Users returned by GetAllUsers based on a role they are in

I am trying to create an administration interface where users and roles (among other things) can be administered. I have a list of users who can be edited, deleted or viewed. I have this code in the action:
var model = Membership.GetAllUsers()
.Cast<MembershipUser>()
.Select(x => new UserModel
{
UserName = x.UserName,
Email = x.Email,
UserRoles = Roles.GetRolesForUser(x.UserName)
});
return View(model);
This is all fine except that I don't want admins to be able to edit each other. So I need to filter out all users in the "super admin" role. I can certainly figure this out by stepping through each role for each user to see if they are a member. I am wondering if there is a nice sucinct way to do this by filtering the result set in the Select statement, or using Except or Where
I would normally think about the sql I want generated then try write the linq, filtering by roles should be fairly easy with a simple where statement.
However it appears you're trying to abstract each part of the query into smaller bits, this may make it easier to write but can have a devastating effect on performance. For example, I wouldn't be suprised if the GetRolesForUser method you are calling causing an extra database query per user that is returned by GetAllUsers, using the Include method is a much nicer way to get all roles at the same time.
var model = context.Users
.Include(user => user.UserRoles)
.Where(user => !user.UserRoles.Any(role => role == superAdmin)
.Select(user => new UserModel() { UserName = user.UserName, Email = user.Email, UserRoles = user.UserRoles});

Foreign key relationships in Entity Framework v.1

I need to be to create an entity data model in the EF version 1, because my web host doesn't have Framework 4.0 yet. Below is just a simple example to show the problem.
I have 3 tables, one Users table, another Webpages table, and one table with Visits. The former two tables each have a one-to-many relationship with the Visits table (which basically works as a many-to-many relationship, only the Visits table has its own primary key and extra fields)
With the 4.0 version this works, but it doesn't with v.1. "Visits" has a count of 0, so the test string returns ""... Why, and how would I be able to access the foreign key relation in v.1?
UsersEntities context = new UsersEntities();
var users = context.Users;
string result = "";
foreach (var user in users)
{
foreach (var visit in user.Visits)
{
result += visit.Webpage.Url + "\n";
}
}
So the foreach loop loops through the users, which it gets ok, but the inner loop is never entered because there are no Visits returned. Again, in Framework 4.0 it works fine, using the same database.
So what's wrong?
Simply change your code to this:
UsersEntities context = new UsersEntities();
var users = context.Users.Include("Visits");
string result = "";
foreach (var user in users)
{
foreach (var visit in user.Visits)
{
result += visit.Webpage.Url + "\n";
}
}
Notice the Include(...) that tells EF to eagerly load each User's visits.
With that in place it should work.
Actually if Webpage is a navigation too, you might need:
Include("Visits.Webpage");
Hope this works

Resources