A referential integrity constraint violation On Update with DbContext - asp.net-mvc-4

Please see below my Model class, my controller action and my view.
When I edit from my view I have got the exception :A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
I have already asked this question, but I have got no answers; pls help!!
public partial class Organization : ILockable, IAuditable, IEntity
{
/*** Construtor(s) ***/
public Organization()
{
}
public Organization(Party obj)
: this()
{
Party = obj;
}
/*** Public Members ***/
[Key, Display(Name = "Id")]
public int PartyId { get; set; }
/* IEntity */
public string Caption { get; set; }
public string NameInUse { get; set; }
public string Description { get; set; }
/* IAuditable */
[NotMapped, ScaffoldColumn(false)]
public System.DateTimeOffset Created
{
get { return Party.Created; }
set { Party.Created = value; }
}
[NotMapped, ScaffoldColumn(false)]
public string CreatedBy
{
get { return Party.CreatedBy; }
set { Party.CreatedBy = value; }
}
[NotMapped, ScaffoldColumn(false)]
public Nullable<System.DateTimeOffset> LastMod
{
get { return Party.LastMod; }
set { Party.LastMod = value; }
}
[NotMapped, ScaffoldColumn(false)]
public string LastModBy
{
get { return Party.LastModBy; }
set { Party.LastModBy = value; }
}
[NotMapped, Display(Name = "Del?")]
public bool IsSoftDeleted
{
get { return Party.IsSoftDeleted; }
set { Party.IsSoftDeleted = value; }
}
[NotMapped, ScaffoldColumn(false)]
public Nullable<System.DateTimeOffset> SoftDeleted
{
get { return Party.SoftDeleted; }
set { Party.SoftDeleted = value; }
}
[NotMapped, ScaffoldColumn(false)]
public string SoftDeletedBy
{
get { return Party.SoftDeletedBy; }
set { Party.SoftDeletedBy = value; }
}
/* ILockable */
public string GetTableName()
{
return "Organization";
}
public int GetLockId()
{
return this.PartyId;
}
/* Navigation Properties */
/// <summary>
/// Foreign key to Party: PartyId
/// Organization is subtype of Party
/// </summary>
public virtual Party Party { get; set; }
}
Controller Edit Action:
[HttpPost]
public ActionResult Edit(Organization obj)
{
//remove the lock since it is not required for inserts
if (ModelState.IsValid)
{
OrganizationRepo.Update(obj);
UnitOfWork.Save();
LockSvc.Unlock(obj);
return RedirectToAction("List");
}
else
{
return View();
}
}
View:
#using PartyBiz.Models.Objects
#using d2Utils.Reflection
#model IEnumerable<Organization>
#{
ViewBag.Title = "Details";
}
<table>
<tr>
<th>
#Html.Raw("Caption")
</th>
<th></th>
</tr>
<tr>
<td colspan="4">
#foreach (var item in Model)
{
<table>
<tr>
#using (Html.BeginForm("Edit", "Organization", FormMethod.Post))
{
<td >
#Html.TextBox("Caption", item.GetValForProp<string>("Caption"), new { #class = "txt" })
</td>
<td >
#Html.TextBox("NameInUse", item.GetValForProp<string>("NameInUse"), new { #class = "txt" })
</td>
<td >
#Html.TextBox("Description", item.GetValForProp<string>("Description"), new { #class = "txt" })
</td>
<td>
<input type="hidden" name="PartyId" value="#item.PartyId"/>
<button type="submit">Edit</button>
</td>
}
</tr>
</table>
}
</td>
</tr>
</table>
Context Method:
public virtual void Update(T obj)
{
IAuditable audit = obj as IAuditable;
IOverTime overtime = obj as IOverTime;
// Existing entity
D2Repository.Updated(ref audit, UserName);
D2Repository.FromDate(ref overtime);
Set.Attach(obj);
Ctxt.Entry(obj).State = EntityState.Modified;
}

I have added
obj.Party.PartyId = obj.PartyId;
in my edit action and it is working now.
I still want to know if this is the correct way of doing it?

Related

DynamicComponent send value from child to the parent

