cascade delete EF Code First - entity-framework

I'm new with entity framework code first, so I will like to ask the following:
I have this entity:
public class ConfigurationSetEntity
{
public virtual List<IsapreEntity> Isapres { get; set; }
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public virtual string Culture { get; set; }
}
and also this:
public class IsapreEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Required]
public virtual string IsapreName { get; set; }
[ForeignKey("IsapreOf")]
[Required]
public virtual string CultureId { get; set; }
public virtual ConfigurationSetEntity IsapreOf { get; set; }
}
when I use ConfigurationSetEntity.Isapres.Remove(entity) I get an DbEntityValidationException, this is the code for the remove:
IsapreModel original = this.ChangeSet.GetOriginal(currentIsapre);
ConfigurationSetEntity defaultConfigSet = dbContext.ConfigurationSets.Find(Constants.DefaultConfigurationSetId);
IsapreEntity originalEntity =defaultConfigSet.Isapres.Find(e => e.IsapreName==original.Isapre);
defaultConfigSet.Isapres.Remove(originalEntity);
try
{
dbContext.SaveChanges();
}
catch (Exception ex)
{
//This is where I catch the exception
}
defaultConfigSet.Isapres.Add(new IsapreEntity { IsapreName = currentIsapre.Isapre });
try
{
dbContext.SaveChanges();
}
catch (Exception ex)
{
}
And this is the exception:
"The IsapreOf field is required."
What I want to do is to use ConfigurationSetEntity.Isapres.Remove(entity) and have entity removed from the IsapreEntities table and from the list.
Can some one please explain why the error and/or how can I achieve my intended purpose?

Related

Entity Framework always adds two records in the tables

