Enter new data in db (EF) - c#

I have method in controller
It receive data from post request and write to table
Here is code
[ResponseType(typeof(TimeTable))]
public IHttpActionResult PostTimeTable(TimeTable timeTable)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (ModelState.IsValid)
{
DateTime dt = DateTime.Today;
TimeTable c = (from x in db.TimeTables
where x.Company == timeTable.Company && x.INN == timeTable.INN
select x).First();
c.StartPause = timeTable.StartPause;
c.StartDay = timeTable.StartDay;
c.EndPause = timeTable.EndPause;
c.EndDay = timeTable.EndDay;
db.SaveChanges();
}
db.TimeTables.Add(timeTable);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = timeTable.Id }, timeTable);
}
But it works well when record with INN and Company already in db.
But if it not in database I need to create new entry.
How I need to modify this method?

You can use a flag (exisingCompanyFlag) for edit mode or add new mode like this
bool existingCompanyFlag = true;
TimeTable c = (from x in db.TimeTables
where x.Company == timeTable.Company && x.INN == timeTable.INN
select x).FirstOrDefult();
if (c == null)
{
existingCompanyFlag = false;
c = new TimeTable();
}
c.StartPause = timeTable.StartPause;
c.StartDay = timeTable.StartDay;
c.EndPause = timeTable.EndPause;
c.EndDay = timeTable.EndDay;
if (!existingCompanyFlag)
db.TimeTables.Add(c);

You need a separate branch in your code for the insert case.
if (ModelState.IsValid) {
if (addingNewRow) {
TimeTable tt = new TimeTable {
// Populate properties (except identity columns)
};
db.TimeTables.Add(tt);
} else {
// update
}
db.SaveChanges();
}
To link to other entities use one of:
Assign instances:
x.Company = theCompany;
or, assign the instance id
x.CompanyId = companyId;
(#1 is easier if you already have the other entity loaded or are creating it – EF will sort out the ids – while #2 saves loading the whole other entity.)

Related

How do I Filter a table view by using TWO tables in MVC Controller?

I'm struggling with Filtering my table view based on TWO table attributes. I can display them fine using data from a single table, but once I add a filter from a second table and the Identity it won't display. Im trying "show results using TABLE 1 where Table1 ID == Table2 ID AND Table 2 User == User.identity.name"... in case it makes a difference... Table 1 is "Safes", Table 2 is a bridge table of "Users and Safes".
Any Help much appreciated :)
public ActionResult GetSafe(Users_and_Safe uas)
{
using (CBREntities2 dc = new CBREntities2())
{
var safe = dc.Safes.Where(a => a.Safe_ID == uas.Safe_ID && uas.User_ID == User.Identity.Name).Select(s => new { Safe_ID = s.Safe_ID, Department_ID = s.Department_ID, User_ID = s.User_ID }).ToList();
return Json(new { data = safe }, JsonRequestBehavior.AllowGet);
}
}
So I have found the answer and thought I would post for anyone in the future who has the issue:
public ActionResult GetSafeHome(Users_and_Safe uas)
{
using (CBREntities2 dc = new CBREntities2())
{
var allUAS = dc.Users_and_Safes.Where(b => b.User_ID == User.Identity.Name).Select(c => c.Safe_ID).ToList();
var homeSafes = dc.Safes.Where(x => (allUAS.Contains(x.Safe_ID))).Select(s => new { Safe_ID = s.Safe_ID, Department_ID = s.Department_ID }).ToList();
return Json(new { data = homeSafes }, JsonRequestBehavior.AllowGet);
}
}

Getting double data in DB

