I have select2 list with employees which admin will add to project.
I select multiple employees and sending json with employee ID's to controller where
trying to get employee by employee, from company database emp list by stored procedure [Employee] to web emp db.
I face such problem that reader reads only first and last rows and skips all employees in midle
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EmpAdd()
{
var project_id = Convert.ToInt32(Request["project"]);
var company = Request["company"];
var emp = Request["emp"];
var ids = emp.Split(',');
var project = db.apsk_project.Where(x => x.id == project_id).FirstOrDefault();
cmd.CommandText = "Employee";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConnection1;
foreach(var i in ids) {
var it = Convert.ToInt32(i);
var kortele = db.apsk_workers.Where(x => x.id == it).FirstOrDefault();
if(kortele == null) {
sqlConnection1.Open();
cmd.Parameters.Clear();
cmd.Parameters.AddWithValue("company", company);
cmd.Parameters.AddWithValue("nr", it);
reader = cmd.ExecuteReader();
if(reader.HasRows) {
while(reader.Read()) {
apsk_workers apsk = new apsk_workers();
var v = reader.GetString(1);
var p = reader.GetString(2);
var d = reader.GetDateTime(3);
apsk.kof_id = 0;
apsk.algos_tipas = "";
apsk.vardas = v;
apsk.pavarde = p;
apsk.ar_dirba = d;
apsk.company = company;
apsk.manager = User.Identity.Name;
apsk.id = it;
db.apsk_workers.Add(apsk);
db.SaveChanges();
}
}
sqlConnection1.Close();
apsk_assigned _Assigned = new apsk_assigned();
_Assigned.project_id = project_id;
_Assigned.project = project.project;
_Assigned.worker_id = it;
db.apsk_assigned.Add(_Assigned);
db.SaveChanges();
} else {
var ar_projekte = db.apsk_assigned.Where(x => x.project_id == project_id && x.worker_id == it).FirstOrDefault();
if(ar_projekte == null) {
apsk_assigned _Assigned = new apsk_assigned();
_Assigned.project_id = project_id;
_Assigned.project = project.project;
_Assigned.worker_id = it;
db.apsk_assigned.Add(_Assigned);
db.SaveChanges();
}
}
}
Assigning person to project works fine.
I'd make several changes:
You are mixing EF with ado.net So please remove all connection opening and closings. Also lines with Parameters etc.
Since id's is a string, you can convert it to an List of ints: https://stackoverflow.com/a/9301290/169714
With Linq you can assign the employees who are already known to the project
With Linq you can foreach add the unknown employees and savechanges after adding them alll.
Let us know if you need help with specific Linq queries.
For instance: instead of db.apsk_project.Where(x => x.id == project_id).FirstOrDefault(); you could use db.apsk_project.FirstOrDefault(x => x.id == project_id);
So do not do a foreach and then a first or default to change per row, but think in collections so you can eliminate the loop and increase performance. Hope this helps. If not, please comment so I can try to explain more.
Related
I have to update one field in the row of the table after fetching two records from the same row. As an easiest practice I have fetched two records individually, created a new value and then updating that particular property through Entity framework. I think there is a better way to do the same thing with less code. If any body can suggest please.
if (objModel.amountpaid==0)
{
using (estatebranchEntities db=new estatebranchEntities())
{
int rentVar = Convert.ToInt32(db.PropertyDetails.Where(m => m.propertyid == objVM.propertyid).Select(m => m.rent).SingleOrDefault());
int balanceVar = Convert.ToInt32(db.PropertyDetails.Where(m => m.propertyid == objVM.propertyid).Select(m => m.balance).SingleOrDefault());
int balanceUpdateVar = (rentVar + balanceVar);
var propInfo = new PropertyDetail() { balance = balanceUpdateVar };
//var result = (from a in db.PropertyDetails
// where a.propertyid == objVM.propertyid
// select new PropertyDetail
// {
// rent = a.rent,
// balance = a.balance
// }).ToList();
db.PropertyDetails.Attach(propInfo);
db.Entry(propInfo).Property(z => z.balance).IsModified = true;
db.SaveChanges();
}
}
Here is what I think you can do.
Fetch the data once and update once.
using (estatebranchEntities db=new estatebranchEntities())
{
var propDetails = db.PropertyDetails.FirstOrDefault(m => m.propertyid == objVM.propertyid);
if (propDetails != null)
{
int rentVar = Convert.ToInt32(propDetails.rent);
int balanceVar = Convert.ToInt32(propDetails.balance);
int balanceUpdateVar = rentVar + balanceVar;
//now do the update
propDetails.balance = balanceUpdateVar;
db.Entry(proDetails).State = EntityState.Modified;
db.SaveChanges();
}
}
if you need to use the rentVar,balanceVar or the balanceUpdateVar, outside of the using statement then declare them outside it.
I want to update a specific row of the database. This is the code:
public void Update_Datos(int ID)
{
int UserId = Convert.ToInt16((string)(Session["UserId"]));
using (var db = new Entities())
{
//Reading
List<Datos_Personales> objDatos = db.Datos_Personales.ToList<Datos_Personales>();
foreach (Datos_Personales item in objDatos)
{
}
//Update
var datos_personales = db.Datos_Personales.FirstOrDefault(d => d.UserId == UserId && d.Id == ID);
Datos_Personales datos = objDatos[datos_personales.Id];
datos = db.Datos_Personales.Where(d => d.UserId == UserId && d.Id == ID).First();
datos.Fecha_de_nacimiento = Convert.ToDateTime(Fecha_de_nacimiento.Text);
datos.Nombre_Completo = txt_Nombre_Completo.Text;
datos.Identificacion = txt_Identificacion.Text;
datos.Estado_civil = ddEstadoCivil.SelectedValue;
datos.Telefono = txt_num_telefono.Text;
datos.Departamento = ddDepartamento.SelectedValue;
datos.Nacionalidad = Country.SelectedValue;
datos.Salario_min_aceptado = ddSalario_min_aceptado.SelectedValue;
datos.Titulo = txt_Titulo.Text;
datos.Descripcion_Profesional = txt_Descripcion_Profesional.Text;
datos.UserId = Convert.ToInt16(UserId);
db.Datos_Personales.Add(datos);
db.SaveChanges();
}
}
The other is issue is that it creating another row instead updating the one which I need.
You must not read all Db. When you use this line List<Datos_Personales> objDatos = db.Datos_Personales.ToList<Datos_Personales>();, your all entity (all rows in Db) stored into memory.
You can fetch your data directly and edit it. Finally you must not add entity again, only call SaveChages. (If you did not close ChangeTracker)
public void Update_Datos(int ID)
{
int UserId = Convert.ToInt16((string)(Session["UserId"]));
using (var db = new Entities())
{
Datos_Personales datos = db.Datos_Personales.FirstOrDefault(d => d.UserId == UserId && d.Id == ID));
if(datos == null)
return;
datos.Fecha_de_nacimiento = Convert.ToDateTime(Fecha_de_nacimiento.Text);
datos.Nombre_Completo = txt_Nombre_Completo.Text;
datos.Identificacion = txt_Identificacion.Text;
datos.Estado_civil = ddEstadoCivil.SelectedValue;
datos.Telefono = txt_num_telefono.Text;
datos.Departamento = ddDepartamento.SelectedValue;
datos.Nacionalidad = Country.SelectedValue;
datos.Salario_min_aceptado = ddSalario_min_aceptado.SelectedValue;
datos.Titulo = txt_Titulo.Text;
datos.Descripcion_Profesional = txt_Descripcion_Profesional.Text;
datos.UserId = Convert.ToInt16(UserId);
db.SaveChanges();
}
}
Sort in LINQ
I have 2 database CustomerEntities and BillEntities
I want to get CustomerName from CustomerEntities and sort it but it have no data and I want .ToList() just once time because it slow if used many .ToList()
using (var db1 = new CustomerEntities())
{ using (var db2 = new BillEntities())
{
var CustomerData = db1.Customer.Select(s=> new{s.CustomerCode,s.CustomerName}).ToList();
var BillData = (from t1 in db2.Bill
select new {
BillCode = t1.Billcode,
CustomerCode = t1.Customer,
CustomerName = ""; //have no data
});
}
if(sorting.status==true)
{
BillData= BillData.OrderBy(o=>o.CustomerName); //can't sort because CustomerName have no data
}
var data = BillData .Skip(sorting.start).Take(sorting.length).ToList(); // I want .ToList() just once time because it slow if used many .ToList()
foreach (var b in data)
{
var Customer = CustomerData.FirstOrDefault(f => f.CustomerCode==b.CustomerCode );
if(CustomerName>!=null)
{
r.CustomerName = Customer.CustomerName; //loop add data CustomerName
}
}
}
I have no idea to do it. Help me please
I'm not sure if I understand your code but what about this:
var BillData = (from t1 in db2.Bill
select new {
BillCode = t1.Billcode,
CustomerCode = t1.Customer,
CustomerName = db1.Customer.FirstOrDefault(c => c.CustormerCode == t1.Customer)?.CustomerName
});
Then you have objects in BillData that holds the CustomerName and you can order by that:
BillData.OrderBy(bd => bd.CustomerName);
If you just want to get CustomerName from your customer Db and sort it, this is what i would have used. I used orderByDescending but you can use OrderBy aswell.
public List<Customer> getLogsByCustomerName(string customername)
{
using (var dbentites = new CustomerEntities())
{
var result = (from res in dbentites.Customer.OrderByDescending(_ => _.CustomerName)
where res.CustomerName == customername
select res).ToList();
return result.ToList();
}
}
I'm somewhat new to EF 6.0 so I'm pretty sure I'm doing something wrong here.
there are two questions related to the problem
what am I doing wrong here
what's the best practice to achieve this
I'm using a code first model, and used the edmx designer to design the model and relationships, the system needs to pull information periodically from a webservice and save it to a local database (SQL Lite) in a desktop application
so I get an order list from the API, when I populate and try to save Ticket, I get a duplicate key exception when trying to insert TicketSeatType -
how do I insert the ticket to dbContext, so that It doesn't try and re-insert insert TicketSeatType and TicketPriceType, I have tried setting the child object states to unchanged but it seems to be inserting
secondly, what would be the best practice to achieve this using EF ? it just looks very inefficient loading each object into memory and comparing if it exists or not
since I need to update the listing periodically, I have to check against each object in the database if it exists, then update, else insert
code:
//read session from db
if (logger.IsDebugEnabled) logger.Debug("reading session from db");
dbSession = dbContext.SessionSet.Where(x => x.Id == sessionId).FirstOrDefault();
//populate orders
List<Order> orders = (from e in ordersList
select new Order {
Id = e.OrderId,
CallCentreNotes = e.CallCentreNotes,
DoorEntryCount = e.DoorEntryCount,
DoorEntryTime = e.DoorEntryTime,
OrderDate = e.OrderDate,
SpecialInstructions = e.SpecialInstructions,
TotalValue = e.TotalValue,
//populate parent refernece
Session = dbSession
}).ToList();
//check and save order
foreach (var o in orders) {
dbOrder = dbContext.OrderSet.Where(x => x.Id == o.Id).FirstOrDefault();
if (dbOrder != null) {
dbContext.Entry(dbOrder).CurrentValues.SetValues(o);
dbContext.Entry(dbOrder).State = EntityState.Modified;
}
else {
dbContext.OrderSet.Add(o);
dbContext.Entry(o.Session).State = EntityState.Unchanged;
}
}
dbContext.SaveChanges();
//check and add ticket seat type
foreach (var o in ordersList) {
foreach (var t in o.Tickets) {
var ticketSeatType = new TicketSeatType {
Id = t.TicketSeatType.TicketSeatTypeId,
Description = t.TicketSeatType.Description
};
dbTicketSeatType = dbContext.TicketSeatTypeSet.Where(x => x.Id == ticketSeatType.Id).FirstOrDefault();
if (dbTicketSeatType != null) {
dbContext.Entry(dbTicketSeatType).CurrentValues.SetValues(ticketSeatType);
dbContext.Entry(dbTicketSeatType).State = EntityState.Modified;
}
else {
if (!dbContext.ChangeTracker.Entries<TicketSeatType>().Any(x => x.Entity.Id == ticketSeatType.Id)) {
dbContext.TicketSeatTypeSet.Add(ticketSeatType);
}
}
}
}
dbContext.SaveChanges();
//check and add ticket price type
foreach (var o in ordersList) {
foreach (var t in o.Tickets) {
var ticketPriceType = new TicketPriceType {
Id = t.TicketPriceType.TicketPriceTypeId,
SeatCount = t.TicketPriceType.SeatCount,
Description = t.TicketPriceType.Description
};
dbTicketPriceType = dbContext.TicketPriceTypeSet.Where(x => x.Id == ticketPriceType.Id).FirstOrDefault();
if (dbTicketPriceType != null) {
dbContext.Entry(dbTicketPriceType).CurrentValues.SetValues(ticketPriceType);
dbContext.Entry(dbTicketPriceType).State = EntityState.Modified;
}
else {
if (!dbContext.ChangeTracker.Entries<TicketPriceType>().Any(x => x.Entity.Id == ticketPriceType.Id)) {
dbContext.TicketPriceTypeSet.Add(ticketPriceType);
}
}
}
}
dbContext.SaveChanges();
//check and add tickets
foreach (var o in ordersList) {
dbOrder = dbContext.OrderSet.Where(x => x.Id == o.OrderId).FirstOrDefault();
foreach (var t in o.Tickets) {
var ticket = new Ticket {
Id = t.TicketId,
Quantity = t.Quantity,
TicketPrice = t.TicketPrice,
TicketPriceType = new TicketPriceType {
Id = t.TicketPriceType.TicketPriceTypeId,
Description = t.TicketPriceType.Description,
SeatCount = t.TicketPriceType.SeatCount,
},
TicketSeatType = new TicketSeatType {
Id = t.TicketSeatType.TicketSeatTypeId,
Description = t.TicketSeatType.Description
},
Order = dbOrder
};
//check from db
dbTicket = dbContext.TicketSet.Where(x => x.Id == t.TicketId).FirstOrDefault();
dbTicketSeatType = dbContext.TicketSeatTypeSet.Where(x => x.Id == t.TicketSeatType.TicketSeatTypeId).FirstOrDefault();
dbTicketPriceType = dbContext.TicketPriceTypeSet.Where(x => x.Id == t.TicketPriceType.TicketPriceTypeId).FirstOrDefault();
if (dbTicket != null) {
dbContext.Entry(dbTicket).CurrentValues.SetValues(t);
dbContext.Entry(dbTicket).State = EntityState.Modified;
dbContext.Entry(dbTicket.Order).State = EntityState.Unchanged;
dbContext.Entry(dbTicketSeatType).State = EntityState.Unchanged;
dbContext.Entry(dbTicketPriceType).State = EntityState.Unchanged;
}
else {
dbContext.TicketSet.Add(ticket);
dbContext.Entry(ticket.Order).State = EntityState.Unchanged;
dbContext.Entry(ticket.TicketSeatType).State = EntityState.Unchanged;
dbContext.Entry(ticket.TicketPriceType).State = EntityState.Unchanged;
}
}
}
dbContext.SaveChanges();
UPDATE:
Found the answer, it has to do with how EF tracks references to objects, in the above code, I was creating new entity types from the list for TicketPriceType and TicketSeatType:
foreach (var o in ordersList) {
dbOrder = dbContext.OrderSet.Where(x => x.Id == o.OrderId).FirstOrDefault();
foreach (var t in o.Tickets) {
var ticket = new Ticket {
Id = t.TicketId,
Quantity = t.Quantity,
TicketPrice = t.TicketPrice,
TicketPriceType = new TicketPriceType {
Id = t.TicketPriceType.TicketPriceTypeId,
Description = t.TicketPriceType.Description,
SeatCount = t.TicketPriceType.SeatCount,
},
TicketSeatType = new TicketSeatType {
Id = t.TicketSeatType.TicketSeatTypeId,
Description = t.TicketSeatType.Description
},
Order = dbOrder
};
....
in this case the EF wouldn't know which objects they were and try to insert them.
the solution is to read the entities from database and allocate those, so it's referencing the same entities and doesn't add new ones
foreach (var t in o.Tickets) {
//check from db
dbTicket = dbContext.TicketSet.Where(x => x.Id == t.TicketId).FirstOrDefault();
dbTicketSeatType = dbContext.TicketSeatTypeSet.Where(x => x.Id == t.TicketSeatType.TicketSeatTypeId).FirstOrDefault();
dbTicketPriceType = dbContext.TicketPriceTypeSet.Where(x => x.Id == t.TicketPriceType.TicketPriceTypeId).FirstOrDefault();
var ticket = new Ticket {
Id = t.TicketId,
Quantity = t.Quantity,
TicketPrice = t.TicketPrice,
TicketPriceType = dbTicketPriceType,
TicketSeatType = dbTicketSeatType,
Order = dbOrder
};
...}
Don't you think that you are trying to write very similar codes for defining the state of each entity?
We can handle all of these operations with a single command.
You can easily achieve this with the newly released EntityGraphOperations for Entity Framework Code First. I am the author of this product. And I have published it in the github, code-project (includes a step-by-step demonstration and a sample project is ready for downloading) and nuget. With the help of InsertOrUpdateGraph method, it will automatically set your entities as Added or Modified. And with the help of DeleteMissingEntities method, you can delete those entities which exists in the database, but not in the current collection.
// This will set the state of the main entity and all of it's navigational
// properties as `Added` or `Modified`.
context.InsertOrUpdateGraph(ticket);
By the way, I feel the need to mention that this wouldn't be the most efficient way of course. The general idea is to get the desired entity from the database and define the state of the entity. It would be as efficient as possible.
I have this query, it selects A LOT of user records from a table. This code block takes 16 seconds from my local/debug machine (more like 5 in production). Anything I do to make this more efficient doubles the amount of time the method takes to return the results. Examples of other things I've tried are below. I don't understand how selecting an anonymous type and having the extra middle section iterating through the anonymous type can possibly be faster than without.
This block takes 16 seconds:
List<BoAssetSecurityUser> userList = new List<BoAssetSecurityUser>();
using (var context = DataObjectFactory.CreateContext())
{
var query = from ui in context.User_Information
where (ui.AssetCustomerID == 1 &&
(ui.GlobalID != "1TPTEMPUSER" ||
ui.GlobalID == null))
select new { ui };
var result =
from q in query
select new
{
UserId = q.ui.UserID,
FirstName = q.ui.FirstName,
LastName = q.ui.LastName,
UserName = q.ui.Username,
Globalid = q.ui.GlobalID
};
foreach (var user in result)
{
BoAssetSecurityUser boAssetSecUser = new BoAssetSecurityUser();
boAssetSecUser.UserId = user.UserId;
boAssetSecUser.FirstName = user.FirstName;
boAssetSecUser.LastName = user.LastName;
boAssetSecUser.UserName = user.UserName;
boAssetSecUser.GlobalId = user.Globalid;
userList.Add(boAssetSecUser);
}
}
return userList;
This takes over 45 seconds to complete:
List<BoAssetSecurityUser> userList = new List<BoAssetSecurityUser>();
using (var context = DataObjectFactory.CreateContext())
{
var query = (from ui in context.User_Information
where (ui.AssetCustomerID == 1 &&
(ui.GlobalID != "1TPTEMPUSER" ||
ui.GlobalID == null))
select ui).ToList();
foreach (var user in query)
{
BoAssetSecurityUser boAssetSecUser = new BoAssetSecurityUser();
boAssetSecUser.UserId = user.UserID;
boAssetSecUser.FirstName = user.FirstName;
boAssetSecUser.LastName = user.LastName;
boAssetSecUser.UserName = user.Username;
boAssetSecUser.GlobalId = user.GlobalID;
userList.Add(boAssetSecUser);
}
}
return userList;
This example also takes over 45 seconds to complete:
List<BoAssetSecurityUser> userList = new List<BoAssetSecurityUser>();
using (var context = DataObjectFactory.CreateContext())
{
var query = from ui in context.User_Information
where (ui.AssetCustomerID == 1 &&
(ui.GlobalID != "1TPTEMPUSER" ||
ui.GlobalID == null))
select new { ui };
foreach (var user in query)
{
BoAssetSecurityUser boAssetSecUser = new BoAssetSecurityUser();
boAssetSecUser.UserId = user.ui.UserID;
boAssetSecUser.FirstName = user.ui.FirstName;
boAssetSecUser.LastName = user.ui.LastName;
boAssetSecUser.UserName = user.ui.Username;
boAssetSecUser.GlobalId = user.ui.GlobalID;
userList.Add(boAssetSecUser);
}
}
return userList;
This is most likely because ui's type has more properties than the 5 you're interested in. The new { ui } anonymous type is unnecessary; your first example is faster because you tell it before you iterate the list (and thus go to the DB) that you're only interested in those 5 fields. In the other examples, you iterate the list, thus pulling the whole ui objects, even though you only use 5 of its properties.
This code should only pull the 5 properties, and so be as fast as your first example, while being more concise:
List<BoAssetSecurityUser> userList = new List<BoAssetSecurityUser>();
using (var context = DataObjectFactory.CreateContext())
{
var query = from ui in context.User_Information
where (ui.AssetCustomerID == 1 && (ui.GlobalID != "1TPTEMPUSER" || ui.GlobalID == null))
select new
{
ui.UserID,
ui.FirstName,
ui.LastName,
ui.Username,
ui.GlobalID
};
foreach (var user in query)
{
BoAssetSecurityUser boAssetSecUser = new BoAssetSecurityUser();
boAssetSecUser.UserId = user.UserID;
boAssetSecUser.FirstName = user.FirstName;
boAssetSecUser.LastName = user.LastName;
boAssetSecUser.UserName = user.Username;
boAssetSecUser.GlobalId = user.GlobalID;
userList.Add(boAssetSecUser);
}
}
return userList;
It's more about the amount of data your bringing from the database. The first query selects only a few columns while the others bring all of them.
Do you have large columns on this table?
It is faster because you only fetch 5 properties per line with your anonymous type. I don't now how many fields you have in User_Information, but they're all fetched when you use .ToList() on your query, you probably get much more data than needed.