I'm implementing an ASP.NET Core 3.1 app. I have implemented following code to insert record in SQL Server database via EF Core but each time I save data, it inserts two records in PersonRequester and Requester table. I appreciate if anyone suggests me how I can prevent reinserting records.
Requester ap = new Requester();
ap.Address = RequesterViewModel.Requestervm.Address;
ap.RequesterType = RequesterViewModel.Requestervm.RequesterType;
ap.Description = RequesterViewModel.Requestervm.Description;
ap.Name = RequesterViewModel.Requestervm.Name;
var pa = new PersonRequester()
{
BirthCertificateNo = RequesterViewModel.personRequestervm.BirthCertificateNo,
IssuePlace = RequesterViewModel.personRequestervm.IssuePlace,
NationalCode = RequesterViewModel.personRequestervm.NationalCode,
Requester = ap
};
using (var context = new DBContext())
{
context.PersonRequester.Attach(pa);
try
{
context.SaveChanges();
}
catch (Exception e)
{
throw e;
}
}
public partial class Requester
{
public Requester()
{
PersonRequester = new HashSet<PersonRequester>();
}
public int RequesterId { get; set; }
public int RequesterType { get; set; }
public string Address { get; set; }
public string Description { get; set; }
public string Name { get; set; }
public virtual EntityType RequesterTypeNavigation { get; set; }
public virtual ICollection<PersonRequester> PersonRequester { get; set; }
}
public partial class PersonRequester
{
public int RequesterId { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public int RequesterType { get; set; }
public string NationalCode { get; set; }
public string BirthCertificateNo { get; set; }
public string IssuePlace { get; set; }
public virtual Requester Requester { get; set; }
public virtual EntityType RequesterTypeNavigation { get; set; }
}

EF: validation error for 1:0..1 relationship in data model with navigation properties

I have this simple data model of some reservations and theirs cancellations:
[Table("ReservationCreation")]
public class ReservationCreation
{
[Key()]
public int ReservationCreationId { get; set; }
[InverseProperty("ReservationCreation")]
public virtual ReservationCancellation ReservationCancellation { get; set; }
}
[Table("ReservationCancellation")]
public class ReservationCancellation
{
[Key()]
[ForeignKey("ReservationCreation")]
public int ReservationCancellationId { get; set; }
[Required]
[ForeignKey("ReservationCancellationId")]
[InverseProperty("ReservationCancellation")]
public virtual ReservationCreation ReservationCreation { get; set; }
}
public class DbContext : System.Data.Entity.DbContext
{
public DbContext() : base(#"DefaultConnection") { }
public DbSet<ReservationCancellation> ReservationCancellation { get; set; }
public DbSet<ReservationCreation> ReservationCreation { get; set; }
}
internal sealed class Configuration : DbMigrationsConfiguration<DbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
}
Here is the code of the test. First the reservation is created and then it is cancelled.
When the cancellation record is being saved into database then an exception is thrown "The ReservationCreation field is required".
How can I create cancellation record only from the reservation's ID and at the same time have the navigation properties defined?
class Program
{
static void Main(string[] args)
{
int reservationId;
// create reservation
using (var db = new DbContext())
{
var reservation =
db.ReservationCreation.Add(
new ReservationCreation());
db.SaveChanges();
reservationId = reservation.ReservationCreationId;
}
// cancel reservation by its Id
using (var db = new DbContext())
{
var cancellation =
db.ReservationCancellation.Add(
new ReservationCancellation
{
ReservationCancellationId = reservationId
});
try
{
// an exception is thrown
db.SaveChanges();
}
catch(DbEntityValidationException ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
foreach (var err in ex.EntityValidationErrors.SelectMany(x_ => x_.ValidationErrors))
System.Diagnostics.Debug.WriteLine($"!!!ERROR!!! {err.PropertyName}: {err.ErrorMessage}");
}
}
}
}
I did not find any way how to modify the data model annotations. If I remove [Required] from ReservationCreation property then I am not able to create the migration {or connect to the database with that data model).
Your mixing things up in your ReservationCancellation model.
In your ReservationCreation property you are referring to the primary key entity instead of the ReservationCreation property.
Try this.
[Table("ReservationCancellation")]
public class ReservationCancellation
{
[Key()]
public int ReservationCancellationId { get; set; }
[ForeignKey("ReservationCreation")]
public int ReservationCreationId { get; set; }
[Required]
public virtual ReservationCreation ReservationCreation { get; set; }
}
Update
Since you want only one cancellation per creation, you can do this using a simpler model.
[Table("ReservationCreation")]
public class ReservationCreation
{
[Key()]
public int ReservationCreationId { get; set; }
public virtual ReservationCancellation ReservationCancellation { get; set; }
}
[Table("ReservationCancellation")]
public class ReservationCancellation
{
[Key()]
public int ReservationCancellationId { get; set; }
public virtual ReservationCreation ReservationCreation { get; set; }
}
I followed the recommendations from #dknaack and my final solution of this problem is this data model:
[Table("ReservationCreation")]
public class ReservationCreation
{
[Key()]
public int ReservationCreationId { get; set; }
[InverseProperty("ReservationCreation")]
public virtual ReservationCancellation ReservationCancellation { get; set; }
}
[Table("ReservationCancellation")]
public class ReservationCancellation
{
[Key()]
[ForeignKey("ReservationCreation")]
public int ReservationCancellationId { get; set; }
[ForeignKey("ReservationCancellationId")]
public virtual ReservationCreation ReservationCreation { get; set; }
}

NullReferenceException on join with Postgres EF Provider

I have a postgres database and using asp.net core mvc (+ ef). The database is created correctly. I have two tables 'Module' and 'ModuleMenu'. I want to get all the menu's for a given module but I keep on failing to create the linq query.
Situation
Model: Module.cs
namespace project.Model
{
public class Module
{
[Required]
public string ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
}
}
Model: ModuleMenu.cs
namespace project.Models
{
public class ModuleMenu
{
[Required]
public string ID { get; set; }
public int ModuleID { get; set; }
[Required]
public string Title { get; set; }
[ForeignKey("ModuleID")]
public virtual Module Module { get; set; }
}
}
ApplicationDbContext.cs
namespace project.Data
{
public class ApplicationDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
public DbSet<Module> Modules { get; set; }
public DbSet<ModuleMenu> ModuleMenus { get; set; }
}
}
Query
public List<ModuleMenu> GetModuleMenus(){
var query = from m in _dbContext.ModuleMenus
join mod in _dbContext.Modules on
m.ModuleID equals mod.ID
select m;
return query.ToList();
}
Error
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[0]
An exception was thrown attempting to execute the error handler.
System.NullReferenceException: Object reference not set to an instance of an object.
Can anyone help me to correctly create the query?
Is this part correct in your code?
public int ModuleID { get; set; }
It seems that you might have had an error in the type used for the fk.
Below I changed the type to be string rather than int.
public string ModuleID { get; set; }
based on that update, the query could look like this.
public ModuleMenu[] GetModuleMenusForModule(string moduleId)
{
return _dbContext.ModuleMenus.Where(x => x.ModuleID == moduleId).ToArray();
}
I would expect that model to error (ModelID and ID are incompatible types). If that were correct, your code should work. Or simpler:
public List<ModuleMenu> GetModuleMenus()
{
return _dbContext.ModuleMenus.ToList();
}

