I'm trying to setup a foreign key using the following two classes.
I want to use pAcqType as an enum and store the names of the types in another table. How should I setup my classes to do this?
public class Property
{
[Key]
public int pID { get; set; }
public string pAddress { get; set; }
public string pCounty { get; set; }
public string pCity { get; set; }
public string pState { get; set; }
public string pzip { get; set; }
public virtual PropertyAcquisitionType pAcqType { get; set; } <-- foreign key
}
public class PropertyAcquisitionType
{
[Key]
public int patID { get; set; }
public string patName { get; set; }
}
UPDATE
Dan got me thinking. And I tried the following and it seems to have worked out.
It setup the foreign key on the table like I wanted. And it didn't even ask for an inverse on the other table.
public int? pAcqType { get; set; }
[ForeignKey("pAcqType")]
public PropertyAcquisitionType patID { get; set; }
Is the foreign key required (NOT NULL in the database)?
public int pAcqTypeId { get; set; }
[ForeignKey("pAcqTypeId")]
public virtual PropertyAcquisitionType pAcqType { get; set; }
Otherwise,
public int? pAcqTypeId { get; set; }
[ForeignKey("pAcqTypeId")]
public virtual PropertyAcquisitionType pAcqType { get; set; }
Then in your other class, add an inverse relationship:
public class PropertyAcquisitionType
{
[Key]
public int patID { get; set; }
public string patName { get; set; }
[InverseProperty("pAcqType")]
public virtual ICollection<Property> pOfThisType { get; set; }
}
Here is one way you could define the relationship using the fluent API (without attributes in the entity classes). Note with this method, you should not need to add a properties property on the PropertyAcquisitionType entity to satisfy the inverse side of the relationship, because the .WithMany() tells EF what it needs to know:
public class MyDbContext : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Property>()
.HasKey(x => x.pID)
.HasRequired(x => x.pAcqType) // or HasOptional if using int?
.WithMany() // or WithMany(x => x.pOfThisType) if you want to add / keep the inverse property
.HasForeignKey(x => x.pAcqTypeId)
;
}
}
Related
I've made a dotnet ef scaffold from database and the classes generated were:
public partial class Course
{
public int Id { get; set; }
public string? Description { get; set; }
}
public partial class Student
{
public int Id { get; set; }
public string? Name { get; set; }
}
public partial class StudentCourse
{
public int? IdStudent { get; set; }
public int? IdCourse { get; set; }
public virtual Student? IdStudentNavigation { get; set; }
public virtual Course? IdCourseNavigation { get; set; }
}
I want to get a List of Student where id of Course is X
I've tried _context.Student.Include("StudentCourse").Where(x=>x.Any(....) but Intellisense does not accept "Any" function.
How can i get this ?
Any(...) is a method provided by Enumerable class so you can not use it on a single Student (which is obviously not an Enumerable object).
Your configuration of many-to-many relationship is maybe missing some lines, here is my suggestion:
public partial class Course
{
public int Id { get; set; }
public string? Description { get; set; }
public List<StudentCourse> StudentCourses { get; set; }
}
public partial class Student
{
public int Id { get; set; }
public string? Name { get; set; }
public List<StudentCourse> StudentCourses { get; set; }
}
public partial class StudentCourse
{
public int? IdStudent { get; set; }
public int? IdCourse { get; set; }
public virtual Student? StudentNavigation { get; set; }
public virtual Course? CourseNavigation { get; set; }
}
In Context file:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<StudentCourse>()
.HasOne(sc => sc.StudentNavigation)
.WithMany(s => s.StudentCourses)
.HasForeignKey(sc => sc.IdStudent);
modelBuilder.Entity<StudentCourse>()
.HasOne(sc => sc.CourseNavigation)
.WithMany(c => c.StudentCourses)
.HasForeignKey(sc => sc.IdCourse);
}
Finally, your query could be:
IEnumerable<Student> students = await _context.Students
.Include(s => s.StudentCourses)
.Where(s => s.StudentCourses.Any(sc => sc.IdCourse == X)))
I am just taking your code as example but this is not a way you design entity in EF core.
Try following though.
var students
=_context.StudentCourse.Include("IdStudentNavigation").Where(x=>x.IdCourse == 1).Select(x => x.IdStudentNavigation).ToList();
Replace one with your course id.
I'm trying to extend Application User (using Code-First) to hold a collection of orders, but I'm getting errors.
My Order class is
public class Order
{
public Order()
{
OrderDetails = new HashSet<OrderDetails>();
}
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public string UserId { get; set; }
public bool IsDelivered { get; set; }
public bool IsReturned { get; set; }
public virtual ApplicationUser User { get; set; }
public virtual ICollection<OrderDetails> OrderDetails { get; set; }
}
And I'm trying to extend Application user like this
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string CompanyName { get; set; }
public string Profession { get; set; }
public string TaxAuthority { get; set; }
public string TaxNumber { get; set; }
public string Address { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Region { get; set; }
public string Country { get; set; }
public string Phone { get; set; }
public string MobilePhone { get; set; }
public bool NewsLetterSubscribe { get; set; } = false;
public DateTime TimeStamp { get; set; } = DateTime.Now;
public ICollection<Order> Orders { get; set; }
}
And I'm getting the following errors:
QCMS.Models.IdentityUserLogin: : EntityType 'IdentityUserLogin' has no key defined. Define the key for this EntityType.
QCMS.Models.IdentityUserRole: : EntityType 'IdentityUserRole' has no key defined. Define the key for this EntityType.
IdentityUserLogins: EntityType: EntitySet 'IdentityUserLogins' is based on type 'IdentityUserLogin' that has no keys defined.
IdentityUserRoles: EntityType: EntitySet 'IdentityUserRoles' is based on type 'IdentityUserRole' that has no keys defined.
Can you please help me to solve this problem?
UPDATE:
I'm using two db contexts. The one provided for Individual User Account (when the project is first created) and a second one named "qvModel" that is for all other database classes of my project.
public partial class qvModel : DbContext
{
public qvModel()
: base("name=qvModel")
{
}
//APPSETTINGS
public virtual DbSet<AdminLog> AdminLog { get; set; }
public virtual DbSet<WebLog> WebLog { get; set; }
//LANGUAGES
public virtual DbSet<Language> Languages { get; set; }
.
.
.
public virtual DbSet<Order> Orders { get; set; }
public virtual DbSet<OrderDetails> OrderDetails { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Precision attribute for decimals
Precision.ConfigureModelBuilder(modelBuilder);
modelBuilder.Entity<Language>()
.HasMany(e => e.Brochures)
.WithRequired(e => e.Language)
.WillCascadeOnDelete(true);
.
.
.
modelBuilder.Entity<Order>()
.HasMany(c => c.OrderDetails)
.WithRequired(c => c.Order)
.WillCascadeOnDelete(true);
modelBuilder.Entity<ApplicationUser>()
.HasMany(c => c.Orders)
.WithRequired(c => c.User)
.WillCascadeOnDelete(true);
base.OnModelCreating(modelBuilder);
}
}
I found a solution that is very simple.
The solution is to inherit from IdentityDbContext like this
public class qvModel : IdentityDbContext<ApplicationUser>
{
public qvModel()
: base("name=qvModel")
{
}
I was also missing the following line from OnModelCreating
base.OnModelCreating(modelBuilder);
After these changes, my migration is working and I stopped getting the errors I mentioned.
Entity Framework code first (v6) creates a columnname in the database that I don't like. In tablename SharepointMappings it adds columnname: 'SharepointDestination_DestinationId' (foreign key).
It also generates a columnname SharepointDestinationId.
I would like to have 1 column, a foreign key, with the name 'SharepointDestinationId'.
My model looks like this:
public class Destination
{
public int DestinationId { get; set; }
}
public class SharepointDestination : Destination
{
public string UserName { get; set; }
public string Password { get; set; }
public string Domain { get; set; }
public string SiteUrl { get; set; }
public string DocumentLibraryName { get; set; }
public List<SharepointMapping> Mappings { get; set; }
}
public class SharepointMapping
{
public int SharepointMappingId { get; set; }
public string SourceFieldName { get; set; }
public string DestinationFieldName { get; set; }
//[ForeignKey("SharepointDestination")]
public int SharepointDestinationId { get; set; }
//[ForeignKey("SharepointDestinationId")]
public virtual SharepointDestination SharepointDestination { get; set; }
}
//.....
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// To use TPT inheritence
modelBuilder.Entity<SharepointDestination>().ToTable("SharepointDestinations");
//modelBuilder.Entity<SharepointMapping>()
// .HasRequired(m => m.SharepointDestination)
// .WithMany(d => d.Mappings)
// .HasForeignKey(m => m.SharepointDestinationId)
// .WillCascadeOnDelete(true);
}
It doesn't matter if i leave or add the attribute ForeignKey and it also doesn't matter if i make properties virtual or not. Completely deleting both properties on SharepointMapping or giving them a complete other name has no consequences.
I think this has something to do with the inheritence structure. Because it's 'only' a 1-n mapping.
How should I configure EF to have only 1 column with the name 'SharepointDestinationId' which should be a foreign key? (and also have the navigation property and DestinationId property on the SharepointMapping class)
Since the key of SharepointDestination is DestinationId, EF can't automatically figure it out. You could go with the annotation:
[ForeignKey("DestinationId")]
public virtual SharepointDestination SharepointDestination { get; set; }
and remove this:
[ForeignKey("SharepointDestination")]
public int SharepointDestinationId { get; set; }
The fluent should work as well if you comment out the annotation:
modelBuilder.Entity<SharepointMapping>()
.HasRequired(m => m.SharepointDestination)
.WithMany(d => d.Mappings)
.HasForeignKey(m => m.DestinationId)
.WillCascadeOnDelete(true);
The ForeignKey attribute is expecting a property name, not a table column name.
Really, you should be able to do this without any attributes.
The following should work:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Parent Parent { get; set; }
public int ParentId { get; set; }
}
Hi I've been searching around for like 40 minutes now trying to figure out how to do this and I'm not having any luck. I'm creating a forum app with ASP.NET. MVC5, and EF6. My app contains a Comment model; this is where I started running into problems. I want threads to be able to have comments(this was easy) and I also want comments to have comments(This is my problem).
Here is how my model is defined:
namespace Forum.Models
{
public class Comment
{
[Key]
public int Id {get; set;}
[DisplayFormat(DataFormatString = "{0:d/M/yyyy HH:mm:ss}",
ApplyFormatInEditMode = true)]
public DateTime TimeStamp { get; set; }
public string Content { get; set; }
public String UserId { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
[ForeignKey("ParentComment")]
public int ParentCommentId { get; set; }
public virtual Comment ParentComment { get; set; }
public int ThreadId { get; set; }
public virtual Thread Thread {get; set;}
}
}
This is the error I get when I try to update this table:
Cannot insert explicit value for identity column in table 'Comments' when IDENTITY_INSERT is set to OFF.
Any help would be greatly appreciated.
I agree with #Slauma, you need to change ParentCommentId to int? type. Also if you want to use ForeignKeyAttribute, you need to assign it to navagation property, like below:
public int? ParentCommentId { get; set; }
[ForeignKey("ParentCommentId")]
public virtual Comment ParentComment { get; set; }
Below is an example, I'm using fluent API to configure the relationships.
Coment Model class:
public class Comment
{
[Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[DisplayFormat(DataFormatString = "{0:d/M/yyyy HH:mm:ss}",ApplyFormatInEditMode = true)]
public DateTime TimeStamp { get; set; }
public string Content { get; set; }
public String UserId { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public int? ParentCommentId { get; set; }
public virtual Comment ParentComment { get; set; }
public int ThreadId { get; set; }
public virtual Thread Thread { get; set; }
}
DbContext class:
public class YourDbContext : DbContext
{
public DbSet<Comment> Comments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Comment>()
.HasOptional(c => c.ParentComment )
.WithMany(c => c.Comments)
.HasForeignKey(c => c.ParentCommentId );
}
}
I have to design a web application using existing database of desktop application. As per existing database i have below class
public class Company
{
#region Primitive Properties
public virtual int CompanyID { get; set; }
public virtual string CompanyName { get; set; }
public virtual bool IsCustomer { get; set; }
public virtual string CustomerCode { get; set; }
public virtual bool IsPotentialCustomer { get; set; }
public virtual bool IsSupplier { get; set; }
public virtual string SupplierCode { get; set; }
public virtual bool IsPotentialSupplier { get; set; }
public CompanyCategoryCodes CustomerCategoryCode { get; set; }
public CompanyCategoryCodes SupplierCategoryCode { get; set; }
public CountryCode CountryCode { get; set; }
}
public class CompanyCategoryCodes
{
public virtual int CategoryID { get; set; }
public virtual string CategoryCodes { get; set; }
public virtual bool PotentialCustomer { get; set; }
public virtual bool PotentialSupplier { get; set; }
public virtual System.DateTime LastModifiedDate { get; set; }
public virtual bool Manufacturer { get; set; }
}
public class CountryCode
{
public virtual int CountryCodeID { get; set; }
public virtual string Code { get; set; }
public virtual string Description { get; set; }
public virtual bool DefaultCode { get; set; }
public virtual bool EECVATApplies { get; set; }
public virtual System.DateTime LastModifiedDate { get; set; }
public virtual bool FixedAddressFormat { get; set; }
}
EF Code first default framework is creating Foreignkey with name "CustomerCategoryCode_CategoryID" , "SupplierCategoryCode_CategoryID", "CountryCode_CountryCodeID". I want this Foreignkey name to be consistance with my old database tables e.g. "CustomerCategoryCodeID", "SupplierCategoryCodeID", "CountryCodeID". How can i do it using EF Code First Fluient API. I try to do it using Fluient API Mapping but i got error for "SupplierCategoryCode_CategoryCodeID" as "CustomerCategoryCode_CategoryID" is also locating to same table "CompanyCategoryCode". Also if is there any option available using Data Annotation then also let me know how to achieve this.
You must manually remap each navigation property to define its key. Something like:
modelBuilder.Entity<Company>()
.HasRequired(c => c.CountryCode)
.WithMany()
.HasForeignKey("CountryCodeID");
modelBuilder.Entity<Company>()
.HasMany(c => c.CustomerCategoryCode)
.WithOptional()
.HasForeignKey("CustomerCategoryCodeID")
.WillCascadeOnDelete(false);
modelBuilder.Entity<Company>()
.HasMany(c => c.SupplierCategoryCode)
.WithOptional()
.HasForeignKey("SupplierCategoryCodeID")
.WillCascadeOnDelete(false);
It is not possible with data annotations unless you define navigation property and foreign key property in each dependent entity like:
public class Company
{
...
[ForeignKey("CountryCode")]
public virtual int CountryCodeID { get; set; }
public CountryCode CountryCode { get; set; }
}
Inside your context class, you will need to override OnModelCreating and map the keys, it should look something like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Company>()
.HasRequired(c => c.CustomerCategoryCode)
.WithMany()
.Map(mc => mc.MapKey("CustomerCategoryCodeID"));
}