Delete an entity causes Validation Error EF6 - asp.net-mvc

I'm having a strange issue when I try to delete an entity Produto using my repository.
Generic Repository:
public class RepositoryBase<T> : IDisposable, IRepositoryBase<T> where T : ModelBase
{
/*Other Methods that work perfectly*/
public virtual int Delete(int id)
{
try
{
T entity = _dataContext.Set<T>().Find(id);
_dataContext.Set<T>().Remove(entity);
return _dataContext.SaveChanges();
}
catch(DbEntityValidationException ex)
{
}
}
}
Entity:
public class Produto : ModelBase
{
public virtual int? CodigoComercial { get; set; }
[Required]
[MaxLength(150)]
public virtual string Nome { get; set; }
[MaxLength(400)]
public virtual string Ingredientes { get; set; }
[Required]
public virtual CategoriaProduto Categoria { get; set; }
public Produto()
{
Categoria = new CategoriaProduto();
}
}
public class CategoriaProduto : ModelBase
{
[Required]
[MaxLength(150)]
public virtual string Nome { get; set; }
[MaxLength(400)]
public virtual string Descricao { get; set; }
public virtual CategoriaProduto CategoriaPai { get; set; }
public virtual IList<OpcaoIngrediente> Opcoes { get; set; }
public virtual CorCategoriaProdutoEnum Cor { get; set; }
public virtual bool Simples { get; set; }
[MaxLength(400)]
public string Imagem { get; set; }
public CategoriaProduto()
{
Opcoes = new List<OpcaoIngrediente>();
}
}
I found the way to catch the exception, that makes no sense, I try to Delete the Product, but It claims that the CategoriaProduto has the Name empty and It's required. as below:
SaborFit.Data.Model.CategoriaProduto failed validation
Nome : The field Nome is required.
I can't figure out the issue. If I try to delete the CategoriaProduto, all goes well.

I don't know why you are using Virtual property for most of fields, This cause to have lazy loading and obviously you'll encounter validation error on Any Operation where you call entire entity like .Find() operand. You must first decide what do you wanna do! Another solution that I don't prefer for you is disabling validation on save changes:
context.Configuration.ValidateOnSaveEnabled = false;
context.SaveChanges();

Related

Add an entry on a virtual property

I'm new to asp.net & mvc entity framework.
I'm doing a backoffice for managing applications
Here is my App class:
public class AsyApp
{
[Key]
public int AsyAppId { get; set; }
[StringLength(255)]
[Required]
[DisplayName("Nom")]
public string Name { get; set; }
[StringLength(255)]
[Required]
[RegularExpression(#"com\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+", ErrorMessage = "Le Bundle n'est pas de la bonne forme (ex: com.Company.AppName)")]
public string Bundle { get; set; }
public virtual Theme Theme { get; set; }
public virtual AppIdentity AppIdentity { get; set; }
public virtual ICollection<Scene> Scenes { get; set; }
public virtual ICollection<FilePath> FilePaths { get; set; }
}
The app has an AppIdentity attached to it:
public class AppIdentity
{
[DisplayName("Ecran d'accueil")]
public virtual FilePath Splashscreen { get; set; }
[DisplayName("Icon")]
public virtual FilePath Icon { get; set; }
[DisplayName("Logo Application")]
public virtual FilePath LogoApp { get; set; }
[DisplayName("Logo Client")]
public virtual FilePath LogoClient { get; set; }
[Key, ForeignKey("AsyApp")]
public int AsyAppId { get; set; }
public virtual AsyApp AsyApp { get; set; }
}
And here is my dbcontext
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
public DbSet<AsyApp> AsyApps { get; set; }
public DbSet<Theme> Themes { get; set; }
public DbSet<Scene> Scenes { get; set; }
public DbSet<AppIdentity> AppIdentities { get; set; }
public DbSet<FilePath> FilePaths { get; set; }
}
I have a view where I edit the AppIdentity of the application.
I would like to update for instance the Splashscreen property.
The behavior that I expect is that when I do
appIdentity.Splashscreen = new FilePath();
It add an entry on the FilePaths dbset;
Set the AsyAppId of the new filepath entry to the current AsyApp.
But It doesn't work...
Here is my controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(AppIdentity appIdentity)
{
var f = new FilePath();
f.AsyAppId = appIdentity.AsyAppId;
db.FilePaths.Add(f);
db.SaveChanges();
appIdentity.Splashscreen = f;
db.SaveChanges();
return RedirectToAction("Edit", "AppIdentity", new { asyAppId = appIdentity.AsyAppId });}}
Any help ?
Thank you in advance, this will help me a lot.
I just don't fully understand how virtual properties works right know
Try putting this code after appIdentity.Splashscreen = f; :
db.AppIdentities.Attach(appIdentity);
context.Entry(appIdentity).State = EntityState.Modified;
db.SaveChanges();

Update hierarchy model in Entity Framework

I have two model classes:
Request:
public partial class Request
{
public long Id { get; set; }
public string Username { get; set; }
public string Description { get; set; }
public System.DateTime CreateDate { get; set; }
public long DeviceId { get; set; }
public bool IsFinalized { get; set; }
public Nullable<long> ParentId { get; set; }
public virtual Device Device { get; set; }
}
Device:
public partial class Device
{
public Device()
{
this.Requests = new List<Request>();
}
public long Id { get; set; }
public string Serial { get; set; }
public string AssetNumber { get; set; }
public System.DateTime CreatedDate { get; set; }
public virtual ICollection<Request> Requests { get; set; }
}
I have to update the models I use this method
public void Update(RequestViewModel viewModel)
{
var entity = _mappingEngine.Map<Request>(viewModel);
_requests.Attach(entity);
_uow.Entry(entity).State = EntityState.Modified;
}
but only Request model is updated after calling the Update method. I want to update both models. Please help me.
Attaching an entity to a DbContext, mark the attached entity and all its dependencies (i.e. associated entities) UnChanged. So its you who must tell EF what entities are new and what entities were modified.