Update only a single column using EF5 in MVC4

I have an UserProfile model
public class UserProfile
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Key]
[Required]
public string EmailAddress { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Surname { get; set; }
[Required]
public string BusinessUnit { get; set; }
[Required]
public string JobRole { get; set; }
public bool IsEnabled { get; set; }
public string Password { get; set; }
}
I want to update only the password field.
This is the code I am trying
if (ModelState.IsValid)
{
var context = new JhaDbContext();
using (JhaDbContext jdc = new JhaDbContext())
{
try
{
jdc.UserProfiles.Attach(userProfile);
userProfile.Password = model.NewPassword;
jdc.SaveChanges();
httpStatus = HttpStatusCode.OK;
}
catch (InvalidOperationException ioe)
{
httpStatus = HttpStatusCode.BadRequest;
}
catch (DbEntityValidationException ev)
{
httpStatus = HttpStatusCode.BadRequest;
}
}
}
I get the DbEntityValidationException on the required fields. Please guide me in solving this.
Regards
Sudheep
I usually would do a
var myEntity = jdc.(tableName).find(userID);
then set
myEntity.Password = "new password";
jdc.Entry(userProfile).State = System.Data.EntityState.Modified;
/* why do you have it as unchanged? */
jdc.saveChanges()

Code First : Context fields are null

Here is my context:
public class ContentContext : DbContext
{
public ContentContext() : base("Name=CodeFirstDatabase") { }
public DbSet<Article> Articles;
public DbSet<ArticleTag> ArticleTags;
}
connection string:
<add name="CodeFirstDatabase" providerName="System.Data.SqlClient" connectionString="Server=X-ПК\SQLEXPRESS;Database=Products;Trusted_Connection=true;"/>
Global.asax:
Database.SetInitializer(new CreateDatabaseIfNotExists<ContentContext>());
HomeController:
public ActionResult Index()
{
ContentContext context = new ContentContext();
context.Database.Initialize(true);
Article a = new Article() { Text = "TEXT" };
context.Articles.Add(a);
context.SaveChanges();
return View();
}
Entities:
public class Article
{
public int Id { get; set; }
public string Author { get; set; }
public string Text { get; set; }
public virtual ICollection<ArticleTag> ArticleTags { get; set; }
}
public class ArticleTag
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Article Article { get; set; }
}
Database created as expected.But no tables created in it and I get null reference exception when I try add new Article. Any ideas? Thanks.
Change your DBSet<> in ContentContext to properties (instead of fields):
public DbSet<Article> Articles { get; set; }
public DbSet<ArticleTag> ArticleTags { get; set; }