MVC inserting multiple records instead of expected one - asp.net-mvc

Let's say I have two models:
public class User
{
[Key]
public int UserId { get; set; }
public string Name { get; set; }
}
and
public class Friend
{
[Key]
public int FriendId { get; set; }
public User A { get; set; }
public User B { get; set; }
}
Let's say I only have 2 users in my database (ids: 1 (Jon) and 2 (Sam)). Now I insert into table friend like this:
db.Friends.Add(new Friend()
{
A = db.Users.Find(1),
B = db.Users.Where(u => u.UserId == 2).First()
});
db.SaveChanges();
Suddenly, I find a user (3, Sam) in a table user. What is the reasoning behind this? Not completely sure if relevant or not, but note that even if I make A and B fields virtual, nothing changes.
UPDATE
Finally found how to reproduce my problem. Apparently the problem isn't exactly the same as I described.
User a, b;
using (var db = new DbConnection())
{
a = db.Users.First(u => u.UserId == 1);
b = db.Users.First(u => u.UserId == 2);
}
using (var db = new DbConnection())
{
db.Friends.Add(new Friend()
{
A = a,
B = b
});
db.SaveChanges();
}
Now users will have 4 users. Does it mean that if I step out of transaction, I can no longer access the entities as if they were exactly the same items in the current transaction? Or maybe there is a way to make the program know that I am referring to the same item (because the ID is the same)?