I pull student data from 2 databases. 1 from an online SOAP API which can handle async calls and 1 from a local DB with an older services that doesnt support async.
I compare these databases and write the differences in a local sqlDB through EF.
Problem:
I get double entries in my EF DB. He puts the correct data and amount in arrays inside the method, but it looks like once he hits the db.savechanges() he jumps back up a few line and saves again.
I don't even know where this extra thread comes from.
Some code might be still there from numerous tries to solve it. For instance I tried with addrange but I get an error when he tries to add the FullVarianceList.
public async Task<bool> FullStudentCompare(string date) //format DD/MM/YYYY
{
try
{
//DB context
using (var db = new SchoolDbContext())
{
//GET DATA
//SMT (async)
List<SmtStudent> smtStdudentList = await GetAllSmartschoolStudents();
//Wisa (sync)
//on date, or if emty on current systemdate
List<WisaStudent> wisaList;
if (date == "")
{
wisaList = GetWisaStudentData(DateTime.Now.ToShortDateString());
}
else
{
wisaList = GetWisaStudentData(date);
}
//Flags and props needed for DB entry after compare
bool existsInLocalDb = false;
List<Variance> vList = new List<Variance>();
//Full list to add to DB outside foreach
List<Variance> fullVarianceList = new List<Variance>();
//Full List of new Students to write to DB outside foreach
List<DbStudent> fullStudentList = new List<DbStudent>();
//Compare lists
foreach (WisaStudent wstd in wisaList)
{
//determine correct classCode
string klasCode;
if (wstd.klasgroep.Trim() == "Klasgroep 00")
{
klasCode = wstd.klas.Trim();
}
else
{
klasCode = wstd.klasgroep.Trim();
}
//Create SmtStudent object for compare
SmtStudent tempStd = new SmtStudent(true,
wstd.voornaam.Trim(),
wstd.naam.Trim(),
wstd.stamboeknummer.Trim(),
wstd.geslacht.Trim(),
wstd.geboortedatum.Trim(),
wstd.straat.Trim(),
wstd.huisnummer.Trim(),
wstd.busnummer.Trim(),
wstd.postcode.Trim(),
wstd.gemeente.Trim(),
wstd.emailadres.Trim(),
wstd.GSM_nummer.Trim(),
wstd.levensbeschouwing.Trim(),
wstd.coaccountmoedervoornaam.Trim(),
wstd.coaccountmoedernaam.Trim(),
wstd.coaccountmoederemailadres.Trim(),
wstd.coaccountmoederGSM_nummer.Trim(),
wstd.coaccountvadervoornaam.Trim(),
wstd.coaccountvadernaam.Trim(),
wstd.coaccountvaderemailadres.Trim(),
wstd.coaccountvaderGSM_nummer.Trim(),
klasCode,
wstd.nationaliteit,
wstd.geboorteGemeente,
wstd.geboorteLand
);
//Find matching SmtStudent
SmtStudent smtStd = smtStdudentList.Find(i => i.Internnummer == wstd.stamboeknummer);
//Find matching Std in local DB
DbStudent dbStd = await db.Students.Where(i => i.Stamboeknummer == wstd.stamboeknummer).FirstOrDefaultAsync();
//if none exists in the local DB create an entity to update and write to DB
if (dbStd == null)
{
dbStd = new DbStudent(wstd.voornaam.Trim(),
wstd.naam.Trim(),
wstd.stamboeknummer.Trim(),
wstd.geslacht.Trim(),
wstd.geboortedatum.Trim(),
wstd.straat.Trim(),
wstd.huisnummer.Trim(),
wstd.busnummer.Trim(),
wstd.postcode.Trim(),
wstd.gemeente.Trim(),
wstd.emailadres.Trim(),
wstd.GSM_nummer.Trim(),
wstd.levensbeschouwing.Trim(),
wstd.coaccountmoedervoornaam.Trim(),
wstd.coaccountmoedernaam.Trim(),
wstd.coaccountmoederemailadres.Trim(),
wstd.coaccountmoederGSM_nummer.Trim(),
wstd.coaccountvadervoornaam.Trim(),
wstd.coaccountvadernaam.Trim(),
wstd.coaccountvaderemailadres.Trim(),
wstd.coaccountvaderGSM_nummer.Trim(),
klasCode,
wstd.loopbaanDatum,
wstd.nationaliteit,
wstd.geboorteGemeente,
wstd.geboorteLand
);
db.Students.Add(dbStd);
fullStudentList.Add(dbStd);
}
else
{
existsInLocalDb = true;
}
if (smtStd == null)
{
//Std doesn't exist in Smt -> New student
dbStd.IsNewStudent = true;
dbStd.ClassMovement = true;
//remove from wisaList
wisaList.Remove(wstd);
}
else
{
//clear vlist from previous iterations
vList.Clear();
//get all properties on the obj, cycle through them and find differences
PropertyInfo[] props = smtStd.GetType().GetProperties();
vList.AddRange(props.Select(f => new Variance
{
Property = f.Name,
ValueA = f.GetValue(smtStd),
ValueB = f.GetValue(tempStd),
Checked = false
})
.Where(v => !v.ValueA.Equals(v.ValueB) && v.ValueB != null)
.ToList());
//If the users allrdy exists in LocalDb delete all previously recorded variances
if (existsInLocalDb)
{
if (db.Variances.Where(j => j.Student.StudentId.Equals(dbStd.StudentId)).FirstOrDefault() != null)
{ //if the student allready exists we will recreate the variancelist, hence deleting all current items first
List<Variance> existingList = db.Variances.Where(j => j.Student.StudentId.Equals(dbStd.StudentId)).ToList();
foreach (Variance v in existingList)
{
db.Variances.Remove(v);
}
}
}
//Add new variances if vList is not empty
if (vList.Count > 0)
{
//Check if KlasCode is a variance -> set classmovement to true
if (vList.Where(i => i.Property == "KlasCode").FirstOrDefault() != null)
{
dbStd.ClassMovement = true;
}
else
{
dbStd.ClassMovement = false;
}
//add the StudentObject to the variance to link them 1-many
foreach (Variance v in vList)
{
v.Student = dbStd;
fullVarianceList.Add(v);
db.Variances.Add(v);
}
}
}
}
//add the full lists of variances and new students to DB
//db.Variances.AddRange(fullVarianceList);
//db.Students.AddRange(fullStudentList);
db.SaveChanges();
return true;
}
}
catch(Exception ex)
{
return false;
}
}
A couple of things:
It is important to understand that EF uses a unit of work pattern where none of the changes to the entities are persisted until SaveChanges is called which explains the "once he hits the db.Savechanges() he jumps back up" phenomenon.
When you have a 1 to many relationsship and you assign a collection of entities to a navigation property on another entity and then add that parent entity to the DbContext, EF marks those child entities to be added too. In your case dbStd is added at the line "db.Students.Add(dbStd);" and at the line "v.Student = dbStd;". This is most likely what is causing your duplicates.

