Evening all,
I was hoping that someone could help me along with a project that I am working on.
Just before I really start, I just want to make it absolutely clear, I have never done anything like this before past dabbling at home, I am not a C# developer or Database administrator. So please excuse any breaks from best practice, this is the total of 4 weeks worth of learning and banging my head on the desk trying to follow quiet a confusing topic.
So I have (somehow) ended up being tasked with creating a number of websites, and in an effort to make it easier for myself I have tried to create a "templated" system where I use a number of partial pages/parts in a layout page to drive the website via data.
I have created the below database structure, trying to think of all the things I will need, such as turning parts on and off and creating a control that creates the menu structure.
Model Diagram
of the back of that I have created the below class that creates all of the various view models that I want to pass to each of the partials in my layout (there are multiple dependant on the site hence the parts instead of one giant layout).
public class PageDetails
{
public static async Task<DataPageDetailsVM> Get(int companyID, ControllerContext controllerContext)
{
using (var dimensionContext = new DimensionContext())
{
var cDNAddress = await CDNAddress.Get();
var aPIAddress = await APIAddress.Get();
var routeDetails = new RouteDetails(controllerContext);
var canonicalPath = CanonicalPath.Get(routeDetails);
var pageDetailsVM = await dimensionContext.PageDetail
.Where(pde => pde.PageAction.PageController.PageArea.Company.CompanyID == companyID
&& (pde.PageAction.PageController.PageArea.Area == (routeDetails.Area ?? "Home")
&& !pde.PageAction.PageController.PageArea.Excluded)
&& (pde.PageAction.PageController.Controller == routeDetails.Controller
&& !pde.PageAction.PageController.Excluded)
&& (pde.PageAction.Action == routeDetails.Action
&& !pde.PageAction.Excluded))
.Select(pde => new DataPageDetailsVM
{
PageActionID = pde.PageActionID,
CDNAddress = cDNAddress,
APIAddress = aPIAddress,
Title = pde.Title,
FormattedTitle = pde.FormattedTitle,
TagLine = pde.TagLine,
StrapLine = pde.StrapLine,
Latitude = pde.PageAction.PageController.PageArea.Company.CompanyAddress
.Select(sca => sca.Latitude)
.FirstOrDefault(),
Longitude = pde.PageAction.PageController.PageArea.Company.CompanyAddress
.Select(sca => sca.Longitude)
.FirstOrDefault(),
DataRouteVM = new DataRouteVM
{
PrimaryDomain = pde.PageAction.PageController.PageArea.Company.CompanySettings
.Select(scs => scs.PrimaryDomain)
.FirstOrDefault(),
Area = (routeDetails.Area ?? "Home"),
Controller = routeDetails.Controller,
Action = routeDetails.Action
},
DataCompanyVM = new DataCompanyVM
{
CompanyID = companyID,
ShortName = pde.PageAction.PageController.PageArea.Company.ShortName,
LongName = pde.PageAction.PageController.PageArea.Company.LongName
},
PartHeaderVM = new PartHeaderVM
{
ShortName = pde.PageAction.PageController.PageArea.Company.ShortName,
CDNAddress = cDNAddress
},
PartMetaVM = pde.PageAction.PageController.PageArea.Company.CompanySettings
.Select(cse => new PartMetaVM
{
ShortName = pde.PageAction.PageController.PageArea.Company.ShortName,
ShortDescription = pde.ShortDescription,
LongDescription = pde.LongDescription,
Keywords = pde.Keywords,
MsValidate = cse.MsValidate,
FbAppID = cse.FbAppID,
CanonicalPath = cse.PrimaryDomain + "/" + canonicalPath,
OgImage = cse.PrimaryDomain + "/" + pde.OgImage,
ThemeColor = cse.ThemeColor
})
.FirstOrDefault(),
PartLinksVM = new PartLinksVM
{
CanonicalPath = pde.PageAction.PageController.PageArea.Company.CompanySettings
.Select(cse => cse.PrimaryDomain)
.FirstOrDefault() + "/" + canonicalPath,
},
PartBreadcrumbVM = new PartBreadcrumbVM
{
BreadcrumbImage = cDNAddress + pde.BreadcrumbImage,
Area = (routeDetails.Area ?? "Home"),
Controller = routeDetails.Controller,
Action = routeDetails.Action,
Title = pde.Title,
TagLine = pde.TagLine
},
PartFooterVM = new PartFooterVM
{
CDNAddress = cDNAddress,
DataCompanyAddressVM = pde.PageAction.PageController.PageArea.Company.CompanyAddress
.Select(cad => new DataCompanyAddressVM
{
ShortName = cad.Company.ShortName,
LongName = cad.Company.LongName,
Registration = cad.Company.Registration,
AddressLine1 = cad.AddressLine1,
AddressLine2 = cad.AddressLine2,
AddressLine3 = cad.AddressLine3,
AddressLine4 = cad.AddressLine4,
Postcode = cad.Postcode,
Phone = cad.Phone
})
.FirstOrDefault(),
DataCompanySocialVM = pde.PageAction.PageController.PageArea.Company.CompanySocial
.Select(cso => new DataCompanySocialVM
{
FacebookAddress = cso.FacebookAddress,
LinkedInAddress = cso.LinkedInAddress,
TwitterAddress = cso.LinkedInAddress
})
.FirstOrDefault()
}
})
.FirstAsync();
return pageDetailsVM;
}
}
}
My question is I am having to do multiple selects such as:
pde.PageAction.PageController.PageArea.Company.CompanySettings
.Select(scs => scs.PrimaryDomain)
.FirstOrDefault(),
When I am pretty sure I can use .Include at the top some how and the use a . noted value instead.
But I cant seem to work out how.
I hope that makes sense, and any feedback would be appreciated.
Edit - So just to build on this, basically I have a layout that builds all the bits off a layoutvm class then pass all the "bits" to all the partials
<body class="loading-overlay-showing" data-plugin-page-transition data-loading-overlay data-plugin-options="{'hideDelay': 500}">
#Html.Partial("~/Views/Shared/DisplayTemplates/_Loader.cshtml")
<div class="body">
#if (isCustomerArea)
{
#Html.Partial("~/Areas/Customer/Views/Shared/DisplayTemplates/_Header.cshtml", Model.DataPageDetailsVM.PartHeaderVM)
}
else
{
#Html.Partial("~/Views/Shared/DisplayTemplates/_Header.cshtml", Model.DataPageDetailsVM.PartHeaderVM)
}
<main>
#if ((ViewContext.RouteData.Values["controller"].ToString() == "Home" && ViewContext.RouteData.Values["action"].ToString() != "Index") || ViewContext.RouteData.Values["controller"].ToString() != "Home")
{
#Html.Partial("~/Views/Shared/DisplayTemplates/_Breadcrumb.cshtml", Model.DataPageDetailsVM.PartBreadcrumbVM)
}
#RenderBody()
</main>
#if (isCustomerArea)
{
#Html.Partial("~/Areas/Customer/Views/Shared/DisplayTemplates/_Footer.cshtml", Model.DataPageDetailsVM.PartFooterVM)
}
else
{
#Html.Partial("~/Views/Shared/DisplayTemplates/_Footer.cshtml", Model.DataPageDetailsVM.PartFooterVM)
}
</div>
<section>
#Scripts.Render(Model.DataPageDetailsVM.CDNAddress + "Common/js-footer")
#Scripts.Render(Model.DataPageDetailsVM.CDNAddress + CompanyDetails.COMPANYID + "/js-footer")
#RenderSection("scripts", required: false)
</section>
I have a layout class:
public abstract class LayoutVM
{
public virtual DataPageDetailsVM DataPageDetailsVM { get; set; }
}
which pulls all the bits in.
Then each page inherits from that layout vm:
public class PageRetailVM : LayoutVM
{
public SuggestedServicesVM SuggestedServicesVM { get; set; }
}
then my page controller becomes very simple, not only do I get access to all the layout data, but the code for the page becomes really small:
[HttpGet]
[AllowAnonymous]
public async Task<ActionResult> Retail()
{
PageRetailVM pageRetailVM = new PageRetailVM
{
DataPageDetailsVM = await PageDetails.Get(CompanyDetails.COMPANYID, ControllerContext),
SuggestedServicesVM = await PartSuggestedServices.Get(CompanyDetails.COMPANYID, ControllerContext)
};
return View(pageRetailVM);
}
That is what the PageDetails class is for
Include() allows you to indicate which related entities should be read from the database as part of the same query. It allows you to make eager loading for performance purposes.
DbContext class enables lazy loading by default, when the entity is first read, related data isn't retrieved. However, the first time you attempt to access a navigation property, the data required for that navigation property is automatically retrieved. This results in multiple queries sent to the database.
You could Include() related data that you need and simply save it to a variable for further processing.
Related
Hello I have a controller method that I want to return the view model of that looks like this
This is what it would look like if it was hard-coded
public ActionResult SpecialOrderSummary(int? id)
{
// Retrieve data from persistence storage and save it to the view model.
// But here I am just faking it.
var vm = new ItemViewModel
{
ItemId = 123,
ItemName = "Fake Item",
Parts = new List<ItemPartViewModel>
{
new ItemPartViewModel
{
PartId = 1,
PartName = "Part 1"
},
new ItemPartViewModel
{
PartId = 2,
PartName = "Part 2"
}
}
};
return View(vm);
}
But I obviously don't want it hard coded. So this is what I was trying to do instead to achieve my goal
public ActionResult SpecialOrderSummary(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
JobOrder jobOrder = db.JobOrders.Find(id);
if (jobOrder == null)
{
return HttpNotFound();
}
ViewBag.JobOrderID = jobOrder.ID;
ItemInstance ii = db.ItemInstances.Where(x => x.serialNumber == jobOrder.serialNumber).FirstOrDefault();
Item item = db.Items.Find(ii.ItemID);
var vm = new ItemViewModel
{
ItemId = item.ItemID,
ItemName = item.Name,
Parts = new List<ItemPartViewModel>
{
foreach(ItemHasParts ihp in item.IHP)
{
Part part = db.Parts.Find(ihp.PartID);
new ItemPartViewModel
{
PartId = part.ID,
PartName = part.Name
};
}
}
};
return View(vm);
}
But that doesn't work. As it doesn't seem to recognize the closing }
of the opening "Parts" and the opening "vm" bracket as it skips both. Why is this?
Hmmm I thought I answered this question before: https://stackoverflow.com/a/62782124/2410655. Basically you can't have a for loop like that in the middle of the view model.
I would like to add 2 more things to it.
1. Id?
If the special order summary expects an ID, don't declare it as optional. If you do so, you have to add more logic to check whether there is an ID or not.
If the order summary expects an ID, just declare it as int id. And if the client doesn't provide it, let the MVC framework handle the error. Now depending on your setup, your MVC might throw a 404, or 500, or a user-friendly page. It's up to you, the developer, to set it up.
2. Be careful on NullReference Exception
In your code example, I see you used FirstOrDefault() on the item instance. That will bite you if it comes back as NULL and you call db.Items.Find(ii.ItemID)...
So based on your example, I would change the code to:
public ActionResult SpecialOrderSummary(int id)
{
JObOrder jobOrder = db.JobOrders.Find(id);
if (jobOrder == null)
{
return HttpNotFound();
}
ItemInstance itemInstance = db.ItemInstances
.Where(x => x.serialNumber == jobOrder.serialNumber)
.FirstOrDefault();
Item item = null;
if (itemInstance != null)
{
item = db.Items.Find(itemInstance.ItemID);
}
var vm = new JobOrderSummaryViewModel
{
JobOrderId = jobOrder.ID,
Parts = new List<ItemPartViewModel>();
};
if (item != null)
{
vm.ItemId = item.ItemId;
vm.ItemName = item.ItemName;
foreach(ItemHasParts ihp in item.IHP)
{
// Does Part and Item have many-to-many relationships?
// If so, you might be able to get the part by
// ihp.Part instead of looking it up using the ID.
// Again, it depends on your setup.
Part part = db.Parts.Find(ihp.PartID);
if (part != null)
{
vm.Parts.Add(new ItemPartViewModel
{
PartId = part.ID,
PartName = part.Name
});
}
}
}
return View(vm);
}
Note:
You have additional calls back to the database inside the loop (db.Parts.Find(ihp.PartID);). That will cause performance issue if you have huge data. Is there any way you can fetch all your data you needed once at the beginning?
I am looking to implement a Tab Menu that uses the same View and Partial View. But then when you click either of the tabs its updated based on the comparison in the Model. The Controller works out if its an Original or Amendment. So far I have the two tabs showing using:
var fullAccountCodeOriginal = Model.OriginalWriter.ID;
var fullAccountCodeAmendment = Model.ActiveAmendmentWriter.ID;
<div class="page-tabs">
<ul class="nav nav-tabs">
<li class='#((actionName.ToLower() == "viewwriteramendments") &&
controllerName.ToLower() == "songsmanagement" ? "active" : "")'>
<a href='#Url.Action("ViewWriterAmendments", "SongsManagement", new
{
accountcode = fullAccountCodeOriginal
})' data-container="body" data-toggle="tooltip" title="Song Management">Original Track Details</a>
</li>
<li class='#((actionName.ToLower() == "viewwriteramendments") &&
controllerName.ToLower() == "songsmanagement" ? "active" : "")'>
<a href='#Url.Action("ViewWriterAmendments", "SongsManagement", new
{
accountcode = fullAccountCodeAmendment
})' data-container="body" data-toggle="tooltip" title="Song Management">Updated Track Details</a>
</li>
}
</ul>
In the Model is have:
public ViewWriterAmendmentsComparisonModel()
{
this.OriginalWriter = default(WriterAmendmentsComparisionModel);
this.ActiveAmendmentWriter = default(WriterAmendmentsComparisionModel);
}
public WriterAmendmentsComparisionModel OriginalWriter { get; set; }
public WriterAmendmentsComparisionModel ActiveAmendmentWriter { get; set; }
Controller
var writerAndActiveAmendment = new ViewWriterAmendmentsComparisonModel
{
OriginalWriter = new WriterAmendmentsComparisionModel
{
ID = domainWriterAndAmendmentModel.Original.ID,
RowVersion = domainWriterAndAmendmentModel.Original.RowVersion,
IsDeleted = domainWriterAndAmendmentModel.Original.IsDeleted,
IsLocked = domainWriterAndAmendmentModel.Original.IsLocked,
IsNew = domainWriterAndAmendmentModel.Original.IsNew,
Version = domainWriterAndAmendmentModel.Original.Version,
FirstName = domainWriterAndAmendmentModel.Original.FirstName,
MiddleName = domainWriterAndAmendmentModel.Original.MiddleName,
LastName = domainWriterAndAmendmentModel.Original.LastName,
PRO = domainWriterAndAmendmentModel.Original.Society?.Name ?? string.Empty,
CaeIpiNumber = domainWriterAndAmendmentModel.Original.CaeIpiNumber,
IsProMember = domainWriterAndAmendmentModel.Original.IsProMember,
Songs = domainWriterAndAmendmentModel.Original.WriterSplits != null
? domainWriterAndAmendmentModel.Original.WriterSplits
.Select(x => new AssociatedSongsComparisonModel
{
// meta
ID = x.ID,
RowVersion = x.RowVersion,
IsDeleted = x.IsDeleted,
// data
SongTitle = x.RelatedWork.Title,
SongId = x.RelatedWork.UniqueCode,
CreatedDate = x.RelatedWork.CreatedDate,
WriterCount = x.RelatedWork.WorkSplits.Count,
RecordingCount = x.RelatedWork.Recordings.Count
})
.ToList()
: new List<AssociatedSongsComparisonModel>(),
},
ActiveAmendmentWriter = new WriterAmendmentsComparisionModel
{
ID = domainWriterAndAmendmentModel.CurrentAmendment.ID,
RowVersion = domainWriterAndAmendmentModel.CurrentAmendment.RowVersion,
IsDeleted = domainWriterAndAmendmentModel.CurrentAmendment.IsDeleted,
IsNew = domainWriterAndAmendmentModel.CurrentAmendment.IsNew,
FirstName = domainWriterAndAmendmentModel.CurrentAmendment.FirstName,
MiddleName = domainWriterAndAmendmentModel.CurrentAmendment.MiddleName,
LastName = domainWriterAndAmendmentModel.CurrentAmendment.LastName,
PRO = domainWriterAndAmendmentModel.CurrentAmendment.Society?.Name ?? string.Empty,
CaeIpiNumber = domainWriterAndAmendmentModel.CurrentAmendment.CaeIpiNumber,
IsProMember = domainWriterAndAmendmentModel.CurrentAmendment.IsProMember,
Songs = domainWriterAndAmendmentModel.CurrentAmendment.WriterSplitAmendments != null
&& domainWriterAndAmendmentModel.CurrentAmendment.WriterSplitAmendments.Any(x => x.RelatedWorkAmendment != null)
? domainWriterAndAmendmentModel.CurrentAmendment.WriterSplitAmendments
.Select(x => new AssociatedSongsComparisonModel
{
// meta
ID = x.ID,
RowVersion = x.RowVersion,
IsDeleted = x.IsDeleted,
// data
SongId = x.RelatedWorkAmendment.UniqueCode,
SongTitle = x.RelatedWorkAmendment.Title,
CreatedDate = x.RelatedWorkAmendment.CreatedDate,
WriterCount = x.RelatedWorkAmendment.WorkSplitAmendments.Count,
RecordingCount = x.RelatedWorkAmendment.RecordingAmendments.Count
})
.ToList()
: new List<AssociatedSongsComparisonModel>(),
}
};
return writerAndActiveAmendment;
}
[HttpGet]
[ActionName("ViewWriterAmendments")]
[Route("{writercode}/ViewWriterAmendments")]
[AuthorizeTenancy(Roles = "super,administrator")]
public async Task<ActionResult>ViewWriterAmendments(string writercode, int page = 1, int take = Constants.MVC.Pagination.DefaultItemsPerPage, string sortBy = "Name", bool sortAsc = true)
{
if (Request.QueryString["IsAmendment"] != null)
{
ViewBag.IsAmendment = Request.QueryString["IsAmendment"];
}
else
{
ViewBag.IsAmendment = "0";
}
// TEST IF VALID
// ajax method - refuse
if (Request.IsAjaxRequest())
{
return RedirectToAction("WriterAmendments", "SongsManagement");
}
// no writer - refuse
if (string.IsNullOrEmpty(writercode))
{
return RedirectToAction("WriterAmendments", "SongsManagement", new { page, take, sortBy, sortAsc });
}
// get originalWithPossibleActiveAmendment work
var writerAndAmendment = await _artistAccountService.GetWriterAndAmendmentGraphAsync(writercode, includeWritersSplitsAndWorks: true, includeWriterSociety: true);
// not found? - refuse
if (writerAndAmendment.Original == default(WriterGraph.Writer))
{
return RedirectToAction("WriterAmendments", "SongsManagement", new { page, take, sortBy, sortAsc }); // something wrong
}
// writer locked? - refuse
if (writerAndAmendment.Original.IsLocked)
{
return RedirectToAction("WriterAmendments", "SongsManagement", new { page, take, sortBy, sortAsc }); // something wrong
}
// setup view model
var viewModel = MapWriterAndAmendmentToViewModel(writerAndAmendment);
// return view
return View(viewModel);
}
}
}
Is there a way I can get it switch betwwen the two tabs using JQuery or another method, maybe an IF/ELSE in Razor. I am new to MVC.
You can just use jQuery so in Controller you got for example Enum param (if more than 2 cases of data loading) or boolean flag, which content to load. Than based on the parameter you've received you make an if statement inside controller to decide what data you should load. It's pretty simple, I won't give you fish but a rod. Read about overriding in jQuery button on click event and sending ajax requests.
Extra advice. IMHO this looks horrible
<li class='#((actionName.ToLower() == "viewwriteramendments") &&
controllerName.ToLower() == "songsmanagement" ? "active" : "")'>
<a href='#Url.Action("ViewWriterAmendments", "SongsManagement", new
{
accountcode = fullAccountCodeAmendment
})' data-container="body" data-toggle="tooltip" title="Song Management">Updated Track Details</a>
</li>
Passing active class should be done inside jQuery too.
If you create repeatable li elements you could think about making another partial view for them. For 2 it's fine but for more elements create seperate view.
Change the a href to some button and override it's default behavior.
Naming conventions - try to name your ids and classes with some stable convention for whole project.
I am building an restaurantfinder website with EPiServer and I'm using EPiFind to search on the site. I've encountered a problem though. I'm trying to facet a pagetype in the pagetree, although I'm only searching in one specific pagetype. My goal is to be able to print out the titles of the pagetype. So if I search for example Sweden, all cities that's in the pagetree should be listed with their names in the facet.
My code:
if (query == null && tags == null && cities == null)
{
return View();
}
var q = SearchClient.Instance.Search<RestaurantPage>()
.For(query)
.TermsFacetFor(x => x.CityPage.HeadLine);
if (!string.IsNullOrWhiteSpace(cities))
{
q = q.Filter(x => x.HeadLine.MatchCaseInsensitive(cities));
}
var results = q.Select(x => new SearchHit
{
Title = x.HeadLine,
Url = x.LinkURL,
Tag = x.Tags,
Adress = x.Adress,
Latitude = x.Latitude,
Longitude = x.Longitude,
Image = x.RestaurantImage
}).GetResult();
ViewBag.Query = query;
ViewBag.Id = results.ProcessingInfo.ServerDuration;
ViewBag.Hits = results.TotalMatching;
var facets = new List<FacetResult>();
var testFacet = (TermsFacet)results.Facets["CityPage.HeadLine"];
var testLinks = new FacetResult("Cities", testFacet.Terms.Select(x => new FacetLink
{
Text = x.Term,
Count = x.Count,
}));
facets.Add(testLinks);
ViewBag.Filters = new List<FacetLink>();
if (!string.IsNullOrEmpty(tags))
{
ViewBag.Filters.Add(new FacetLink
{
Text = tags,
Url = Url.QueryBuilder(currentPage.ContentLink).AddSegment("?query=" + query).ToString()
});
}
return View(new SearchResult(results, query) {Facets = facets});
In order to retrieve the facets, you could do:
results.TermsFacetFor<RestaurantPage>(x => x.CityPage.HeadLine)
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.
I want to update my model through a class and not a form in ASP.Net MVC 2.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(string wo_number)
{
WorkOrder wo = GetWorkOrder(wo_number);
UpdateModel(wo);
camprintRepository.Save();
return RedirectToAction("Details", new { wo_number = wo_number });
}
I'm pulling the information from an outside source and I want it to update the entities in my applications database.
public WorkOrder GetWorkOrder (string wo_number)
{
UniFile uFile = uSession.CreateUniFile("WO");
uFile.RecordID = wo_number;
WO wo = new WO();
wo.wo_id = wo_number;
wo.sales_product_code = uFile.ReadNamedField("Sales_Code").ToString();
wo.description = uFile.ReadNamedField("P_Desc").ToString();
wo.part_number = uFile.ReadNamedField("Desc").ToString();
wo.work_order_quantity = uFile.ReadNamedField("Qty_To_Mfg").ToString();
wo.sales_order_quantity = uFile.ReadNamedField("Sod_Qty").ToString();
GetWorkOrderOper(wo);
}
I am using LINQ to SQL and as you can see there are some child objects that branch off from each workorder.
public void GetWorkOrderOper(WorkOrder wo)
{
UniFile uFile = uSession.CreateUniFile("WPO");
string key = wo.wo_id + "*" + wo.first_routing_sequence;
while(key != wo.wo_id + "*")
{
uFile.RecordID = key;
WPO wpo = new WPO();
wpo.wpo_id = key;
wpo.next_sequence_number = uFile.ReadNamedField("Next_Seq").ToString();
wpo.run_hours = uFile.ReadNamedField("Plan_Run_Lbr_Time").ToString();
key = wo.wo_id + "*" + wpo.next_sequence_number;
wo.WPOs.Add(wpo);
}
}
This is not updating the models and I'm not sure why. Any help would be greatly appreciated
Seems like there is no SubmitChanges? Or is that in your UpdateModel?
Another cause might be no primary key in your underlying table