I have 2 tables IncomingCheck and OutgoingCheck which contain many History items. To achieve this I've used inheritance and inherited 2 classes for incoming and outgoing histories.
public class IncomingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<IncomingCheckHistory> History { get; set; }
//... other stuff
}
public class OutgoingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<OutgoingCheckHistory> History { get; set; }
//... other stuff
}
public class CheckHistory
{
[Key]
public int Id { get; set; }
//... other stuff
}
public class IncomingCheckHistory : CheckHistory
{
public IncomingCheck IncomingCheck { get; set; }
}
public class OutgoingCheckHistory : CheckHistory
{
public OutgoingCheck OutgoingCheck { get; set; }
}
This approach works perfectly. In my database I have a table called CheckHistories with 2 nullable columns named [IncomingCheck_Id] and [OutgoingCheck_Id].
Now I have created a view on IncomingCheck which I created in Sql Server Management Studio and I can get its data using EF:
public class ViewIncomingCheck
{
[Key]
public int Id { get; set; }
public virtual IList<IncomingCheckHistory> History { get; set; }
//... other stuff
}
So far so good, but now I want Entity Framework to automatically load the History items but when I try to load the data, I get the following error:
SqlException: Invalid column name 'ViewIncomingCheck_Id'.
Invalid column name 'ViewIncomingCheck_Id'.
My guess is that the EF is looking for a column named ViewIncomingCheck_Id in the IncomingCheckHistory table but can't find it.
Is there a way to tell EF that it should use IncomingCheck_Id instead of ViewIncomingCheck_Id?
Related
Using Entity Framework Code first I have a class that holds data for a drop-down list. The same class holds records that are sub-items for the items in the main list. Ultimately this will create a cascading set of drop-down lists.
I am trying to figure out how to make the navigation property for the class link back to itself. The issue class is the one that I am using to populate the drop-down list. The Complaint class also has a link to the Issues class but does not need a link back to the subcategory.
public class Issue
{
public Issue()
{
Complaints = new List<Complaint>();
SubIssues = new List<Issue>();
}
[Key]
public int IssueID { get; set; }
public string Name { get; set; }
public bool IsSubCategory { get; set; }
[ForeignKey("IssueID")]
public ICollection<Issue> SubIssues { get; set; }
public virtual ICollection<Complaint> Complaints { get; set; }
}
public class Complaint
{
public Complaint()
{
}
public int ComplaintID { get; set; }
public string Name {get; set;}
[ForeignKey("IssueID")]
public virtual Issue Issue { get; set; }
}
I did something similar, but actually did only have a parent reference in the children. Either way this should work.
public class Folder
{
[Key]
public int Id { get; set; }
// Some Property
public string Name { get; set; }
// They foreignkey for Many-side
public virtual Folder Parent { get; set; }
// The list for One-side (Not tested in my application)
public virtual ICollection<Folder> SubFolders { get; set; }
}
It is same as a regular one-to-many relation, just all the references are within same entity.
For example if I have a model:
public class BasePolicy {
public int Id { get; set; }
public string Name { get; set; }
}
public class PaymentPolicy : BasePolicy {
public string PaymentMethod { get; set; }
}
public class ReturnPolicy : BasePolicy {
public int ReturnTerm { get; set; }
}
... and want to create codefirst database and a repository with next requirements:
ability to retrieve base entities by Id in base type (BasePolicy). This is necessary for admin index page which displays list of policies only by it's name.
I need to have access to children specific properties (PaymentMethod if it is PaymentPolicy - etc.) using select by Id . This is necessary for edit actions.
What is the best way to do that? Should I create seperate table for each child type?
public class Database : DbContext
{
public DbSet<PaymentPolicy> PaymentPolicies { get; set; }
public DbSet<ReturnPolicy> ReturnPolicies { get; set; }
}
+ data is logically sorted
- I will not be able to get BasePolicy entity by it's unique id without joining those tables and specifying policy type in select query. That's why I should inject some PolicyType enum to base type and implement repository method which will get BasePolicy by it's type (to determine which table to get from) and only then by unique Id - and downcast BasePolicy to specific child type policy. This is the solution I'm using just now.
... should I remove inheritance at all?
public class PaymentPolicy {
public int Id { get; set; }
public string Name { get; set; }
public string PaymentMethod { get; set; }
}
public class ReturnPolicy {
public int Id { get; set; }
public string Name { get; set; }
public int ReturnTerm { get; set; }
}
+ data is still logically sorted
- I still will not be able to get BasePolicy entity by it's unique id.
... should I add child types as navigation properties to base type?
public class BasePolicy {
public int Id { get; set; }
public string Name { get; set; }
public PaymentPolicy PaymentPolicy { get; set; }
public ReturnPolicy ReturnPolicy { get; set; }
}
public class PaymentPolicy {
public string PaymentMethod { get; set; }
}
public class ReturnPolicy {
public int ReturnTerm { get; set; }
}
- This will destroy logic model structure
+ I will be able to get list of policies without redundant joins
+ It will provide strong one to one relationship
Or are there some more advanced strategies and techniques?
I am trying to add a many to many relationship between two of my entities. I need a junction table with an additional field, I'm aware that means EF cannot do this automatically and that I need to create an Entity for my junction table.
I have the following models
public class Supplier
{
public int Id { get; set;}
public virtual ICollection<SupplierUsers> UserPermissions { get; set; }
}
And
public class User
{
public string Id { get; set;}
public virtual ICollection<SupplierUsers> UserPermissions { get; set; }
}
I need for a user to have a permission stored in the junction table. So I have created the following entity
public class SupplierUsers
{
public string UserId { get; set; }
public int SupplierId { get; set; }
public SupplierUserPermission Permission { get; set; }
public virtual Supplier Supplier { get; set; }
public virtual User User { get; set; }
}
In my OnModelCreating I've also added the following (this is probably where I'm going wrong)
modelBuilder.Entity<SupplierUsers>()
.HasKey(x => new { x.UserId, x.SupplierId });
This works to an extent, I can successfully add a user/supplier/permission to this table.
But I cannot add the same user / supplier multiple times to this table (probably due to the PK?).
How can I alter my code so that I can add the same user or supplier multiple times in this table?
Here's what the table structure looks like at the moment:
Thank you.
If i understand you correctly you want to add multiple equal pairs of UserId and SupplierId to SupplierUsers, right?
Add a SupplierUsersId field to your SupplierUsers entity and make it primary key.
public class SupplierUsers
{
public int SupplierUsersId { get;set; }
public string UserId { get; set; }
public int SupplierId { get; set; }
public SupplierUserPermission Permission { get; set; }
public virtual Supplier Supplier { get; set; }
public virtual User User { get; set; }
}
Remove the configuration from OnModelCreating()
I have got a lot of tables in my DB and one that needs to hold common data for all of them. How can I map these tables using EntityFramework CodeFirst so I could Lazy or Eager load such data using normal queries?
Here is what I mean:
Entities:
public class Table1
{
[Key]
public int Id { get; set; }
...etc data
}
public class Table2
{
[Key]
public Guid Id { get; set; }
...etc data
}
public class Table3
{
[Key]
public string Id { get; set; }
...etc data
}
And a table with common data for all of them:
public class CommonDataTable
{
[Key]
public Guid Id { get; set; }
}
Normally I would map this by creating a table like:
public class CommonDataMappingTable
{
[Key]
public Guid Id { get; set; }
public string Mask { get; set; } // like: typeof(Table3).Name
public string MappedID { get; set; } // like: Table3.Id.ToString()
public virtual CommonDataTable MappedData { get; set; }
}
But as soon as I am new to Entity Framework I just do not know how to map such relation in EF CodeFirst model.
Thank you for your time and sorry for my bad English.
I've got a class defined
public class ReportClass
{
public int ID { get; set; }
public int ClassIndex { get; set; }
public string ClassName { get; set; }
public int CompanyID { get; set; }
}
and I set up a dbcontext.
public class ReportClassContext : DbContext
{
public DbSet<ReportClass> ReportClasses { get; set; }
}
When I first went to get records, the runtime tells me the database table doesn't exist: I check, and I see that the name of my DbSet doesn't match with the table. I switched the name to match:
public class ReportClassContext : DbContext
{
public DbSet<ReportClass> ReportClassesRealTable { get; set; }
}
but it is still querying against the non-existent table.
What am I doing wrong?
Use the table attribute like this:
[Table("ReportClassesRealTable")]
public class ReportClass
{
public int ID { get; set; }
public int ClassIndex { get; set; }
public string ClassName { get; set; }
public int CompanyID { get; set; }
}
This tells the EF what the actual table name is for your class, otherwise it attempts to use the plural form of your class name.
Let this be there as it is
public DbSet<ReportClass> ReportClasses { get; set; }
Now overrde the OnMoedlCreateing method to tell EF to map this class to a different table using fluent API. Add that method to your DBContext class
public class ReportClassContext : DbContext
{
public DbSet<ReportClass> ReportClasses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ReportClass>().ToTable("ReportClassesRealTable");
}
}
This tells EF that when you query ReportClasses property of your DbContxt object, It will fetch data from teh ReportClassRealTable table in your database.