Edit table data using auto mapper

Hi i am building a web application for school.
I am trying to update student information, i already did teacher part
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Save(Teacher teacher)
{
if (!ModelState.IsValid)
{
var data = teacher;
return View("TeacherForm", data);
}
if (teacher.Id == 0)
_context.Teachers.Add(teacher);
else
{
var dataInDb = _context.Teachers.Single(c => c.Id == teacher.Id);
dataInDb.Name = teacher.Name;
dataInDb.Designation = teacher.Designation;
dataInDb.EducationalQualification = teacher.EducationalQualification;
dataInDb.DateOfBirth = teacher.DateOfBirth;
dataInDb.PhoneNumber = teacher.PhoneNumber;
dataInDb.StartDate = teacher.StartDate;
dataInDb.EndDate = teacher.EndDate;
dataInDb.Status = teacher.Status;
}
_context.SaveChanges();
return RedirectToAction("Index", "Teacher");
}
But in Student part i want to use auto mapper for map data
if (student.Id == 0)
_context.Students.Add(student);
else
{
var dataInDb = _context.Students.Single(c => c.Id == student.Id);
Mapper.Map(student, dataInDb);
}
but its not working. I try to edit data but the table data remain same.
its relay difficult to write every property for student.
how can i solve this problem?

asp.net return same view but delete url?

