I'm pulling out my hair here. I've seen the solutions to turning off cascade on delete here, but I can't implement it. I don't know what I'm doing wrong here, but I keep getting the below error:
'System.Data.Entity.ModelConfiguration.EntityTypeConfiguration' does not contain a definition for 'WillCascadeOnDelete' and no extension method 'WillCascadeOnDelete' accepting a first argument of type 'System.Data.Entity.ModelConfiguration.EntityTypeConfiguration' could be found (are you missing a using directive or an assembly reference?)
I've added the necessary namespaces, but I don't see it as an option anywhere in the intellisense and I'm not getting anywhere searching. I'm in VS 2010 MVC 3
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using vf2.Models;
using vf2.Models.LinkTables;
using vf2.Models.Requests;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity.ModelConfiguration.Configuration;
using System.Data.Entity.ModelConfiguration;
using vf2.Models.Reporting;
using vf2.Models.POSObj;
namespace vf2.Models
{
public class vfContext : DbContext
{
public DbSet<App> Apps { get; set; }
public DbSet<Origin> Origins { get; set; }
public DbSet<WineType> WineTypes { get; set; }
public DbSet<VarType> VarTypes { get; set; }
public DbSet<Wine> Wines { get; set; }
public DbSet<Vintage> Vintages { get; set; }
public DbSet<Distributor> Distributors { get; set; }
public DbSet<Importer> Importers { get; set; }
public DbSet<Producer> Producers { get; set; }
public DbSet<Publication> Publications { get; set; }
public DbSet<Review> Reviews { get; set; }
public DbSet<UserType> UserTypes { get; set; }
public DbSet<Restaurant> Restaurants { get; set; }
public DbSet<WineListChangeRate> WineListChangeRates { get; set; }
public DbSet<MenuChangeRate> MenuChangeRates { get; set; }
public DbSet<WineListCount> WineListCounts { get; set; }
public DbSet<UserObj> UserObjs { get; set; }
public DbSet<ProducerUser> ProducerUsers { get; set; }
public DbSet<DistributorUser> DistributorUsers { get; set; }
public DbSet<RestaurantUser> RestaurantUsers { get; set; }
public DbSet<ProducerEditRequest> ProducerEditRequests { get; set; }
public DbSet<RequestStatus> RequestStatuses { get; set; }
public DbSet<VOAVIRequest> VOAVIRequests { get; set; }
public DbSet<POS> POSs { get; set; }
public DbSet<Cart> Carts { get; set; }
public DbSet<FutureUser> FutureUsers { get; set; }
public DbSet<Doc> Docs { get; set; }
public DbSet<DocType> DocTypes { get; set; }
public DbSet<WineVisit> WineVisits { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Review>().WillCascadeOnDelete(false);
//error here!
base.OnModelCreating(modelBuilder);
}
}
}
"Cascading delete" is a configuration of a relationship, not of an entity/table. Hence WillCascadeOnDelete is a method of CascadableNavigationPropertyConfiguration. Use case example:
modelBuilder.Entity<Review>()
.HasRequired(r => r.Wine)
.WithMany()
.WillCascadeOnDelete(false);
It means that if a wine is deleted from the catalog in the database, it's reviews should not be deleted together with the wine. That's a property of this specific relationship, not of the Reviews table.
In this case trying to delete a wine which has reviews would result in a foreign key constraint violation and exception of course, but that is what you usually want when you disable cascading delete on a required relationship ("Don't allow to delete a wine which has reviews, only allow it for wines which haven't any...").
Related
I am trying to implement filtering on Resource table which has MartialStatus of char property in DDL of database.Let my show you my approach first. In my program.cs file, i have the following:
using LIS.ResourcePlanningSystem.API;
using LIS.ResourcePlanningSystem.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<RpsDbContext>(options => options.UseLazyLoadingProxies().UseNpgsql(builder.Configuration.GetConnectionString("RPSDbContext")));
builder.Services.AddGraphQLServer().
RegisterDbContext<RpsDbContext>().
AddQueryType<Query>().
AddProjections().
AddFiltering().
AddSorting().
BindRuntimeType<char, StringType>().
AddTypeConverter<char, string>(from => from.ToString()).
AddTypeConverter<string, char>(from => from.ToCharArray()[0]);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.MapGraphQL("/graphql");
app.Run();
Here is my a model Register.cs which has "MaritalStatus" char property.
public class Resource
{
public int Id { get; set; }
public string? FirstName { get; set; }
public string? MiddleName { get; set; }
public string? LastName { get; set; }
public string? FullName { get; set; }
public char? MaritalStatus { get; set; }
public virtual Gender? Gender { get; set; }
public virtual Education? Education { get; set; }
public int? InstitutionId { get; set; }
public string? PerStreet { get; set; }
public DateTime? OfficeJoinDt { get; set; }
public virtual Grade? Grade { get; set; }
public int? PositionId { get; set; }
public virtual Department? Department { get; set; }
public virtual ClientType? ClientType{ get; set; }
public int? ExpOut { get; set; }
public string? ResignedFlag { get; set; }
public string? Email { get; set; }
public virtual BloodGroup? BloodGroup { get; set; }
public virtual ResignedRemarks? ResignedRemark { get; set; }
public virtual Source? Source { get; set; }
}
Now, the program runs just fine until i add [UseFiltering] on the Resource table in query.cs file.
[UseFiltering]
[UseSorting]
public IQueryable<Resource>? GetResources(RpsDbContext context) => context.Resources;
The error i am getting is this:
HotChocolate.SchemaException: For more details look at the `Errors` property.
1. For more details look at the `Errors` property.
1. The type of the member MaritalStatus of the declaring type Resource is unknown
If i remove the [UseFiltering] [UseSorting], the program works fine. I think the problem is related to filtering on resource table. Filtering also work fine on all the other tables which doesn't have char property in its schema definition. Someone has opened a bug issue on github [here] . Tried to solve reading this issue but no luck. Could somebody please tell me how can i get around this problem?
I have the following db structure:
I am using EF6 to create the entities from database and have the following classes created by EF6:
public partial class Mechanic
{
public Mechanic()
{
this.MechanicAddresses = new HashSet<MechanicAddress>();
this.MechanicServices = new HashSet<MechanicService>();
}
public string ID { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public Nullable<System.DateTime> LockoutEndDateUtc { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string UserName { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
public string MobileNumber { get; set; }
public Nullable<bool> IsMobile { get; set; }
public string Url { get; set; }
public string FaceBookUrl { get; set; }
public string TwitterUrl { get; set; }
public string Description { get; set; }
public string Discriminator { get; set; }
public bool IsEnabled { get; set; }
public bool IsAuthorised { get; set; }
public string Logo { get; set; }
public System.DateTime CreationTimestamp { get; set; }
public virtual ICollection<MechanicAddress> MechanicAddresses { get; set; }
public virtual ICollection<MechanicService> MechanicServices { get; set; }
}
public partial class MechanicAddress
{
public int ID { get; set; }
public string MechanicId { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
public string District { get; set; }
public string Region { get; set; }
public string PostalCode { get; set; }
public int CountryId { get; set; }
public System.DateTime CreationTimestamp { get; set; }
public bool IsPrimary { get; set; }
public Nullable<double> Latitude { get; set; }
public Nullable<double> Longitude { get; set; }
public System.Data.Entity.Spatial.DbGeography Location { get; set; }
public virtual Country Country { get; set; }
public virtual Mechanic Mechanic { get; set; }
}
public partial class MechanicService
{
public int ID { get; set; }
public string MechanicId { get; set; }
public string Service { get; set; }
public virtual Mechanic Mechanic { get; set; }
}
The data is correct so i expect to get data in all entities.
When i run the following linq query in my DAL:
Mechanic mech = context.Mechanics.Where(a => a.ID == id).Include(a => a.MechanicAddresses).Include(a => a.MechanicServices).FirstOrDefault();
It returns the mechanic and mechanicAddresses but mechanicServices is always empty (count == 0).
When i run the same query in LinqPad I get all entities filled as expected.
I have removed the edmx and re-created it but still get the same issue.
Please check if "MultipleActiveResultSets" is set to true and LazyLoadingEnabled is enabled in connection string. It may help.
And what about your OnModelCreating?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
It's not necessary to use Include if you have LazyLoading (virtual). And If it works fine in LinqPad try to do migration into empty DB (just test). And then try to get data from test DB.
The only way i was able to resolve this was to:
delete the EDMX
script the create for the mechanicsServices table
script the data
drop the mechanicsServices table
run the create table script from above
run the insert data script
regenerate the EDMX
This now works, WTF! Can't explain it.
I know it's always best to understand what went wrong but this one beat me.
I had same problem.
If you using git, please check .edmx file old version. SSDL content may be missing.
I have a Project table with some fields that point to a Participant table but all with a different meaning of course:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace iMaSys.Models
{
public class Project
{
[Key]
public int ProjectID { get; set; }
[Required]
[StringLength(128)]
[Display(Name = "Omschrijving")]
public string Description { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Startdatum")]
public DateTime StartDate { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
[Display(Name = "Einddatum")]
public DateTime? EndDate { get; set; }
public Boolean Active { get; set; }
[Display(Name = "Mediation Casenummer")]
public string Mediation_casenr { get; set; }
public Participant CaseManager { get; set; }
public Participant Supervisor { get; set; }
public Participant Party_1 { get; set; }
public Participant Party_2 { get; set; }
public Participant Client { get; set; }
public Participant InterventionManager { get; set; }
public Participant Mediator { get; set; }
public virtual ProjectCategorySub ProjectCategorySubject { get; set; }
}
}
The fields Casemanager, Supervisor, Party_1 etc all point to Participant. In Particpant I added InverseProperties to tell the framework the connection between Projects and Participants:
[InverseProperty("Mediator")]
public List<Project> ProjectMediators { get; set; }
[InverseProperty("Supervisor")]
public List<Project> ProjectSupervisors { get; set; }
etc. etc.
After add-migration and update-database the fields in Project are named like:
CaseManager_ParticipantID etc. I just simply need CaseManagerID to point to Participant_ParticipantID. I tried several things but I seem not to understand howto get it to work.
I'm stuck on this one, can anyone point me in the right direction?
Best regards, Janno Hordijk
I solved it myself but want to share what I found out.
At Participant:
[InverseProperty("Mediator")]
public virtual ICollection<Project> MediatorProjects { get; set; }
[InverseProperty("Supervisor")]
public virtual ICollection<Project> SupervisorProjects { get; set; }
At Project:
[ForeignKey("Mediator")]
public int? Mediator_ID { get; set; }
public virtual Participant Mediator { get; set; }
[ForeignKey("Supervisor")]
public int? Supervisor_ID { get; set; }
public virtual Participant Supervisor { get; set; }
Now the database is ok and my fieldnames are Supervisor_ID instead of Supervisor_Participant_ID
Best regards, Janno
I am creating two tables in Visual Web Developer 2010 Express using the following code:
http://imgur.com/a/Mi2Bv (sorry, the forum will not let me, due to a new account, post pictures directly)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace BarApp.Models
{
public class Drinks
{
public int DrinksId { get; set; }
public int EstablishmentsID { get; set; }
public string name { get; set; }
public decimal price { get; set; }
public string description { get; set; }
public string image { get; set; }
public virtual Establishments establishment { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace BarApp.Models
{
public class Promotions
{
public int PromotionsId { get; set; }
public string name { get; set; }
public float discount { get; set; }
public int EstablishmentId { get; set; }
public int DrinkId { get; set; }
public string description { get; set; }
public virtual Establishments establishment { get; set; }
public virtual Drinks drink { get; set; }
}
}
But when I look at the created tables, the Promotions table has actual rows for the public virtual code, whereas the Drinks table does not.
I am able to have the Drinks table function the way I want elsewhere in the project, but I cannot get Promotions to behave the same way because it appears that "public virtual" is giving different results in each table.
I do not understand why my Promotions table is actually creating rows for the public virtual variables. Can someone help me understand?
In this particular situation I was not using the conventional way of referencing the Id field of another table.
I simply needed to change the following:
public int EstablishmentId { get; set; }
public int DrinkId { get; set; }
to the following:
public int EstablishmentsId { get; set; }
public int DrinksId { get; set; }
My tables were created as expected after I made this change.
I've have two tables in my project which are User and InvoiceLine.
It has been specified that an InvoiceLine can have a User known as a Checker.
My models are:
public class InvoiceLine : IEntity
{
public virtual int Id { get; set; }
public virtual int? CheckerId { get; set; }
public virtual string CreatedByUserName { get; set; }
public virtual DateTime CreatedDateTime { get; set; }
public virtual string LastModifiedByUserName { get; set; }
public virtual DateTime? LastModifiedDateTime { get; set; }
// Navigation properties
public virtual User Checker{ get; set; }
}
public class User : IEntity
{
public int Id { get; set; }
public string CreatedByUserName { get; set; }
public DateTime CreatedDateTime { get; set; }
public string LastModifiedByUserName { get; set; }
public DateTime? LastModifiedDateTime { get; set; }
//Navigation properties
public virtual ICollection<InvoiceLine> InvoiceLines { get; set; }
}
So this was fine I have a 0..1 to many relationship from User to InvoiceLine.
This meant with Linq I could get the InvoiceLines the User needs to check via:
user.InvoiceLines
However there is another requirement that an InvoiceLine also has an Auditor so I modified the InvoiceLine to:
public class InvoiceLine : IEntity
{
public virtual int Id { get; set; }
public virtual int? CheckerId { get; set; }
public virtual int? AuditorId { get; set; }
public virtual string CreatedByUserName { get; set; }
public virtual DateTime CreatedDateTime { get; set; }
public virtual string LastModifiedByUserName { get; set; }
public virtual DateTime? LastModifiedDateTime { get; set; }
// Navigation properties}
public virtual User Checker { get; set; }
public virtual User Auditor { get; set; }
}
So what I was really wanting was to go:
user.InvoiceLines
and get the Checkers and Auditors or alternatively get them seperately via:
user.CheckerInvoiceLines
user.AuditorInvoiceLines
I'm getting null back from user.InvoiceLines though which is understandable.
Could someone please point me in the right direction on how to use Linq to get the InvoiceLines from the User?
Edit Update:
My model configuration code is like:
public class VectorCheckContext : DbContext
{
...
public DbSet<InvoiceLine> InvoiceLines { get; set; }
public DbSet<User> Users { get; set; }
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
}
You need to use fluent mappings to configure the relationships when EF can not resolve them by conventions.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
//other mappings
modelBuilder.Entity<InvoiceLine>()
.HasOptional(i => i.Checker)
.WithMany(u => u.CheckerInvoiceLines)
.HasForeignKey(i => i.CheckerId);
modelBuilder.Entity<InvoiceLine>()
.HasOptional(i => i.Auditor)
.WithMany(u => u.AuditorInvoiceLines)
.HasForeignKey(i => i.AuditorId);
}