I have a class that represents the necessary data for creating a DynamicComponent:
public class ComponentMetadata
{
public string? Name { get; set; }
public Dictionary<string, object> Parameters { get; set; } =
new Dictionary<string, object>();
}
I have a custom table component that uses ComponentMetadata to add some dynamic component to the table:
TableTemplate.razor:
<table class="table">
<thead>
<tr>#TableHeader</tr>
</thead>
<tbody>
#foreach (var RowTemplateConfig in RowTemplateConfigs)
{
if (RowTemplateConfig.DataItem is not null)
{
<tr>
<td> #RowTemplateConfig.DataItem </td>
#if(RowTemplateConfig.ComponentMetadata is not null)
{
<td>
<DynamicComponent
Type= RowTemplateConfig.ComponentMetadata.Name
Parameters= RowTemplateConfig.ComponentMetadata.Parameters />
</td>
}
</tr>
}
}
</tbody>
</table>
#code {
public class RowTemplateConfig
{
public ComponentMetadata ComponentMetadata { get; set;}
public string DataItem { get; set; }
}
[Parameter]
public RenderFragment? TableHeader { get; set; }
[Parameter]
public List<RowTemplateConfig> RowTemplateConfigs {get; set;}
}
I have also other custom components for example Button custom component:
MyButton.razor
<button type="button"
class="#Style"
#onclick="BtnClick">
#Text
</button>
#code {
[Parameter]
public string Style { get; set; }
[Parameter]
public string Text { get; set; }
[Parameter]
public EventCallback<object> OnBtnClick { get; set; }
private async Task BtnClick(object item)
{
await OnBtnClick.InvokeAsync(item);
}
}
I want to use my TableTemplate.razor in some razor page:
pets1.razor
#page "/pets1"
<h1>Pets</h1>
<TableTemplate RowTemplateConfigs =RowTemplateConfigs TItem =string>
<TableHeader>
<th>Name</th>
</TableHeader>
</TableTemplate>
#code {
private List<RowTemplateConfig> RowTemplateConfigs = new()
{
RowTemplateConfig = new ()
{
DataItem = "Bigglesworth",
ComponentMetadata = new()
{
Name= typeof(MyButton).
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success" }
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<object>(this, OnTestClick)},
{ nameof(MyButton.Text), "Hi"}
}
}
},
RowTemplateConfig = new ()
{
DataItem = "Saberhagen",
ComponentMetadata = new()
{
Name= typeof(MyButton).
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success" }
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<object>(this, OnTestClick)},
{ nameof(MyButton.Text), "Hi"}
}
}
},
//rest of the lest ...
}
private async Task OnTestClick(object sender)
{
// I want to catch the name of the pet here when user click on the button
await Task.Delay(20);
}
}
My Question:
When user clicks on MyButton in TableTemplate in pets1.razor I want to catch the element (name of pet) in the event OnTestClick.
Thanks and sorry for long question, I appreciate any suggestion.
You need to add a Pet Name parameter to the button component, load it and then submit the property back on the callback event.
Here's a modified version of your code (with a few typo and type fixes). Note: I code with Nullable enabled.
ComponentMetadata
public class ComponentMetadata
{
public Type Name { get; set; } = default!;
public Dictionary<string, object> Parameters { get; set; } =
new Dictionary<string, object>();
}
MyButton.razor
<button type="button" class="#Style" #onclick=BtnClick>
#Text
</button>
#code {
[Parameter] public string? Style { get; set; }
[Parameter] public string? Name { get; set; }
[Parameter] public string? Text { get; set; }
[Parameter] public EventCallback<string> OnBtnClick { get; set; }
private async Task BtnClick()
=> await OnBtnClick.InvokeAsync(this.Name);
}
And then the rest of the code rolled into my test page:
#page "/"
#foreach (var component in myDynamicComponents)
{
<DynamicComponent Type="#component.ComponentMetadata.Name" Parameters=component.ComponentMetadata.Parameters />
}
<div class="p-2 m-2">
<strong>Message:</strong> #message
</div>
#code {
private string message = string.Empty;
private RowTemplateConfig GetRowTemplate(string petName)
=> new RowTemplateConfig
{
DataItem = petName,
ComponentMetadata =
new ComponentMetadata()
{
Name = typeof(MyButton),
Parameters = new Dictionary<string, object>()
{
{ nameof(MyButton.Style), "btn btn-outline-success ms-1" },
{ nameof(MyButton.Name), petName },
{ nameof(MyButton.OnBtnClick), EventCallback.Factory.Create<string>(this, OnTestClick)},
{ nameof(MyButton.Text), $"Hi {petName}"}
}
}
};
private List<RowTemplateConfig> myDynamicComponents => new List<RowTemplateConfig> {
GetRowTemplate("Ginger"),
GetRowTemplate("Tiger"),
GetRowTemplate("Felix")
};
private async Task OnTestClick(string name)
{
await Task.Delay(20);
message = $"{name} Clicked at {DateTime.Now.ToLongTimeString()}";
}
public class RowTemplateConfig
{
public ComponentMetadata ComponentMetadata { get; set; } = default!;
public string? DataItem { get; set; }
}
}