I have a project where I report time on diffrent projects, and I am working on so I can delete a report incase I do it wrong, which is working decent.
When I go to the summery page of all my reports it lists all the dates, I click the date and it sends it to the TimeReport view like this:
http://localhost:9061/Reports/TimeReport/b604a74a-2034-4916-9534-57788db1e8e2
And than it checks if the ReportId has a value like this:
#if (Model.ReportId.HasValue)
{
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#basic">Ta bort!</button>
}
And if it exists a Remove button will appear, I click the remove button and it will remove the report. but the URL is still the same, so if I refresh the site my application will crash because it that ID no longer exists in the database.
if (form != null && form.AllKeys.Contains("delete"))
{
new DatabaseLayer().DeleteTimeReport(Guid.Parse(form["ReportId"]));
LoadDefaultSettings(projectData);
ViewData.Model = projectData;
ViewData["deleted"] = true;
return View();
}
This is the model that check if if the GUID exists.
public void SaveToDatabase(Guid consultantId)
{
using (DatabaseLayer db = new DatabaseLayer())
{
//Time report exists, delete it.
if (ReportId.HasValue)
{
db.DeleteTimeReport(ReportId.Value);
}
//Time report does not exist, create a new one.
else
{
ReportId = Guid.NewGuid();
}
Report report = new Report
{
FK_ConsultantID = consultantId,
FK_UserID = Constants.UserTreetop,
Date = Date,
TimeReportID = ReportId.Value
};
TimeReportData reportData = new TimeReportData
{
Absent = 0,
Description = "",
StartHour = Times.StartHour,
StartMinute = Times.StartMinute,
EndHour = Times.EndHour,
EndMinute = Times.EndMinute,
BreakHour = Times.BreakHour,
BreakMinute = Times.BreakMinute,
FK_TimeReportID = ReportId.Value,
TimeReportDataID = Guid.NewGuid()
};
TimeReportProject[] reportProjects = new TimeReportProject[Projects.Count];
for (int i = 0; i < Projects.Count; i++)
{
reportProjects[i] = new TimeReportProject
{
Description = Projects[i].Description,
FK_ProjectID = Projects[i].ProjectId,
FK_TimeReportID = ReportId.Value,
Hours = Projects[i].Hours.GetValueOrDefault(), //Projects[i].Hours.Value,
HourRate = db.GetProjectHourRate(Projects[i].ProjectId, Date, Projects[i].Hours.GetValueOrDefault()),
TimeReportProjectID = Guid.NewGuid()
};
}
db.InsertTimeReport(report, reportData, reportProjects);
}
}
And as it exists it does this
public void DeleteTimeReport(Guid timeReportId)
{
db.ExecuteStoreCommand(
#" DELETE FROM [Salesweb].[dbo].[TimeReportProject] WHERE FK_TimeReportID = #id;
DELETE FROM [Salesweb].[dbo].[TimeReportData] WHERE FK_TimeReportID = #id;
DELETE FROM [Salesweb].[dbo].[TimeReport] WHERE TimeReportID = #id;"
, new SqlParameter("#id", timeReportId));
db.SaveChanges();
}
This is the view when I pass in the guid I Want to delete as the guid has a value the remove button will appear.
But as I delete the project it will return to the same view. Like we can see the tabs is not showing up, so if I want the to show again I have to go to another view, and than back to the same view. And if I refresh it will crash due the guid dosen't exist in the DB.
And here is the whole controller, it's a bit messy right now.
public ActionResult TimeReport(FormCollection form, Guid? id)
{
ViewDataDictionary vd = new ViewDataDictionary
{
["projects"] = new DatabaseLayer().GetConsultantProjects(Constants.CurrentUser(User.Identity.Name)),
["id"] = 1,
["showDescription"] = true
};
ViewData["vd"] = vd;
NewTimeReportModel projectData = new NewTimeReportModel();
if (form != null && form.AllKeys.Contains("delete"))
{
new DatabaseLayer().DeleteTimeReport(Guid.Parse(form["ReportId"]));
LoadDefaultSettings(projectData);
ViewData.Model = projectData;
ViewData["deleted"] = true;
return RedirectToAction("Index");
}
if (id.HasValue && (form == null || form.AllKeys.Length == 0))
{
using (DatabaseLayer db = new DatabaseLayer())
{
var timeReport = db.GetTimeReport(id.Value);
projectData = new NewTimeReportModel(timeReport);
if (projectData.Projects.Count == 1)
projectData.Projects[0].Hours = null;
}
}
else if (form == null || form.AllKeys.Length == 0)
{
LoadDefaultSettings(projectData);
}
else
{
//Get's all the dates from the view and formates them to look like yy-mm-dd so we can parse it to a datetime.
string[] dates = FormateDate(form["date"]);
//Loops over all the dates and saves the dates to the database.
projectData = ReportDates(form, projectData, dates);
//Loads default settings if all dates been reported.
LoadDefaultSettings(projectData);
}
//Get's and lists all the missing days
ListAllMssingDays();
ViewData.Model = projectData;
return View();
}
Recommended thing to do in such cases is run redirect to some default URL, like the summary page. Guessing that you have Summary action, that should be something like:
if (form != null && form.AllKeys.Contains("delete"))
{
new DatabaseLayer().DeleteTimeReport(Guid.Parse(form["ReportId"]));
return RedirectToAction("Summary", "Reports");
}
Note that this will do a client-side redirect, so to say - this will do a response with code 302 and new URL /Reports/Summary. This is usually a desired behavior though.
The exception you're getting is because your code assumes the item you're deleting will exist.
Change
return db.TimeReports.Where(x => x.TimeReportID == timeReportId).Single();
To
return db.TimeReports.Where(x => x.TimeReportID == timeReportId).SingleOrDefault();
Which will return null if your Where clause returns 0 items.
Then wherever in your code you're calling GetTimeReport() you need to check for and handle null.