Breeze.js and PreserveReferencesHandling serializing failure

I encounter a problem with deserializing entities in client side with breeze.js.
My data model entity has one to many relation to other entities (A has ICollection of B)
When I make a query , I see the data returned from the server include $ref= # , I understood breeze uses this to identify same objects returned from the server.
But in client side all those entities with $ref=# doesn't deserialized properly I get this function () { return mc.refMap[node]} insted to get the real object in client side .
Here is my object structure :
public partial class Product
{
public Product()
{
this.ProductCatalogue = new HashSet<ProductCatalogue>();
this.DiameterRanges = new HashSet<DiameterRanges>();
this.Product_Children = new HashSet<Product>();
}
public int Id { get; set; }
public string Code { get; set; }
public virtual ICollection<ProductCatalogue> ProductCatalogue { get; set; }
public virtual ICollection<DiameterRanges> DiameterRanges { get; set; }
public virtual Product Product_Parent { get; set; }
}
public partial class DiameterRanges
{
public int Id { get; set; }
public double MinSPH { get; set; }
public double MaxSPH { get; set; }
public double MinCyl { get; set; }
public double MaxCyl { get; set; }
public short MinDiameter { get; set; }
public short MaxDiameter { get; set; }
public int Product_Id { get; set; }
public virtual Product Product { get; set; }
}
Nothing special in my server side query : Context.Product.Include("DiameterRanges");
Any idea to figure out this problem .
Thanks in advance ....

Entity Framework Required Foreign Key = validation error on db.SaveChanges

I have these classes for my Company Entity
public class Company
{
public Company()
{
this.Users = new HashSet<User>();
this.Tools = new HashSet<Tool>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Tool> Tools { get; set; }
[Required]
public virtual CompanyGroup CompanyGroup { get; set; }
}
public class CompanyDto
{
public string Name { get; set; }
public string Address { get; set; }
}
in the CompaniesController i've added an additional class with the Id parameter for usage in edit/update methods like this
public class CompanyViewEditModel : CompanyDto {
public int Id { get; set; }
}
The Edit Method looks like that:
[HttpPost]
public ActionResult Edit(CompanyViewEditModel companyViewModel)
{
if (ModelState.IsValid)
{
var company = db.Companies.Find(companyViewModel.Id);
company.InjectFrom(companyViewModel);
db.Entry(company).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(companyViewModel);
}
The InjectFrom Method is from ValueInjecter.
Everything works as expected only the db.SaveChanges call fails, because of an validation exception. With some digging in the exceptionI've found out that he thinks the company is invalid because the field CompanyGroup is required but if i take a debugger look at the company variable even after the InjectFrom call everything seems to be fine. The corresponding company group is there.
Consider changing your model as you shouldn't have to mark the navigational property as required. Instead add a FK like so.
public class Company
{
public Company()
{
this.Users = new HashSet<User>();
this.Tools = new HashSet<Tool>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public int CompanyGroupId { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Tool> Tools { get; set; }
public virtual CompanyGroup CompanyGroup { get; set; }
}

EF4 - Can a POCO be used as both an Entity and ComplexType?

I am using EF4 CTP5. Here are my POCOs:
public class Address
{
public int Id { get; set; }
public string Name { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public List<Address> Addresses { get; set; }
public List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public decimal Total { get; set; }
public Address ShippingAddress { get; set; }
public Address BillingAddress { get; set; }
}
Is there a way to get Address to be a ComplexType for the Order class? After playing around with this, I'm guessing not, but maybe there's a way I haven't seen.
EDIT: In response to Shawn below, I gave it my best shot:
//modelBuilder.Entity<Order>().Ignore(o => o.BillingAddress);
//modelBuilder.Entity<Order>().Ignore(o => o.ShippingAddress);
modelBuilder.Entity<Order>()
.Property(o => o.BillingAddress.City).HasColumnName("BillingCity");
Fails at runtime with error "The configured property 'BillingAddress' is not a declared property on the entity 'Order'." Trying to use Ignore() doesn't work. Next, the Hanselman article is CTP4, but the CTP5 equivalent is:
modelBuilder.Entity<Order>().Map(mapconfig =>
{
mapconfig.Properties(o => new {
o.Id
, o.Total
, o.BillingAddress.City
});
mapconfig.ToTable("Orders");
});
Fails with error "Property 'BillingAddress.City' of type 'Order' cannot be included in its mapping."
I give up. Maybe the final release will have something like this. Or maybe I need to switch to NHibernate =)
All you need to do is to place ComplexTypeAttribute on Address class:
[ComplexType]
public class Address
{
public int Id { get; set; }
public string Name { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
}
Alternatively, you can achieve this by fluent API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ComplexType<Address>();
}
But you cannot have Address type as to be both an Entity and a Complex Type, it's one way or another.
Take a look at this blog post where I discuss this at length:
Associations in EF Code First CTP5: Part 1 – Complex Types
If you want Address to be in the same table as Order, you're going to have to tell EF that in the DbContext OnModelCreating override.
Take a look here: http://weblogs.asp.net/scottgu/archive/2010/07/23/entity-framework-4-code-first-custom-database-schema-mapping.aspx

Resources