How to deal with this decimal error for a price?

I'm working on this app that should show on "localhost/catalog" some data. I have a library for the models and for the services that the application might use. I am getting this error:
InvalidOperationException: The property 'Price' is not a navigation
property of entity type 'StoreAsset'. The 'Include(string)' method can
only be used with a '.' separated list of navigation property names.Microsoft.EntityFrameworkCore.Query.Internal.IncludeCompiler.WalkNavigations(IEntityType entityType, IReadOnlyList<string> navigationPropertyPaths, IncludeLoadTree includeLoadTree, bool shouldThrow)
Here is the code that I'm using (controller, models and view) and the service methods on bottom:
public class CatalogController : Controller
{
private IStoreAsset _assets;
public CatalogController(IStoreAsset assets)
{
_assets = assets;
}
public ActionResult Index()
{
var assetModels = _assets.GetAll();
var listingResult = assetModels
.Select(result => new AssetIndexListingModel
{
Id = result.Id,
Tipology = _assets.GetTipology(result.Id),
Size = _assets.GetSize(result.Id),
Price = decimal.Parse(_assets.GetPrice(result.Id))
});
var model = new AssetIndexModel()
{
Assets = listingResult
};
return View(model);
}
public class AssetIndexListingModel
{
public int Id { get; set; }
public string Size { get; set; }
public decimal Price { get; set; }
public string Tipology { get; set; }
public string ImageUrl { get; set; }
}
public abstract class StoreAsset
{
public int Id { get; set; }
[Required]
public Status Status { get; set; }
[Required]
public decimal Price { get; set; }
public string ImageUrl { get; set; }
}
public class Dress : StoreAsset
{
[Required]
public string Color { get; set; }
[Required]
public string Tipology { get; set; }
[Required]
public string Size { get; set; }
}
#model Models.Catalog.AssetIndexModel
<div id="assets">
<h3></h3>
<div id="assetsTable">
<table class="table table-condensed" id="catalogIndexTable">
<thead>
<tr>
<th>Size</th>
<th>Price</th>
<th>Tipology</th>
</tr>
</thead>
<tbody>
#foreach (var asset in Model.Assets)
{
<tr class="assetRow">
<td class="">
<a asp-controller="Catalog" asp-action="Detail" asp-route-id="#asset.Id">
<img src="#asset.ImageUrl" class="imageCell" />
</a>
</td>
<td class="">#asset.Price</td>
<td class="">#asset.Size</td>
<td class="">#asset.Tipology</td>
</tr>
}
</tbody>
</table>
</div>
public class StoreAssetService : IStoreAsset
{
private Context _context;
public StoreAssetService(Context context)
{
_context = context;
}
public void Add(StoreAsset newAsset)
{
_context.Add(newAsset);
_context.SaveChanges();
}
public IEnumerable<StoreAsset> GetAll()
{
return _context.StoreAssets
.Include(asset => asset.Status)
.Include(asset => asset.Price);
}
public StoreAsset GetById(int id)
{
// Return a query (same as returning GetAll().FirstOrDefault(...))
return _context.StoreAssets
.Include(assets => assets.Status)
.Include(assets => assets.Price)
// So it can return null with no problem
.FirstOrDefault(asset => asset.Id == id);
}
public StoreBranch GetCurrentLocation(int id)
{
throw new NotImplementedException();
}
// To implement and test
public string GetPrice(int id)
{
return _context.Dresses.FirstOrDefault(p => p.Id == id).Price.ToString();
}
public string GetSize(int id)
{
return _context.Dresses.FirstOrDefault(s => s.Id == id).Size;
}
public string GetStatus(int id)
{
throw new NotImplementedException();
}
public string GetTipology(int id)
{
var dress = _context.StoreAssets.OfType<Dress>()
.Where(b => b.Id == id);
// For now return other if it's not a party dress
return dress.Any() ? "Party" : "Other";
}
}
Should I use some ForeignKey attribute or change Price to a string?
Any help would be great thanks
As pointed out in the error message, the Include is for the Navigation property only.
You need to change below:
return _context.StoreAssets
.Include(asset => asset.Status)
.Include(asset => asset.Price);
To:
return _context.StoreAssets
.Include(asset => asset.Status).ToList();
Reference: https://learn.microsoft.com/en-us/ef/core/modeling/relationships#definition-of-terms
https://learn.microsoft.com/en-us/ef/core/querying/related-data
I am having yet another problem. When I go to "localhost/catalog" the page should display all columns/entries that I have in the database but it only displays one column. Is there something wrong in the foreach cicle?

Data column into db MVC4

<table>
#foreach (DataRow row in Model.Rows)
{
<tr>
#foreach (DataColumn col in Model.Columns)
{
<td>#row[col.ColumnName]</td>
}
</tr>
}
</table>
#Html.ActionLink("Pass", "Insert", "Home")
When clicking the pass link i would like the columns to be inserted into db. Is there any tutorial on how to do this?
Please try this sample.
Create a view model class as follows
public class DataRows
{
public int Column1{ get; set; }
public string Column2 { get; set; }
public double Column3 { get; set; }
}
public class MyModel
{
public virtual DataRows[] DataSet { get; set; }
}
Retrieve all the data using your business logic into MyModel in your controller. I am demonstrating this using a sample code
public TestModel GenerateModel()
{
var model = new TestModel();
model.DataSet = this.GenerateDataGridData().ToArray();
return model;
}
private ICollection<SampleDataSet> GenerateDataGridData()
{
var list = new List<SampleDataSet>()
{
new SampleDataSet() { Column1= 1, Column2= "XXX", Column3= 23 },
new SampleDataSet() { Column1= 2, Column2= "YYY", Column3= 27 },
new SampleDataSet() { Column1= 3, Column2= "ZZ", Column3= 25 }
};
return list;
}
In the Action of your view you will be calling GenerateModel method as follows
public ActionResult MyView()
{
var model = this.GenerateModel();
return this.View(model);
}
Now you restructure your MyView page as follows
#model MyModel
#{
int i = 0;
}
#using (Html.BeginForm("Insert", "Home", FormMethod.Post))
{
<table>
<thead>
<tr>
<th>Column1</th>
<th>Column2</th>
<th>Column3</th>
</tr>
</thead>
<tbody>
#foreach (var row in Model.DataSet)
{
<tr>
<th>#row.Column1<span>#Html.HiddenFor(x => Model.DataSet[i].Column1)</span></th>
<th>#row.Column2<span>#Html.HiddenFor(x => Model.DataSet[i].Column2)</span></th>
<th>#row.Column3<span>#Html.HiddenFor(x => Model.DataSet[i].Column3)</span></th>
</tr>
i++;
}
</tbody>
</table>
<input type="submit" value="Pass" />
}
Now on submiting the data in the view will be posted to your Insert Action of Home controller and you can insert into your DB using your logic
I hope this will be a solution for your query.