Insert data using Entity Framework model

I'm trying to insert some data in my database using Entity Framework model, but for some unknown reasons to me, it does nothing.
Am I missing something here?
using (var context = new DatabaseEntities())
{
var t = new test
{
ID = Guid.NewGuid(),
name = "blah",
};
context.AddTotest(t);
context.SaveChanges();
}
It should be:
context.TableName.Add(TableEntityInstance);
For versions of entity framework before 6, it was:
context.TableName.AddObject(TableEntityInstance);
Where:
TableName: the name of the table in the database.
TableEntityInstance: an instance of the table entity class.
If your table is Orders, then:
Order order = new Order();
context.Orders.Add(order);
For example:
var id = Guid.NewGuid();
// insert
using (var db = new EfContext("name=EfSample"))
{
var customers = db.Set<Customer>();
customers.Add( new Customer { CustomerId = id, Name = "John Doe" } );
db.SaveChanges();
}
Here is an example:
public void UpdatePlayerScreen(byte[] imageBytes, string installationKey)
{
var player = (from p in this.ObjectContext.Players where p.InstallationKey == installationKey select p).FirstOrDefault();
var current = (from d in this.ObjectContext.Screenshots where d.PlayerID == player.ID select d).FirstOrDefault();
if (current != null)
{
current.Screen = imageBytes;
current.Refreshed = DateTime.Now;
this.ObjectContext.SaveChanges();
}
else
{
Screenshot screenshot = new Screenshot();
screenshot.ID = Guid.NewGuid();
screenshot.Interval = 1000;
screenshot.IsTurnedOn = true;
screenshot.PlayerID = player.ID;
screenshot.Refreshed = DateTime.Now;
screenshot.Screen = imageBytes;
this.ObjectContext.Screenshots.Add(screenshot);
this.ObjectContext.SaveChanges();
}
}
var context = new DatabaseEntities();
var t = new test //Make sure you have a table called test in DB
{
ID = Guid.NewGuid(),
name = "blah",
};
context.test.Add(t);
context.SaveChanges();
Should do it
[HttpPost] // it use when you write logic on button click event
public ActionResult DemoInsert(EmployeeModel emp)
{
Employee emptbl = new Employee(); // make object of table
emptbl.EmpName = emp.EmpName;
emptbl.EmpAddress = emp.EmpAddress; // add if any field you want insert
dbc.Employees.Add(emptbl); // pass the table object
dbc.SaveChanges();
return View();
}

Categories