How to make Delete and Edit methods in MVC without DB - c#

I am building a simple MVC CRUD without using a database, but just making methods in a Repository model class.
To make it easier to understand i have 2 model classes. MyNote in which i have some properties and NoteRepository in which i have a list with the properties.
Then I've made a NoteController and i have already made Get and Create methods, but i can't seem to figure out what to write to make an Edit and Delete method? Hope you guys can help.
Here you will see some of the code from my project:
[HttpPost]
public ActionResult Create(MyNote mn)
{
try
{
note.Create(mn);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
this is the create from the Controller.
public static List<MyNote> notes = new List<MyNote>();
public NoteRepository()
{
notes.Add(new MyNote() { ID = 1, Titel = "Morgenmad", OprettelsesDato = DateTime.Now, Note = "Spis morgenmad i dag" });
notes.Add(new MyNote() { ID = 2, Titel = "Frokost", OprettelsesDato = DateTime.Now, Note = "Spis frokost i dag" });
notes.Add(new MyNote() { ID = 3, Titel = "Aftensmad", OprettelsesDato = DateTime.Now, Note = "Spis aftensmad i dag" });
}
public void Create(MyNote mn)
{
notes.Add(mn);
}
here is the repository class with the list and the method for the create method.
and please, ask if i have missed something! Thank you :-)

It looks like you're using a List for your in-memory repository. For delete, you can implement something like this:
public bool Delete (MyNote noteToDelete) {
return notes.Remove(noteToDelete);
}
Edit: However, in this case, the list will check for reference equality. Since you have an ID, which I will assume is unique, you can instead do this:
public bool Delete(MyNote noteToDelete) {
var matchingNote = notes.FirstOrDefault(n => n.ID == noteToDelete.ID);
return notes.Remove(matchingNote);
}
You could also implement IEquatable on your MyNote class to change how your notes are compared with each other, and return a valid match when the IDs are the same.
For the IEquatable example, you would want to change the class definition for MyNote to look like:
public class MyNote : IEquatable<MyNote>
and add in the following code to the MyNote class:
public override bool Equals(object obj) {
if (obj == null) return false;
Part objAsNote = obj as MyNote;
if (objAsNote == null) return false;
else return Equals(objAsNote);
}
public bool Equals(MyNote otherNote) {
if(otherNote == null) return false;
return (this.ID.Equals(otherNote.ID));
}
public override int GetHashCode(){
return this.ID;
}

You can do something like this:
public ActionResult Edit(MyNote noteToEdit)
{
var oldNote = notes.FirstOrDefault(n => n.Id == noteToEdit.Id);
if(oldNote == null)
return View(); //With some error message;
oldNote.Title = noteToEdit.Title;
oldNote.OprettelsesDato = DateTime.Now;
oldNote.Note = noteToEdit.Note;
return RedirectToAction("Index", "Note");
}
public ActionResult Delete(int id)
{
var noteToRemove = notes.FirstOrDefault(x => x.Id == id);
if(noteToRemove == null)
return View(); //With some error message;
notes.Remove(noteToRemove);
return RedirectToAction("Index", "Note");
}
When you are editing your note, i recommend you to use AutoMapper to make your code more easy to maintain.

Related

Show buttons on a partial view based on some query

I am showing search results same as searching groups on facebook
enter image description here
I have a relationship Table named CommunityUser in Database having attributes CommunityID and UserID.
Using Partial View I want to show if User not already joined that Community/Group that it will show Join Button else if user already joined that community it will show Leave button.
I have written IsMember() function in my controller that takes two parameters, CommunityID and UserID. This will return true if that Community ID exist against that user ID.
public bool IsMember(string UserID, int CommunityID) {
var Membership = db.Users.Include(x => x.CommunityUsers).Where(s => s.Id.Equals(UserID)).Count();
if(Membership>0)
return true;
else
return false;
}
Now what I actually need is, I want to call this function in an IF condition on my view class. It is not allowing me to call this function on my view Class.
#if (){
<button>#Html.ActionLink("Leave", "LeaveCommunity", new { id = ViewBag.ComID })</button>
}
else
{
<button>#Html.ActionLink("Join", "joinCommunity", new { id = ViewBag.ComID })</button>
}
In your controller you should have a method which will return this view. So in this method you call this function
public ActionResult Index(string UserID, int CommunityID)
{
var hasMembership = IsMember(serID, CommunityID);
return View(hasMembership);
}
In the View it self then you just grab this variable hasMembership you just passed from #model.
#if (Model){
<button>#Html.ActionLink("Leave", "LeaveCommunity", new { id = ViewBag.ComID })</button>
}
else
{
<button>#Html.ActionLink("Join", "joinCommunity", new { id = ViewBag.ComID })</button>
}
Note: it might be wise to create some DTO class for passing data to a view, because you might need to pass multiple value to a view at some point. Plus the whole condition would be more readable
public SomeDTO {
public bool IsMember {get;set}
public List<Community> Communities {get;set;}
}
public ActionResult Index(string UserID, int CommunityID)
{
var hasMembership = IsMember(serID, CommunityID);
var listOfCommunities = _repo.GetComunities();
var dto = new SomeDTO
{
IsMember = hasMembership,
Communities = listOfCommunities
}
return View(dto);
}
#if (Model.IsMember){
// do or do not something
}