'HttpPostedFileBase' has no key defined. Define the key for this EntityType

I have create an application to upload image in database
this is my model
[Table("ImageGallery")]
public class ImageGallery
{
[Key]
public int ImageID { get; set; }
public int ImageSize { get; set; }
public string FileName { get; set; }
public byte[] ImageData { get; set; }
[Required(ErrorMessage="Please select Image File")]
public HttpPostedFileBase file { get; set; }
}
this is my database model
public class TPADB : DbContext
{
public DbSet<ImageGallery> imagegallery { get; set; }
}
this is my view
#using (Html.BeginForm("Upload", "ImageUP", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<table>
<tr>
<td>Select File : </td>
<td>
#Html.TextBoxFor(Model => Model.file, new { type="file"})
#Html.ValidationMessage("CustomError")
</td>
<td>
<input type="submit" value="Upload" />
</td>
</tr>
</table>
}
this is my controller
[HttpGet]
public ActionResult Upload()
{
return View();
}
[HttpPost]
public ActionResult Upload(ImageGallery IG)
{
IG.FileName = IG.file.FileName;
//IG.ImageSize = IG.file.ContentLength;
byte[] data = new byte[IG.file.ContentLength];
IG.file.InputStream.Read(data, 0, IG.file.ContentLength);
IG.ImageData = data;
using (TPADB db = new TPADB())
{
db.imagegallery.Add(IG);
db.SaveChanges();
}
return View();
}
but it throughs an error that
"One or more validation errors were detected during model generation:
TPA.Models.HttpPostedFileBase: : EntityType 'HttpPostedFileBase' has no key defined. Define the key for this EntityType.
HttpPostedFileBases: EntityType: EntitySet 'HttpPostedFileBases' is based on type 'HttpPostedFileBase' that has no keys defined."
Figured it out, make the following changes to the model:
public partial class ImageGallery
{
[Key]
public int ImageID { get; set; }
public int ImageSize { get; set; }
public string FileName { get; set; }
public byte[] ImageData { get; set; }
public string File
{
get
{
string mimeType = "image/png";
string base64 = Convert.ToBase64String(ImageData);
return string.Format("data:{0},{1}", mimeType, base64);
}
}
}
Then add this line to the controller:
HttpPostedFileBase File = Request.Files[0];
Replace any IG.File entry with File for example:
if (File.ContentLength > (2 * 1024 * 1024))

