How do you use Automapper to map navigation properties in EF6? - entity-framework

Note: I never solved this issue and just moved on to using a straight up Linq query. .Select(a => new UserDetailsDto { ContactId = a.ContactId, etc
The issue I'm having is trying to understand how Automapper can be used to map navigation properties with the parent entity all in one query.
Lets say I have a UserDto that closely mirrors the entity and looks like this:
public class User
{
public int UserId { get; set; }
public int UserDetailsId { get; set; }
public int ContactId { get; set; }
public DateTime CreateDateTime { get; set; }
public DateTime? ModifiedDateTime { get; set; }
public DateTime? InactiveDateTime { get; set; }
public UserDetail UserDetails { get; set; }
}
Then I have an entity called UserDetail which is mostly made up of navigation properties(I'll post just a few props to keep it short):
public partial class UserDetail
{
public int UserDetailId { get; set; }
public int UsertId { get; set; }
public DateTime? DateOfBirth { get; set; }
public int? ProviderId { get; set; }
public int? FacilityId { get; set; }
public int? CarrierId { get; set; }
public int? GenderId { get; set; }
public int? EthnicityId { get; set; }
}
Then its DTO
public class UserDetailDto
{
public int ParticipantDetailId { get; set; }
public int ParticipantId { get; set; }
public DateTime DateOfBirth { get; set; }
public string Provider { get; set; }
public string Facility { get; set; }
public string Carrier { get; set; }
public string Gender { get; set; }
public string Ethnicity { get; set; }
}
I've seen that you can use something like:
IEnumerable<UserDto> users = await
db.DbContext.Set<User>()
.ProjectTo<UserDto>()
.ToListAsync();
but I don't get how you use that in combination with something like .ForMember in the Mapper Config.
I'm just showing what I've seen. I'm totally open to any suggestion on how to accomplish this.
Edit:
Mapper Config:
config.CreateMap<User, UserDto>();
config.CreateMap<UserDto, User>();
config.CreateMap<UserDetail, UserDetailDto>()
.ForMember(dto => dto.Provider, conf => conf.MapFrom(entity => entity.Provider.ProviderName))
.ForMember(dto => dto.Facility, conf => conf.MapFrom(entity => entity.Facility.FacilityName))
.ForMember(dto => dto.Carrier, conf => conf.MapFrom(entity => entity.Carrier.CarrierName))
.ForMember(dto => dto.Gender, conf => conf.MapFrom(entity => entity.Gender.GenderText))
.ForMember(dto => dto.Ethnicity, conf => conf.MapFrom(entity => entity.Ethnicity.EthnicityText))
.ForMember(dto => dto.Orientation, conf => conf.MapFrom(entity => entity.Orientation.OrientationText))
.ForMember(dto => dto.Education, conf => conf.MapFrom(entity => entity.Education.EducationText))
.ForMember(dto => dto.Employment, conf => conf.MapFrom(entity => entity.Employment.EmploymentText))
.ForMember(dto => dto.EarningRange, conf => conf.MapFrom(entity => entity.EarningRange.EarningRangeText))
.ForMember(dto => dto.Language, conf => conf.MapFrom(entity => entity.Language.LanguageCode))
.ForMember(dto => dto.CallTimeId, conf => conf.MapFrom(entity => entity.CallTime.CallTimeText));
config.CreateMap<ParticipantDetailDto, ParticipantDetail>();
config.CreateMap<UserDetailDto, UserDetail>();

Related

Entity Framework Core 3 : Pulling data from multiple sources using join

I basically have three tables that I need to query information to get PersonNotes. I am using Entity Framwork Core 3.
Person Table
PersonNote Table
PersonNoteAttachment Table
One person can have many personnotes and one personnote can contain many PersonNoteAttachment.
I need Person table to get the FirstName and LastName which is mapped to the AuthorName in the PersonNote User data model. You can see the mapping section which shows the mapping.
DataModels
namespace Genistar.Organisation.Models.DataModels
{
[Table(nameof(PersonNote), Schema = "common")]
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
[ForeignKey("PersonId")]
public Person Person { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
[ForeignKey("AuthorId")]
public Person Author { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
}
}
namespace Genistar.Organisation.Models.DataModels
{
[Table(nameof(PersonNoteAttachment), Schema = "common")]
public class PersonNoteAttachment
{
public int Id { get; set; }
public int PersonNoteId { get; set; }
[ForeignKey("PersonNoteId")]
public PersonNote PersonNote { get; set; }
public string Alias { get; set; }
public string FileName { get; set; }
public string MimeType { get; set; }
public int Deleted { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
}
}
User Model - This is the model that I am returning to the client application
namespace Genistar.Organisation.Models.User
{
[Table(nameof(PersonNote), Schema = "common")]
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
public string AuthorName { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
}
}
Mapping
CreateMap<Genistar.Organisation.Models.DataModels.PersonNote, Genistar.Organisation.Models.User.PersonNote>()
.ForMember(t => t.Id, opt => opt.MapFrom(s => s.Id))
.ForMember(t => t.PersonId, opt => opt.MapFrom(s => s.PersonId))
.ForMember(t => t.AuthorName, opt => opt.MapFrom(s => s.Author.FirstName + " " + s.Author.LastName))
.ForMember(t => t.Note, opt => opt.MapFrom(s => s.Note))
.ForMember(t => t.AuthorId, opt => opt.MapFrom(s => s.AuthorId))
.ForMember(t => t.CreatedBy, opt => opt.MapFrom(s => s.CreatedBy))
.ForMember(t => t.Created, opt => opt.MapFrom(s => s.Created));
The following query works but is only pulling data from Person and PersonNote table. I am looking at getting the PersonNoteAttachment as well. How do I do that ? I would basically need FileName & MimeType
field populated in User.PersonNote model. If you see above I have created a PersonNoteAttachment data model
Repository
public IQueryable<PersonNote> GetPersonNotes(int personId)
{
var personNotes = _context.PersonNotes.Include(x => x.Person).Include(x=> x.Author).Where(p => p.PersonId == personId);
return personNotes;
}
API :
[FunctionName(nameof(GetPersonNote))]
[UsedImplicitly]
public Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
int id) => _helper.HandleAsync(async () =>
{
//await _helper.ValidateRequestAsync(req, SecurityPolicies.ViewNotes);
var personNotes = await _organisationRepository.GetPersonNotes(id).ProjectTo<PersonNote>(_mapper.ConfigurationProvider).ToListAsync();
return new OkObjectResult(personNotes);
});
My approach was to do it the following way in the repository but I need to return the PersonNote datamodel in the repository. I cannot add those additional fields in the model because it say invalid columns.How do I approach this ?
var personNotes = _context.PersonNotes
.Include(x => x.Person)
.Include(x => x.Author)
.Where(p => p.PersonId == personId)
.Join(_context.PersonNotesAttachments, c => c.Id, cm => cm.PersonNoteId, (c, cm) => new
{
cm.PersonNote.Id,
cm.PersonNote.PersonId,
cm.PersonNote.Person,
cm.PersonNote.Note,
cm.FileName,
cm.MimeType,
cm.Alias,
cm.PersonNote.AuthorId,
cm.PersonNote.CreatedBy,
cm.PersonNote.Created
});
I have resolved the issue
I just had to add the following line in PersonNote datamodel
public PersonNoteAttachment PersonNoteAttachment { get; set; }
Added the new fields to the PersonNote usermodel and did the following mapping
.ForMember(t => t.FileName, opt => opt.MapFrom(s => s.PersonNoteAttachment.FileName))
.ForMember(t => t.MimeType, opt => opt.MapFrom(s => s.PersonNoteAttachment.MimeType))
.ForMember(t => t.Alias, opt => opt.MapFrom(s => s.PersonNoteAttachment.Alias))

Entity Framework Core: How to solve Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths

I'm using Entity Framework Core with Code First approach but recieve following error when updating the database:
Introducing FOREIGN KEY constraint 'FK_AnEventUsers_Users_UserId' on table 'AnEventUsers' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.
My entities are these:
public class AnEvent
{
public int AnEventId { get; set; }
public DateTime Time { get; set; }
public Gender Gender { get; set; }
public int Duration { get; set; }
public Category Category { get; set; }
public int MinParticipants { get; set; }
public int MaxParticipants { get; set; }
public string Description { get; set; }
public Status EventStatus { get; set; }
public int MinAge { get; set; }
public int MaxAge { get; set; }
public double Longitude { get; set; }
public double Latitude { get; set; }
public ICollection<AnEventUser> AnEventUsers { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class User
{
public int UserId { get; set; }
public int Age { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Gender Gender { get; set; }
public double Rating { get; set; }
public ICollection<AnEventUser> AnEventUsers { get; set; }
}
public class AnEventUser
{
public int AnEventId { get; set; }
public AnEvent AnEvent { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
public class ApplicationDbContext:DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AnEventUser>()
.HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<AnEventUser>()
.HasKey(t => new { t.AnEventId, t.UserId });
modelBuilder.Entity<AnEventUser>()
.HasOne(pt => pt.AnEvent)
.WithMany(p => p.AnEventUsers)
.HasForeignKey(pt => pt.AnEventId);
modelBuilder.Entity<AnEventUser>()
.HasOne(eu => eu.User)
.WithMany(e => e.AnEventUsers)
.HasForeignKey(eu => eu.UserId);
}
public DbSet<AnEvent> Events { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<AnEventUser> AnEventUsers { get; set; }
}
The issue I thought was that if we delete a User the reference to the AnEvent will be deleted and also the reference to AnEventUser will also be deleted, since there is a reference to AnEventUser from AnEvent as well we get cascading paths. But I remove the delete cascade from User to AnEventUser with:
modelBuilder.Entity<AnEventUser>()
.HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);
But the error doesn't get resolved, does anyone see what is wrong? Thanks!
In your sample code in OnModelCreating you have declared modelBuilder.Entity<AnEventUser>().HasOne(e => e.User)... twice: at start of method and at end.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AnEventUser>() // THIS IS FIRST
.HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<AnEventUser>()
.HasKey(t => new { t.AnEventId, t.UserId });
modelBuilder.Entity<AnEventUser>()
.HasOne(pt => pt.AnEvent)
.WithMany(p => p.AnEventUsers)
.HasForeignKey(pt => pt.AnEventId);
modelBuilder.Entity<AnEventUser>() // THIS IS SECOND.
.HasOne(eu => eu.User) // THIS LINES
.WithMany(e => e.AnEventUsers) // SHOULD BE
.HasForeignKey(eu => eu.UserId); // REMOVED
}
Second call overrides first. Remove it.
This is what I did from the answer of Dmitry,
and It worked for me.
Class:
public class EnviornmentControls
{
public int Id { get; set; }
...
public virtual Environment Environment { get; set; }
}
And it's Mapping
public EnviornmentControlsMap(EntityTypeBuilder<EnviornmentControls> entity)
{
entity.HasKey(m => m.Id);
entity.HasOne(m => m.Environment)
.WithMany(m => m.EnviornmentControls)
.HasForeignKey(m => m.EnvironmentID)
.OnDelete(DeleteBehavior.Restrict); // added OnDelete to avoid sercular reference
}
These solutions didn't work for my case, but I found a way. I am not quite sure yet if it is safe but there's just something that's happening with deleting. So I modified the generated Migration File instead of putting an override.
onDelete: ReferentialAction.Cascade
The reason I did this because all the overriding mentioned above is not working for me so I manually removed the code which relates to Cascading of Delete.
Just check which specific relation being mentioned at the error so you can go straightly.
Hope this will be able to help for some people who's having the same issue as mine.
public Guid? UsuarioId { get; set; }
builder.Entity<Orcamentacao>()
.HasOne(x => x.Usuario)
.WithMany(x => x.Orcamentacaos)
.OnDelete(DeleteBehavior.Restrict)
.IsRequired(false)
.HasForeignKey(x => x.UsuarioId);

Inserting a dependent entity when inserting a parent with Entity Framework

I am having an issue inserting a record for a dependent entity when inserting the parent. Below is my entity definitions and mappings
EBUser
public partial class EBUser : ModelBase, IUser<long>
{
public string UserName { get; set; }
public string Password { get; set; }
public long AccountId { get; set; }
public EBAccount EbAccount { get; set; }
public string Email { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime? LastUpdateDate { get; set; }
public virtual EBUserInfo UserInfo { get; set; }
}
EBUserInfo
public partial class EBUserInfo : ModelBase
{
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DisplayName { get; set; }
public virtual EBUser User { get; set; }
}
EBUserMapping
public class EBUserMapping : BaseEntityMapping<EBUser>
{
public EBUserMapping()
{
this.ToTable("Users");
this.Property(u => u.AccountId).HasColumnName("AccountId");
this.Property(u => u.Password).HasColumnName("Password");
this.Property(u => u.UserName).HasColumnName("UserName");
this.Property(u => u.Email).HasColumnName("Email");
this.Property(u => u.CreatedDate).HasColumnName("CreatedDate");
this.Property(u => u.LastUpdateDate).HasColumnName("LastUpdateDate").IsOptional();
//this.HasRequired(u => u.UserInfo).WithRequiredDependent(u => u.User);
this.HasRequired(t => t.EbAccount)
.WithMany(t => t.Users)
.HasForeignKey(d => d.AccountId);
}
}
EBUserInfoMapping
public class EBUserInfoMapping :BaseEntityMapping<EBUserInfo>
{
public EBUserInfoMapping()
{
this.ToTable("UserInfo");
this.Property(u => u.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(u => u.Email).HasColumnName("Email");
this.Property(u => u.FirstName).HasColumnName("FirstName");
this.Property(u => u.LastName).HasColumnName("LastName");
this.Property(u => u.DisplayName).HasColumnName("DisplayName");
// Relationships
this.HasRequired(t => t.User).//WithRequiredDependent(t => t.UserInfo);
WithOptional(t => t.UserInfo);
}
}
In the database schema, all tables have an ID column but in the EBUserInfor class the Id column is both the primary and foreign key to the EBUsers table.
The BaseEntityuMapping maps the Id column and set the DatabaseGenerationOptions to identity but in the EBUserinfoMapping class I overwrite that with a DatabaseGenerationOption of None.
When I insert a new EBUser record using Entity Framework, the user record is created but no userInfo record is created
Please help
Thanks
Map user to userInfo as
EBuser user= new EBuser();
// fill here user
EBuserInfo info = new EBuserInfo();
Info.userInfo= user;
// fill here rest info
db.add(info);
db.saveChanges();

Entity Framework many to many fluent API

I'm working with an existing database whose schema is fixed.
There are 3 many-to-many relations, Contact-Group, Contact-Department and Contact-Team.
There is a common table, ContactRelation that acts as the middle table for all 3 relations.
public class Contact
{
[Column("CtcID")]
public int Id { get; set; }
[Column("CtcFirstName")]
public string FirstName { get; set; }
[Column("CtcFamilyName")]
public string LastName { get; set; }
public virtual ICollection<ContactRelation> GroupRelations { get; set; }
public virtual ICollection<ContactRelation> DepartmentRelations { get; set; }
public virtual ICollection<ContactRelation> TeamRelations { get; set; }
}
public class Group
{
[Key, Column("GRID")]
public int Id { get; set; }
[Column("GRName")]
public string Name { get; set; }
public virtual ICollection<ContactRelation> ContactRelations { get; set; }
}
public class Department
{
[Key, Column("DEPID")]
public int Id { get; set; }
[Column("DEPName")]
public string Name { get; set; }
public virtual ICollection<ContactRelation> ContactRelations { get; set; }
}
public class Team
{
[Key, Column("TMID")]
public int Id { get; set; }
[Column("TransCode")]
public string TransCode { get; set; }
public virtual ICollection<ContactRelation> ContactRelations { get; set; }
}
public class ContactRelation
{
[Key]
[Column("CtcRelnID")]
public int Id { get; set; }
[Column("GRID")]
public int GroupId { get; set; }
[Column("DEPID")]
public int DepartmentId { get; set; }
[Column("TMID")]
public int TeamId { get; set; }
[Column("CUCtcID")]
public int ContactId { get; set; }
[Column("RCode")]
public string RoleCode { get; set; }
}
In my mapping, I have the following code:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Group>()
.HasMany(g => g.ContactRelations)
.WithRequired()
.HasForeignKey(r => r.GroupId);
modelBuilder.Entity<Department>()
.HasMany(c => c.ContactRelations)
.WithRequired()
.HasForeignKey(r => r.DepartmentId);
modelBuilder.Entity<Team>()
.HasMany(s => s.ContactRelations)
.WithRequired()
.HasForeignKey(r => r.TeamId);
modelBuilder.Entity<Contact>()
.HasMany(c => c.GroupRelations)
.WithRequired()
.HasForeignKey(r => r.ContactId);
modelBuilder.Entity<Contact>()
.HasMany(c => c.DepartmentRelations)
.WithRequired()
.HasForeignKey(r => r.ContactId);
modelBuilder.Entity<Contact>()
.HasMany(c => c.TeamRelations)
.WithRequired()
.HasForeignKey(r => r.ContactId);
}
I then try to execute the following query:
var ctc = repo.Contacts
.Include("GroupRelations")
.Include("DepartmentRelations")
.FirstOrDefault(c => c.FirstName.ToLower() == "jason");
and I keep getting error:
System.Data.SqlClient.SqlException:
Invalid column name 'Contact_Id1'.
Invalid column name 'Contact_Id'.
Invalid column name 'Contact_Id1'.
Invalid column name 'Contact_Id2'.
I read somewhere that a table cannot participate in more than one many-to-many relations. Is that true? Is it because the ContactRelation table is used more than once that I'm getting this error?
If so, what's the correct way to map these relations, without modifying the database schema.?
PS: I'm working with EF6.1
Thanks for your help.
Remove this mapping
modelBuilder.Entity<Contact>()
.HasMany(c => c.TeamRelations)
.WithRequired()
.HasForeignKey(r => r.ContactId);
and then try executing your query.

EF Code First Approach: Confused in EF Foreign Key constraint by fluent syntax

I am trying to create a foreign key relation ship with fluent syntax using EF code first approach.
My entities are as follows,
public partial class Defect
{
public int DefectID { get; set; }
public decimal ReleaseNo { get; set; }
public int BuildNo { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string StepsToReproduce { get; set; }
public int ApplicationModuleID { get; set; }
public int SeverityLevel { get; set; }
public string LoggedBy { get; set; }
public Nullable<System.DateTime> LoggedOn { get; set; }
public string LastModifiedBy { get; set; }
public Nullable<System.DateTime> LastModifiedOn { get; set; }
public string AssignedTo { get; set; }
public string Status { get; set; }
public string ResolutionNote { get; set; }
public Nullable<System.DateTime> ResolvedOn { get; set; }
public int ProjectID { get; set; }
public virtual SeverityIndex SeverityIndex { get; set; }
public virtual User LoggedByUser { get; set; }
public virtual User LastModifiedUser { get; set; }
public virtual User AssignedToUser { get; set; }
public virtual Project Project { get; set; }
}
public class DefectMap:EntityTypeConfiguration<Defect>
{
public DefectMap()
{
this.HasKey(d => d.DefectID);
this.ToTable("Defect");
this.Property(d => d.DefectID)
.IsRequired()
.HasColumnName("DefectID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(d => d.Description)
.IsRequired()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(2000)
.HasColumnName("Description")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.StepsToReproduce)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(4000)
.HasColumnName("StepsToReproduce")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.LastModifiedBy)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(10)
.HasColumnName("LastModifiedBy")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.AssignedTo)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(10)
.HasColumnName("AssignedTo")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.Status)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(50)
.HasColumnName("Status")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(d => d.ResolutionNote)
.IsOptional()
.IsUnicode()
.IsVariableLength()
.HasMaxLength(4000)
.HasColumnName("ResolutionNote")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.HasRequired(p => p.Project).WithMany(p => p.DefectList).HasForeignKey(p => p.ProjectID);
this.HasRequired(s => s.SeverityIndex).WithMany(s => s.DefectList).HasForeignKey(s => s.SeverityLevel).WillCascadeOnDelete();
this.HasOptional(u => u.AssignedToUser).WithMany(u => u.AssignedToUserList).HasForeignKey(u => u.AssignedTo).WillCascadeOnDelete();
this.HasOptional(u => u.LastModifiedUser).WithMany(u => u.ModifiedByUserList).HasForeignKey(u => u.LastModifiedBy);
this.HasRequired(u => u.LoggedByUser).WithMany(u => u.LoggedByUserList).HasForeignKey(u => u.LoggedBy);
}
public partial class Project
{
public Project()
{
ApplicationModuleList = new List<ApplicationModule>();
DefectList = new List<Defect>();
UserList = new List<User>();
}
public int ID { get; set; }
public string ProjectName { get; set; }
public string ProjectManager { get; set; }
public Nullable<System.DateTime> ProjectStartDate { get; set; }
public Nullable<System.DateTime> ProjectEstimatedEndDate { get; set; }
public Nullable<System.DateTime> ProjectActualEndDate { get; set; }
public Nullable<int> ProjectBillingModel { get; set; }
public Nullable<decimal> ProjectEstimatedBudget { get; set; }
public Nullable<decimal> ProjectActualBudget { get; set; }
public Nullable<int> ProjectPortfolio { get; set; }
public Nullable<decimal> ProjectBillingRate { get; set; }
public Nullable<int> ProjectEstimatedManHours { get; set; }
public Nullable<int> ProjectActualManHours { get; set; }
public Nullable<int> ProjectIsApproved { get; set; }
public virtual ICollection<ApplicationModule> ApplicationModuleList { get; set; }
public virtual ICollection<Defect> DefectList { get; set; }
public virtual ICollection<User> UserList { get; set; }
public virtual BillingModel BillingModel { get; set; }
public virtual Portfolio Portfolio { get; set; }
public virtual ApprovalStatus ApprovalStatus { get; set; }
}
public class ProjectMap:EntityTypeConfiguration<Project>
{
public ProjectMap()
{
this.HasKey(p => p.ID);
this.ToTable("Projects");
this.Property(p => p.ID)
.HasColumnName("ID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
this.Property(p => p.ProjectName)
.HasColumnName("ProjectName")
.HasMaxLength(200)
.IsRequired()
.IsVariableLength()
.IsUnicode()
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.HasOptional(p => p.BillingModel).WithMany(p=>p.Projects).HasForeignKey(p => p.ProjectBillingModel).WillCascadeOnDelete();
this.HasOptional(p => p.Portfolio).WithMany(p=>p.Projects).HasForeignKey(p => p.ProjectPortfolio).WillCascadeOnDelete();
this.HasOptional(p => p.ApprovalStatus).WithMany(p=>p.Projects).HasForeignKey(p => p.ProjectIsApproved).WillCascadeOnDelete();
}
}
I am trying code first approach for database creation using fluent API.
However when I run the code I get error saying
*Introducing FOREIGN KEY constraint 'FK_dbo.User_dbo.Projects_ProjectID' on table 'User' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors*
The same error appears for AssignedTo column.
Here I am trying to implement logic where, A project can have many defects and a defect should have an associated Project ID (i.e one to many relationship between project and defect).
Can anyone suggest what is wrong with the code and where should I rectify the code to get things working?
Thanks in advance!!!
EF has Cascade delete on by default, and this will cause problems with your design - as per the error message.
Either add the following
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
}
or include
WillCascadeOnDelete(false)
in your fluent API