One to zero or one relationship error when create/update related model asp.net EF6

I need to map two entities with one to zero or one relationship. when I create a principal object it works.
I have the following models:
//Principal class
public class Sugerencia
{
public int ID { get; set; }
[DisplayName("Título")]
public string Titulo { get; set; }
//More properties simplified for example
}
//Related class
public class Resultado
{
[ScaffoldColumn(false)]
public int SugerenciaID { get; set; }
[ScaffoldColumn(false)]
public int ID { get; set;}
//More properties
}
This is my DbContext Class
public class SugerenciaContext : DbContext
{
public SugerenciaContext() : base("SugerenciaContext")
{
}
public DbSet<Sugerencia> Sugerencias { get; set; }
public DbSet<Resultado> Resultados { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Resultado>()
.HasRequired(r => r.Sugerencia)
.WithOptional(s => s.Resultado);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Note the OnModelCreate overriding for map the relationship.
This is the ResultadoController Create actions (POST and GET)
//GET
public ActionResult Create(int? id)
{
ViewBag.ID = new SelectList(db.Sugerencias, "ID", "Titulo");
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
//I am retrieving the principal model instance to set resultado.Sugerencia property.
Sugerencia sugerencia = db.Sugerencias.Find(id);
if (sugerencia == null)
{
return HttpNotFound();
}
Resultado resultado = new Resultado();
resultado.Sugerencia = sugerencia;
return View(resultado);
}
//POST
public ActionResult Create([Bind(Include = "ID,SugerenciaID,Responsable,Resultados,Fecha")] Resultado resultado, string status)
{
if (ModelState.IsValid)
{
resultado.Fecha = System.DateTime.Now;
Sugerencia sugerencia = db.Sugerencias.Find(resultado.ID);
if (sugerencia == null)
{
return HttpNotFound();
}
sugerencia.Status = status;
//Here I am modifying the state property of Sugerencia model.
db.Entry(sugerencia).State = EntityState.Modified;
db.Entry(resultado).State = resultado.ID == 0 ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ID = new SelectList(db.Sugerencias, "ID", "Titulo", resultado.ID);
return View(resultado);
}
The error I am getting is triggered in db.SaveChenges();line. When I am trying to add a new Resultado model. However when I invoke the Create action for a principal instance which already has a related object in the DB it recreates the object rewriting the values on DB as expected.
In the create view of Resultado controller I have to update one property of Sugerencia model.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded
Note I am inserting or modifying the instance. I am debugging via Command Window and setting a breakpoint at that line. When printing resultado and sugerencia variables all properties seem to be valid.
Thanks for considering my question.
Looking at your code, this is what I think is happening:
// This is not needed, by the way, since the previous line should have done this
db.Entry(sugerencia).State = EntityState.Modified;
// This is probably setting resultado's state to Modified, even for new items!
db.Entry(resultado).State = resultado.ID == 0 ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
First of all, when would you need to set the resultado state to EntityState.Modified in a Create action? Also, I'm guessing that your model configuration is setting Resultado.ID as the foreign key, so when you previously set resultado.Sugerencia = sugerencia, Resultado.ID was set to a value not equal to zero.
You should be fine with
db.Entry(resultado).State = EntityState.Added;

How to create multiple POST methods on an Azure Mobile Service?

I have an Azure Mobile Service with multiple controllers. One of my controllers (TestSetController) has some extra methods to check on insert.
Problem I need to solve: The TestSet table has two different types of TestSets, one for a local team and another for a field team. The table contains data for both and the records are differentiated by a "TeamType" field which says if the local team inserted the TestSet or the field team did. On any insert I want to check if a similar TestSet exists that was inserted by the other team. I want to compare the TestSets (if found) then do some other inserts/updates on the same table if the TestSets are different.
However, I keep getting this error:
Exception=System.InvalidOperationException: Multiple actions were found that match the request:
PostTestSetDTO on type sbp_ctService.Controllers.TestSetController
CheckForDiscrepancy on type sbp_ctService.Controllers.TestSetController
CompareTestPointAttempts on type sbp_ctService.Controllers.TestSetController
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext(), Id=f07761ae-1be7-4f00-90b0-685dd0c108f3, Category='App.Request'
Here's my controller:
public class TestSetController : TableController<TestSetDTO>
{
private Context context;
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
context = new Context();
DomainManager = new SimpleMappedEntityDomainManager<TestSetDTO, TestSet>(context, Request, Services, testset => testset.Id);
}
// GET tables/TestSet
[QueryableExpand("TestPointAttempts")]
public IQueryable<TestSetDTO> GetAllTestSetDTO()
{
return Query();
}
// GET tables/TestSet/48D68C86-6EA6-4C25-AA33-223FC9A27959
public SingleResult<TestSetDTO> GetTestSetDTO(string id)
{
return Lookup(id);
}
// PATCH tables/TestSet/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task<TestSetDTO> PatchTestSetDTO(string id, Delta<TestSetDTO> patch)
{
return UpdateAsync(id, patch);
}
// POST tables/TestSet/48D68C86-6EA6-4C25-AA33-223FC9A27959
public async Task<IHttpActionResult> PostTestSetDTO(TestSetDTO item)
{
TestSet testSet = AutoMapper.Mapper.Map<TestSetDTO, TestSet>(item);
this.CheckForDiscrepancy(testSet);
TestSetDTO current = await InsertAsync(item);
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
// DELETE tables/TestSet/48D68C86-6EA6-4C25-AA33-223FC9A27959
public Task DeleteTestSetDTO(string id)
{
return DeleteAsync(id);
}
public TestSet CheckForDiscrepancy(TestSet sourceTestSet)
{
// Set the team type to search for opposite to the one being posted.
string searchTeamType = null;
if (sourceTestSet.TestTeamType == "D")
{
searchTeamType = "F";
}
if (sourceTestSet.TestTeamType == "F")
{
searchTeamType = "D";
}
var testSetTable = context.TestSets;
TestSet foundTestSet = (from ts in testSetTable
where ts.TileId == sourceTestSet.TileId && ts.ScenarioId == sourceTestSet.ScenarioId && ts.TestTeamType.StartsWith(searchTeamType)
select ts).SingleOrDefault();
// If no other test set was found from the opposing team then the test set is missing.
// Else a testSet was found so continue with checks.
if (foundTestSet == null)
{
sourceTestSet.DiscrepancyTypeId = DiscrepancyType.Missing.ToString();
}
else
{
var testPointAttemptTable = context.TestPointAttempts;
// Get all of the associated TestPointAttempts for each testSet.
sourceTestSet.TestPointAttempts = (from tpa in testPointAttemptTable
where tpa.TestSetId == sourceTestSet.Id
orderby tpa.TestAttemptNumber
select tpa).ToList<TestPointAttempt>();
foundTestSet.TestPointAttempts = (from tpa in testPointAttemptTable
where tpa.TestSetId == foundTestSet.Id
orderby tpa.TestAttemptNumber
select tpa).ToList<TestPointAttempt>();
bool matchingTestSets = CompareTestPointAttempts(sourceTestSet.TestPointAttempts, foundTestSet.TestPointAttempts);
if (!matchingTestSets)
{
sourceTestSet.DiscrepancyTypeId = DiscrepancyType.Discrepancy.ToString();
sourceTestSet.DiscrepancyTestSetId = foundTestSet.Id;
}
}
return sourceTestSet;
}
public bool CompareTestPointAttempts(IEnumerable<TestPointAttempt> sourceTPAs, IEnumerable<TestPointAttempt> foundTPAs)
{
bool pass = false;
// First check if the total number of testPointAttempts are the same
if (sourceTPAs.Count() == foundTPAs.Count())
{
foreach (TestPointAttempt sTpa in sourceTPAs)
{
bool foundMatch = false;
foreach (TestPointAttempt fTpa in foundTPAs)
{
if (sTpa.TestAttemptNumber == fTpa.TestAttemptNumber)
{
if (sTpa.TalkIn == fTpa.TalkIn && sTpa.TalkOut == fTpa.TalkOut)
{
foundMatch = true;
}
}
}
if (!foundMatch)
{
return pass;
}
}
// The foreach loop finished successfully meaning all matches were found
pass = true;
}
return pass;
}
/// <summary>
/// The type of discrepancy a TestSet can have.
/// </summary>
public enum DiscrepancyType
{
Discrepancy,
Missing,
None
}
}
}
I'm using Data Transfer Objects (DTOs) to map between the entity models. Any help would be appreciated. I've looked at some different answers on StackOverflow for ASP.NET but they all talk about updating the config.Routes. This is for an Azure Mobile Service which might have different requirements than a simple ASP.NET website though.
It was as simple as making the two methods private and leaving the actual POST method as public. ASP.NET will only make routes automatically for public methods.

C# Enum - How to Compare Value

How can I compare the value of this enum
public enum AccountType
{
Retailer = 1,
Customer = 2,
Manager = 3,
Employee = 4
}
I am trying to compare the value of this enum in an MVC4 controller like so:
if (userProfile.AccountType.ToString() == "Retailer")
{
return RedirectToAction("Create", "Retailer");
}
return RedirectToAction("Index", "Home");
I also tried this
if (userProfile.AccountType.Equals(1))
{
return RedirectToAction("Create", "Retailer");
}
return RedirectToAction("Index", "Home");
In each case I get an Object reference not set to an instance of an object.
use this
if (userProfile.AccountType == AccountType.Retailer)
{
...
}
If you want to get int from your AccountType enum and compare it (don't know why) do this:
if((int)userProfile.AccountType == 1)
{
...
}
Objet reference not set to an instance of an object exception is because your userProfile is null and you are getting property of null. Check in debug why it's not set.
EDIT (thanks to #Rik and #KonradMorawski) :
Maybe you can do some check before:
if(userProfile!=null)
{
}
or
if(userProfile==null)
{
throw new ArgumentNullException(nameof(userProfile)); // or any other exception
}
You can use Enum.Parse like, if it is string
AccountType account = (AccountType)Enum.Parse(typeof(AccountType), "Retailer")
Comparision:
if (userProfile.AccountType == AccountType.Retailer)
{
//your code
}
In case to prevent the NullPointerException you could add the following condition before comparing the AccountType:
if(userProfile != null)
{
if (userProfile.AccountType == AccountType.Retailer)
{
//your code
}
}
or shorter version:
if (userProfile !=null && userProfile.AccountType == AccountType.Retailer)
{
//your code
}
You can use extension methods to do the same thing with less code.
public enum AccountType
{
Retailer = 1,
Customer = 2,
Manager = 3,
Employee = 4
}
static class AccountTypeMethods
{
public static bool IsRetailer(this AccountType ac)
{
return ac == AccountType.Retailer;
}
}
And to use:
if (userProfile.AccountType.isRetailer())
{
//your code
}
I would recommend to rename the AccountType to Account. It's not a name convention.
You should convert the string to an enumeration value before comparing.
Enum.TryParse("Retailer", out AccountType accountType);
Then
if (userProfile?.AccountType == accountType)
{
//your code
}

A circular reference was detected while serializing an object of type in asp.net mvc c#

I tried to search but cannot solve my problem.
This is my controller :
public JsonResult Index()
{
return this.Json(TempData["displayList"], JsonRequestBehavior.AllowGet);
}
public JsonResult AddToCart(string id)
{
QuotationModels objQuote = new QuotationModels();
List<QuotationModels> listQuote = objQuote.GetObjectInSession;
int itemID = Int32.Parse(id);
int index = -1;
if(listQuote != null)
index = listQuote.FindIndex(p => p.ItemdID== itemID);
if (index >= 0)
{
listQuote[index].ProductQty++;
objQuote.AddToSession(listQuote);
}
else
{
int _id = Convert.ToInt16(id);
var _product = DataContext.DataContext.Items.FirstOrDefault(s => s.ID == _id);
QuotationModels quote = new QuotationModels();
quote.ItemdID = _product.ID;
quote.ItemNote = _product.Notes;
quote.Phone = "";
quote.PictureName = _product.PictureName;
quote.ProductName = _product.Name;
quote.ProductPrice = (decimal)_product.Price;
quote.ProductQty = 1;
quote.ShoppingCartId = "";
quote.Total = 0;
quote.Email = "";
quote.CustomerID = 0;
quote.CusName = "";
quote.Company = "";
quote.Address = "";
objQuote.AddToSession(quote);
}
int itemInSession = objQuote.GetObjectInSession.Sum(s => s.ProductQty);
TempData["displayList"] = objQuote.GetObjectInSession;
return Json(new
{
ja = itemInSession
}, JsonRequestBehavior.AllowGet);
}
But when I browse the Index() view, It was an error A circular reference was detected while serializing an object of type.
Can any one give me the solution please. Thank you so much.
I'm not sure what you're trying to serialize, but here is a clue about what you have to do !
The problem of the circular reference means that you have for exemple a Quote, which contains a reference to a Product. And that that Product itsel has a reference to the parent Quote.
You can't serialize that simply in JSON, cause it would do something like this:
Quote :
- some attributes..
- Product
- some attributes
- Quote
- some attributes...
- Product... and so on !
But now, if you have the parent Quote, is it really interesting for you to have the relationship on the child entity ? Maybe in your server-side model, but it's kind of redundant and not necessary for the client.
What you could do in that case is create other classes which don't contain what is not necessary and could result in circular reference.
You'll have for example a SimpleQuote, which is like a Quote, but instead of having a Product property, it will have a SimpleProduct property.
Original classes :
public class Quote{
public int Id;
public Product Product;
public double Amount;
}
public class Product{
public int Id;
public Quote Quote;
public string Name;
}
Simple classes for serialization :
public class SimpleQuote{
public int Id;
public SimpleProduct Product;
public double Amount;
}
public class SimpleProduct{
public int Id;
public int QuoteId;
public string Name;
}
Now you can create extensions methods like :
public static void ToSimpleQuote(this Quote quote){
return new SimpleQuote(){
Id = quote.Id,
Amount = quote.Amount,
Product = quote.Product.ToSimpleProduct()
};
}
public static void ToSimpleProduct(this Product product){
return new SimpleProduct(){
Id = product.Id,
Name = product.Name,
QuoteId = product.Quote.QuoteID
};
}
So if you had something like :
public ActionResult Index(){
....
return Json(myQuote, JsonRequestBehavior.AllowGet);
}
you can now do this instead :
public ActionResult Index(){
....
return Json(myQuote.ToSimpleQuote(), JsonRequestBehavior.AllowGet);
}
Don't return this. Instead use:
public JsonResult Index()
{
return Json(TempData["displayList"], JsonRequestBehavior.AllowGet);
}
Can you show the object graph of what is in TempData["displayList"]?
You might have a looping hierarchy.
You can use the attributes XMLIgnore for strict XML Serializing or NonSerialized for broader targets.
Simply mark the properties or fields that are circular with either of these attributes and it should ignore them.
Works well in Entity Framework scenarios with virtual members properties that are indeed circular references.

Categories

Resources