how to bind data to checkbox from viewmodel

I'm trying to make a view model to show a list of checkboxes. A checkbox will be checked when its ID is found in the database. However, my code is generating an error.
CheckFacilityVN
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace XNet.WebUI.Hotel.ViewModel
{
public class CheckFacilityVM
{
public int FacilityID { get; set; }
public string facilityName { get; set; }
public List<FacilityAvailable> facilityAvailable { get; set; }
}
public class FacilityAvailable
{
public bool isCheck { get; set; }
}
}
My controller
public ActionResult Facility()
{
var htl = _hotelService.ShowRoomFacility(2);
var list = new List<FacilityAvailable>();
foreach (var x in htl)
{
list.Add(new FacilityAvailable { FacilityID = htl.FacilityID, facilityName = htl.FacilityName, isCheck = htl.IsActive });
}
return View();
}
My constructor
public Facility ShowRoomFacility(int HotelID)
{
var x = (from d in db.Facilities
where d.FacilityID == HotelID
select d).FirstOrDefault();
return x;
}
How can I make these checkboxes?
Start by adapting your view model:
public class CheckFacilityVM
{
public int FacilityID { get; set; }
public string FacilityName { get; set; }
public bool IsFacilityAvailable { get; set; }
}
and then use this view model:
public ActionResult Facility()
{
var model = _hotelService
.ShowRoomFacility(2)
.Select(htl => new CheckFacilityVM
{
FacilityID = html.FacilityID,
FacilityName = html.FacilityName,
IsFacilityAvailable = htl.IsActive,
})
.ToList();
return View(model);
}
and then write a corresponding view:
#model List<CheckFacilityVM>
#using (Html.BeginForm())
{
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Is available</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(x => x[i].FacilityID)
#Html.HiddenFor(x => x[i].FacilityID)
</td>
<td>
#Html.DisplayFor(x => x[i].FacilityName)
#Html.HiddenFor(x => x[i].FacilityName)
</td>
<td>
#Html.CheckBoxFor(x => x[i].IsFacilityAvailable)
</td>
</tr>
}
</tbody>
</table>
<button type="submit">Save</button>
}
and finally:
[HttpPost]
public ActionResult Facility(List<CheckFacilityVM> model)
{
// process the values from the view model here ...
}