Honestly tried the same steps as you described and everything work well.. Anyway my steps
Created a db context class derived from `DbContext'
public class EFContext : DbContext
{
public DbSet<Friend> Friends { get; set; }
public DbSet<User> Users { get; set; }
public EFContext(string connectionString)
: base(connectionString)
{
}
}
I use MSQL2008 Express with win auth so I created the Users table
using (var db = new EFContext(#"Data Source=yourMachineName\SQLEXPRESS2008;Initial Catalog=DBName;Integrated Security=True;MultipleActiveResultSets=True"))
{
db.Users.Add(new User()
{
UserId = 1,
Name = "John"
});
db.Users.Add(new User()
{
UserId = 2,
Name = "Sam"
});
db.SaveChanges();
}
I checked my db and found 2 records
After I created the Friends table
using(var db = new EFContext(#"Data Source=yourMachineName\SQLEXPRESS2008;Initial Catalog=DBName;Integrated Security=True;MultipleActiveResultSets=True"))
{
db.Friends.Add(new Friend()
{
A = db.Users.Find(1),
B = db.Users.Where(u => u.UserId == 2).First()
});
db.SaveChanges();
}
Again I got 1 record in the Friends table with columns FriendId=1, A_UserId=1, B_UserId=2.
I checked the Users table and I still have 2 records.
If I were you I would try my code in a separate app. If it works then please post here all steps which led you to this problem.

Related

problem Viewmodel and LINQ query in asp.net mvc

I am developing an application in asp.net MVC, and for show multi-table in the same view, I have created one big ViewModel which contains the three models (employee, user, and request)
now my problem is my query that not work, and I can't locate the problem
Thank you for your help
Sorry for my english is not good
My bigviewmodel
namespace freegest.Models
{
public class ControleViewModel
{
public List<employe> employes { get; set; }
public List<demande > demandes { get; set; }
public List<utilisateur> utilisateurs { get; set; }
}
}
My query
public ActionResult listdemande()
{
int id = Convert.ToInt32(Session["id_utilisateur"]);
ControleViewModel CV = new ControleViewModel();
CV = (from a in CV.utilisateurs
join b in CV.demandes
on a.id_utilisateur equals b.idutilisateur_demande
join c in CV.employes
on a.idemploye_utilisateur equals c.id_employe
orderby c.nom_employe ascending
where a.id_utilisateur == id
select new ControleViewModel
{
c.nom_employe ,
});
return View(CV);
}
Try the following approach to join multiple tables using LINQ:
public ActionResult Index()
{
using (DBEntities db=new DBEntities())
{
List<Employee> employees = db.Employees.ToList();
List<Department> departments = db.Departments.ToList();
List<Incentive> incentives = db.Incentives.ToList();
var employeeRecord = from e in employees
join d in departments on e.Department_Id equals d.DepartmentId into table1
from d in table1.ToList()
join i in incentives on e.Incentive_Id equals i.IncentiveId into table2
from i in table2.ToList()
select new ViewModel
{
employee=e,
department=d,
incentive=i
};
return View(employeeRecord);
}
}

How increment ID automatic in mvc

Recently I have faced with an issue in mvc. My problem is about how increment a value of field which is unique,primary and int. For example , I have a customerCode as int and I want to increment a value of that after saving new customer . I get that mvc first check id and if its equal to zero ,then increment it to max+1. But the issue is here: if I want to increment it like Max+4, how can I handle it?
this is my code:
public ActionResult Save(Customers customer)
{
if (!ModelState.IsValid)
{
var _Customer = new CreatnewCustomerViewModel()
{
Customer = customer,
membershiptype = _context.membershiptype.ToList()
};
return View("CustomerForm", _Customer);
}
if (customer.CustomerID==0)
{
//int id = _context.customers.Max(m => m.CustomerID);
//customer.CustomerID = id + 1;
_context.customers.Add(customer);
}
else
{
var CustomerIndb = _context.customers.Single(c => c.CustomerID == customer.CustomerID);
{
CustomerIndb.Name = customer.Name;
CustomerIndb.birthday = customer.birthday;
CustomerIndb.IsSubscribedToNewsletter = customer.IsSubscribedToNewsletter;
// CustomerIndb.MembershipType = customer.MembershipTypeID;
CustomerIndb.MembershipTypeID = customer.MembershipTypeID;
}
}
_context.SaveChanges();
return RedirectToAction("index", "Customer");
}
Write your Customers model class as follows:
public class Customers
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CustomerID { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CustomerCode { get; set; }
public string Name { get; set; }
// Other properties
}
Now generate a new migration and update the database accordingly!
Now if you want to set Identity Increment more than 1, then go to the database with SQL Server Management Studio, open the the Customers table. Right click on CustomerCode column and then select properties. Now set the Identity Increment value (default is 1) to your desired value.
you can easily solve that problem with the help of DatabaseGeneratedOption.Identity and Sql() method in the Up() .
If you new to both of above concepts , Here is the links with clear instructions
https://forums.asp.net/t/2062551.aspx?Entity+Framework+How+to+set+a+start+value+for+an+Auto+Incremented+Column+
Addtional:
How to set initial value for auto incremented property (DatabaseGeneratedOption.Identity)
Hope it will help to get rid of the problem, let me know your status.
Thanks

How do I loop through an array and add each value to my model variable? MVC Razor

I am trying to make a variable in my model that retrieves all available skills to later display them in a DDL. I have one variable that contains all of the skills and one variable that displays all of the skills an employee has already rated. I want to check all of the skills against the rated skills so that only the unrated skills are added to the new variable in the model. The only way I could think of to do this is to use a foreach loop to check for the values in the AllSkills variable.
model:
public IEnumerable<long> AvailableSkills { get; set; }
public IEnumerable<long> AllSkills { get; set; }
public IEnumerable <long> EmployeeRatings { get; set; }
public IEnumerable<Rating> Ratings { get; set; }
public IEnumerable<Skill> Skills { get; set; }
public long SkillId { get; set; }
Controller:
model.AllSkills = db.Skills.OrderBy(s => s.SkillName).Select(s => s.SkillId);
model.EmployeeRatings = db.Ratings.Where(r => r.EmployeeId == User.Identity.Name.Remove(0, 8)).OrderBy(s => s.SkillId).Distinct();
foreach (var skill in model.EmployeeRatings)
{
model.AvailableSkills = model.AllSkills.Where(s => s != skill);
}
I want to do something like the following code in the foreach loop:
model.AvailableSkills += model.AllSkills.Where(s=> s != skill); but this is not allowed.
The problem is that this for each loop above is assigning the model.AvailableSkills to the every skill but the last one that is in the foreach loop (as it should). How do I make it so that every one of the duplicate skills are excluded from model.AvailableSkills?
Using LINQ is IMO more readable if you use to query syntax opposed to the method chaining syntax.
model.AllSkills =
from skill in db.Skills
orderby skill.SkillName
select skill.SkillId;
model.EmployeeRatings =
from rating in db.Ratings
let employeeId = User.Identity.Name.Remove(0, 8)
where rating.EmployeeId == employeeId
orderby rating.SkillId
select rating.SkillId
You can use the Except() extension method to remove items from the collection.
// exclude the 'owned' skils
model.AvailableSkills = model.AllSkills.Except(model.EmployeeRatings);
And you probably want to distinct the results:
model.AvailableSkills = model.AvailableSkills.Distinct();
Last but not least:
Because you select the SkillId I'm unsure why you would order the results. This does not make sense especially because you order by different properties in both lists. Furtermore you probably want to select more details to display to the user, but to know this we need more details on your model.
Assuming EmployeeRatings contains rated skills, and you want AvailableSkills to have only skills not in EmployeeRatings but are in AllSkills, I think this is what you like to do:
model.AvailableSkills = model.AllSkills
.Where(s => !model.EmployeeRatings.Contains(s));
Consider two classes like this:
public class Skill
{
public int Id { get; set; }
}
public class Employee
{
public int[] RatedSkills { get; set; }
}
var skills = new List<Skill>
{
new Skill{ Id = 1}, new Skill{Id = 2}, new Skill{ Id = 3}, new Skill { Id = 4}
};
var emp = new Employee
{
RatedSkills = new int[] { 1,2 }
};
var availableSkills = skills.Select(s => s.Id).Except(emp.RatedSkills);
Console.Read();
The rating has an Id property an an employee has an int[] to hold his/her selected ratings. From there it's easy to filter
Following your current approach, you can use AddRange with a list. Something like:
List<long> availableSkills = new List<long>();
foreach (var skill in model.EmployeeRatings)
{
availableSkills.AddRange(model.AllSkills.Where(s => s != skill));
}
model.AvailableSkills = availableSkills;
Or you can achieve this with a more compact approach, and I believe Except removes dupes:
model.AvailableSkills = model.AllSkills.Except(model.EmployeeRatings);

How to create a simple left outer join in lambda expression in EF ASP.NET MVC5

I searched hours and hours for this without any luck. I'm trying to create a lambda expression to fetch data from two tables Schedule and Request. But i'm outputting a bool here. How can i do a proper left outer join to fix this?
this is the best i could come up with
ViewBag.RequestList = db.Requests
.Include(r => r.Department)
.Select(r => db.Schedules.Any(s => s.RequestId == r.RequestId));
but its a bool not a list.
Assume my table models are as follows
public class Request{
public virtual int RequestId { get; set; }
public virtual string Remarks { get; set; }
}
public class Schedule{
public virtual int ScheduleId{ get; set; }
public virtual string Name{ get; set; }
public virtual Request Request { get; set; }
}
I'm trying to see if each and every request has one or more schedules associated with it or not. so if i could attach schedule object to request and output it as a list then thats all i need.
But I want to do it using LINQ and lambda expressions and I've seen queries as below;
var leftList = (from emp in db.Requests
join d in db.Schedules
on emp.RequestId equals d.RequestId into output
from j in output.DefaultIfEmpty()
select new { RequestId = emp.RequestId,
name = emp.Department.Name,
route = emp.Route.Name });
But that's not what i want, because i have to specify every field i need in new { RequestId = emp.RequestId, name = emp.Department.Name, route = emp.Route.Name }
Thanks a lot!
just list what you want like this:
var leftList = from emp in db.Requests
join d in db.Schedules
on emp.RequestId equals d.RequestId into output
from j in output.DefaultIfEmpty()
select new
{
RequestId = emp.RequestId,
name = emp.Department.Name,
route = emp.Route.Name,
ScheduleId=j==null?0:j.ScheduleId,
SName=j==null?""j.Name,
};

One Field Refuses to Update Using EF

I have an unusual problem. One field in the database (FK_ItemType) will not update itself. I went into the vs debug, and checked that int ItemType was assigned, that it found a record in the database, that it assigned that record to item.FK_ItemType, and that that record stayed attached all the way to db.SaveChanges() (I used a breakpoint to check the value of item.FK_ItemType at db.Entry(item).State = EntityState.Modified;
To be extra sure, immediately after I commented out my redirect and pulled the record from the database and checked what the value was, returning that instead of the redirect. It returns the correct value.
However, when I look in the database, or go to my listing page, the newly updated ItemType is not there (still NULL in the database). Even more puzzling, everything works perfectly fine when adding a record.
Here are the relevant sections of my controller and model
[HttpPost]
public ActionResult Edit(Item item, int Company = 0, int Service = 0, int ItemType = 0)
{
if (Request.Form["doDelete"] == "true")
return Delete(item);
//Get, assign foreign keys
Company c = db.Companies.Find(Company);
Service s = db.Services.Find(Service);
ItemType i = db.ItemTypes.Find(ItemType);
if (c != null)
item.FK_Company = c;
if (s != null)
item.FK_Service = s;
if (i != null)
item.FK_ItemType = i;
//Force revalidate
ModelState.Clear();
//TryUpdateModel(item);
TryValidateModel(item);
if (ModelState.IsValid)
{
if (item.ItemID == 0) //add
db.Items.Add(item);
else
{
db.Entry(item).State = EntityState.Modified;
}
db.SaveChanges();
Item i2 = db.Items.Find(item.ItemID);
Response.Write(i2.FK_ItemType.Name);
return null;
// Return to the listing page, and show the user the filters they were looking at before editing.
return Redirect("~/" + Request.RequestContext.RouteData.Values["Controller"].ToString() + "/Index/" + Request.Form["ref"]);
}
// There was a validation error
if (item.ItemID != 0)
return Update(item);
else
return Add(item);
}
Model
public class Item
{
public int ItemID { get; set; }
...
[Required]
[Display(Name="Company")]
public virtual Company FK_Company { get; set; }
[Required]
[Display(Name="Service")]
public virtual Service FK_Service { get; set; }
[Display(Name="Item Type")]
public virtual ItemType FK_ItemType { get; set; }
}
Despite the name FK_ItemType this property is not a FK (foreign key) property. It is a navigation property and relationships represented by navigation properties are not updated when you set the state to Modified. (The same applies to FK_Company and FK_Service.)
You can either introduduce "real" foreign key properties...
[ForeignKey("FK_ItemType")]
public int RealFK_ItemType { get; set; }
public virtual ItemType FK_ItemType { get; set; }
// please give those properties better names..., like "ItemTypeID" and "ItemType"
...and then use the FK RealFK_ItemType directly to change relationships.
Or you must load the original Item from the database first (including related entities) to change the relationships by setting the navigation properties. The code for the UPDATE would be something like this:
var itemIdDb = db.Items
.Include(i => i.Company)
.Include(i => i.Service)
.Include(i => i.ItemType)
.Single(i => i.ItemID == item.ItemID);
Company c = db.Companies.Find(Company);
Service s = db.Services.Find(Service);
ItemType i = db.ItemTypes.Find(ItemType);
if (c != null)
itemInDb.FK_Company = c;
if (s != null)
itemInDb.FK_Service = s;
if (i != null)
itemInDb.FK_ItemType = i;
db.Entry(itemInDb).CurrentValues.SetValues(item);
db.SaveChanges();

Resources