I inherited an ASP.NET MVC 4 app that is using Entity Framework and keep getting duplicate records on related tables. I haven't been able to figure out why this is happening and it only happens randomly.
The models are as such:
Company -> has many Users -> has many UserRoles
UserRoles references the Roles table which has a RoleId and Name.
It is duplicating entries in the Roles table. I have been trying to figure this out but am pretty new with EF and some of that.
UserRole.cs partial class:
public static bool UpdateUserRoles(int userId, List<int> roleIds)
{
using (var context = new ImageTrackerEntities())
{
var userRoles = context.UserRoles.Where(r => r.UserId == userId).ToList();
foreach (var role in userRoles)
{
// do not remove users from super admin role
context.Entry(role).State = EntityState.Deleted;
}
foreach (var id in roleIds)
{
var ur = new UserRole() {
RoleId = id,
UserId = userId
};
context.Entry(ur).State = EntityState.Added;
}
context.SaveChanges();
return true;
}
}
To notice whats happened more precisely , try to activate EF Log so you can see the SQL generated (If you are using EF6 (current version of course)). Something like this :
using (var context = new BlogContext())
{
//YOU NEED TO ADD THIS
context.Database.Log = Console.Write;
var blog = context.Blogs.First(b => b.Title == "One Unicorn");
blog.Posts.First().Title = "Green Eggs and Ham";
blog.Posts.Add(new Post { Title = "I do not like them!" });
context.SaveChanges();
}
This will generate the following output:
SELECT TOP (1)
[Extent1].[Id] AS [Id],
[Extent1].[Title] AS [Title]
FROM [dbo].[Blogs] AS [Extent1]
WHERE (N'One Unicorn' = [Extent1].[Title]) AND ([Extent1].[Title] IS NOT NULL)
-- Executing at 7/17/2015 10:55:41 AM -07:00
-- Completed in 4 ms with result: SqlDataReader
Related
Is it possible to use two context entities from two different database
Code connectiong to one entity:
Using one FoodSupplyEntities
using (var contextFood = new FoodSupplyEntities())
{
var _result = (from _FoodSupplyStatus in contextFood.FoodSupplyStatus
join _FoodQualityStatus in contextFood.FoodQualityStatus
But is it possible to join for example another table from a different entities from another server.?
Sample (Dont know but it might gosomething like this.)
using (var contextFood = new FoodSupplyEntities() and contextKitchenware = new KitchenwareEntities() )
{
var _result = (from _FoodSupplyStatus in contextFood.FoodSupplyStatus
join _KitchenwareSupplyStatus in contextKitchenware.KitchenwareSupplyStatus
Suppose you have 2 tables in 2 different databases:
User in Database1
Orders in Database2 where UserId of User table in database 1 is referring OrderedBy in Orders table.
I have Created 2 different context.
now i will create 2 queries for 2 different context and will make join on these queries on UserId and OrderedBy like:
List<OrderDetails> GetOrderDetails()
{
var users = this.TestDb1ModelUnit.GetRepository<User_Login>().GetAll();
var orders = this.TestDb2ModelUnit.GetRepository<OrderDetail>().GetAll();
var orderDetails = users.Join(orders,
usr => usr.User_Id,
ord => ord.OrderedBy,
(usr, ord) => new { usr, ord }
).ToList();
}
using (var dataContext = new realtydbEntities())
{
var user =
(
from aspnet_Roles rol in dataContext.aspnet_Roles.Include("aspnet_Users")
from aspnet_Users usr in rol.aspnet_Users
where rol.RoleId == roleID
select usr
);
return user.ToList();
}
I want use
usr.MemberShip.Email
MemberShip is a foreign table's foreign table.
aspnet_Roles->aspnet_Users->Membership.Email
but i got an error: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
How can i include the membership object to the result??????
You will most probably need to include the aspnet_Membership table that hangs off the aspnet_User table as below:
using (var dataContext = new realtydbEntities())
{
var user =
(
from aspnet_Roles rol in dataContext.aspnet_Roles.Include("aspnet_Users")
from aspnet_Users usr in rol.aspnet_Users.Include("aspnet_Membership")
where rol.RoleId == roleID
select usr
);
return user.ToList();
}
Some basics
I have two tables, one holding the users and one holding a log with logins.
The user table holds something like 15000+ users, the login table is growing and is reaching 150000+ posts.
The database is built upon SQL Server (not express).
To administer the users I got a gridview (ASPxGridView from Devexpress) that I populate from an ObjectDatasource.
Is there any general do’s and donts I should know about when summarizing the number of logins a user made.
Things are getting strangely slow.
Here is a picture showing the involved tables.
I’ve tried a few things.
DbDataContext db = new DbDataContext();
// Using foregin key relationship
foreach (var proUser in db.tblPROUsers)
{
var count = proUser.tblPROUserLogins.Count;
//...
}
Execution time: 01:29.316 (1 minute and 29 seconds)
// By storing a list in a local variable (I removed the FK relation)
var userLogins = db.tblPROUserLogins.ToList();
foreach (var proUser in db.tblPROUsers)
{
var count = userLogins.Where(x => x.UserId.Equals(proUser.UserId)).Count();
//...
}
Execution time: 01:18.410 (1 minute and 18 seconds)
// By storing a dictionary in a local variable (I removed the FK relation)
var userLogins = db.tblPROUserLogins.ToDictionary(x => x.UserLoginId, x => x.UserId);
foreach (var proUser in db.tblPROUsers)
{
var count = userLogins.Where(x => x.Value.Equals(proUser.UserId)).Count();
//...
}
Execution time: 01:15.821 (1 minute and 15 seconds)
The model giving the best performance is actually the dictionary. However I you know of any options I'd like to hear about it, also if there's something "bad" with this kind of coding when handling such large amounts of data.
Thanks
========================================================
UPDATED With a model according to BrokenGlass example
// By storing a dictionary in a local variable (I removed the FK relation)
foreach (var proUser in db.tblPROUsers)
{
var userId = proUser.UserId;
var count = db.tblPROUserLogins.Count(x => x.UserId.Equals(userId));
//...
}
Execution time: 02:01.135 (2 minutes and 1 second)
In addition to this I created a list storing a simple class
public class LoginCount
{
public int UserId { get; set; }
public int Count { get; set; }
}
And in the summarizing method
var loginCount = new List<LoginCount>();
// This foreach loop takes approx 30 secs
foreach (var login in db.tblPROUserLogins)
{
var userId = login.UserId;
// Check if available
var existing = loginCount.Where(x => x.UserId.Equals(userId)).FirstOrDefault();
if (existing != null)
existing.Count++;
else
loginCount.Add(new LoginCount{UserId = userId, Count = 1});
}
// Calling it
foreach (var proUser in tblProUser)
{
var user = proUser;
var userId = user.UserId;
// Count logins
var count = 0;
var loginCounter = loginCount.Where(x => x.UserId.Equals(userId)).FirstOrDefault();
if(loginCounter != null)
count = loginCounter.Count;
//...
}
Execution time: 00:36.841 (36 seconds)
Conclusion so far, summarizing with linq is slow, but Im getting there!
Perhaps it would be useful if you tried to construct an SQL query that does the same thing and executing it independently of your application (in SQL Server Management Studio). Something like:
SELECT UserId, COUNT(UserLoginId)
FROM tblPROUserLogin
GROUP BY UserId
(NOTE: This just selects UserId. If you want other fields from tblPROUser, you'll need a simple JOIN "on top" of this basic query.)
Ensure there is a composite index on {UserId, UserLoginId} and it is being used by the query plan. Having both fields in the index and in that order ensures your query can run without touching the tblPROUserLogin table:
Then benchmark and see if you can get a significantly better time than your LINQ code:
If yes, then you'll need to find a way to "coax" the LINQ to generate a similar query.
If no, then you are already as fast as you'll ever be.
--- EDIT ---
The follwing LINQ snippet is equivalent to the query above:
var db = new UserLoginDataContext();
db.Log = Console.Out;
var result =
from user_login in db.tblPROUserLogins
group user_login by user_login.UserId into g
select new { UserId = g.Key, Count = g.Count() };
foreach (var row in result) {
int user_id = row.UserId;
int count = row.Count;
// ...
}
Which prints the following text in the console:
SELECT COUNT(*) AS [Count], [t0].[UserId]
FROM [dbo].[tblPROUserLogin] AS [t0]
GROUP BY [t0].[UserId]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
--- EDIT 2 ---
To have the "whole" user and not just UserId, you can do this:
var db = new UserLoginDataContext();
db.Log = Console.Out;
var login_counts =
from user_login in db.tblPROUserLogins
group user_login by user_login.UserId into g
select new { UserId = g.Key, Count = g.Count() };
var result =
from user in db.tblPROUsers
join login_count in login_counts on user.UserId equals login_count.UserId
select new { User = user, Count = login_count.Count };
foreach (var row in result) {
tblPROUser user = row.User;
int count = row.Count;
// ...
}
And the console output shows the following query...
SELECT [t0].[UserId], [t0].[UserGuid], [t0].[CompanyId], [t0].[UserName], [t0].[UserPassword], [t2].[value] AS [Count]
FROM [dbo].[tblPROUser] AS [t0]
INNER JOIN (
SELECT COUNT(*) AS [value], [t1].[UserId]
FROM [dbo].[tblPROUserLogin] AS [t1]
GROUP BY [t1].[UserId]
) AS [t2] ON [t0].[UserId] = [t2].[UserId]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.1
...which should be very efficient provided your indexes are correct:
The second case should always be the fastest by far provided you drop the ToList() so counting can be done on the database side, not in memory:
var userId = proUser.UserId;
var count = db.tblPROUserLogins.Count(x => x.UserId == userId);
Also you have to put the user id into a "plain" primitive variable first since EF can't deal with mapping properties of an object.
Sorry, doing this blind since I'm not on my normal computer. Just a couple of questions
do you have an index on the user id in the logins table
have you tried a view specifically crafted for this page?
are you using paging to get the users, or trying to get all counts at once?
have you run sql profiler and watched the actual sql being sent?
Does something like this work for you?
var allOfIt = from c in db.tblProUsers
select new {
User = c,
Count = db.tblProUserLogins.Count(l => l.UserId == c.UserId)
}
.Skip(pageSize * pageNumber)
.Take(pageSize) // page size
Let's say have 3 tables:
Category
-------------
CategoryID int
Title text
Admin
------------
AdminID int
FullName text
Permission
------------
CategoryID int
AdminID int
AllowAccess bit
When i try to update changes to database i got following exception:
Unable to insert or update an entity because the principal end of the 'KiaNetModel.FK_Permissions_Admins' relationship is deleted.
WHY?
The function that update changes:
public static void SetPermissions(int[] cats, int userId, Entities context)
{
var premissions = from p in context.AdminPremissions where p.AdminID == userId select p;
// Clear all premissions...
foreach (var p in premissions)
{
p.AllowAccess = false;
}
foreach (var c in cats)
{
var es = from e in context.AdminPremissions where e.CategoryID == c && e.AdminID == userId select e;
// If any pre permission was found, set flag = true
if (es.Count() > 0)
es.First().AllowAccess = true;
// Otherwise add new one
else
context.AdminPremissions.AddObject(new AdminPremission() { AdminID = userId, CategoryID = c, AllowAccess = true });
}
}
It's an web application, and when user mark permissions, i could only determine which permissions are set, not all of them.
If you have any other idea, or better way please tell me.
I think relationship between tables Permission and Admin has been deleted from either Actual database or from Entity Model. It it is the case then u have to create that relationship again.
Generate "Admin" Table And "Permission" Drop And Create Script (With Data - If U Have Data On it).
Then Execute It, If U Have Relation Re Create It,
Ur Prb Must Be Solve.
I have a WPF app with a local .MDF file on which I created an Entity Framework class model.
Retrieving entities from the database works fine:
//get entities
using (var context = new TestDataEntities1())
{
var customers = from c in context.Customers
select c;
foreach (var customer in customers)
{
TheCustomers.Add(customer);
}
}
However, updating and adding and deleting* do not. There is **no error, the debugger steps right through, no messages in Output, but the data in the database table remains unchanged.
//update entity
using (var context = new TestDataEntities1())
{
var customer = (from c in context.Customers
where c.Id == 1
select c).FirstOrDefault();
customer.FirstName = DateTime.Now.ToString();
int num = context.SaveChanges(); //returns 1, table unchanged
}
//add entity
using (var context = new TestDataEntities1())
{
var customer = new Models.Customers();
customer.FirstName = "Ned";
customer.LastName = "Newton";
context.AddToCustomers(customer);
int num = context.SaveChanges(); //returns 1, table unchanged
}
//delete entity
using (var context = new TestDataEntities1())
{
var customer = (from c in context.Customers
where c.Id == 2
select c).FirstOrDefault();
context.Detach(customer); // table unchanged
}
What do I have to do to get Entity Framework to also update and add entities to the database table?
First, SaveChanges does not guarantee an update. It returns the # of rows changed. So check the return value. If it's 0, then the EF doesn't think it made an update. If it's > 0 then it does.
Second, you should profile SQL to see what the EF is sending.
If the result of SaveChanges is 0, then the cause is almost certainly that the EF doesn't think anything in the context is modified. Why that would be depends upon how your changes are tracked. Your code above looks correct for insert, but for update the ApplyPropertyChanges is superfluous and should be removed.
If the EF is sending SQL but the DB is doing nothing with it, you should examine the SQL for a fix.