Database-first key annotations unrecognized by entity framework - asp.net-mvc

I am trying to use partial classes to decorate EF's auto-generated entity models for SQL views that I have access to. These views are 1:1 representations of tables, but omit the primary keys and foreign key constraints present in the database. I would like to reproduce these keys/constraints with data annotations, but attempting to use them within EF fails.
Any attempts to use Include or Find within LINQ always fail. The foreign key defined here, for example, does not seem to be recognized:
public class FactTimeEntryMetadata
{
[Key]
public int TimeEntryKey { get; set; }
[ForeignKey("DimEmployee.EmployeeKey")]
public int EmployeeKey { get; set; }
}
[MetadataType(typeof(FactTimeEntryMetadata))]
public partial class FactTimeEntry { }
public class DimEmployeeMetadata
{
[Key]
public int EmployeeKey { get; set; }
}
[MetadataType(typeof(DimEmployeeMetadata))]
public partial class DimEmployee { }
In this example, the FactTimeEntry contains TimeEntryKey as a primary, and a column for EmployeeKey, referring to the foreign key in DimEmployee. Is my syntax off in some way, or is this simply not possible with Entity Framework database-first?
Edit:
I have also tried to add a virtual reference to the object, like so:
public class FactTimeEntryMetadata
{
[Key]
public int TimeEntryKey { get; set; }
[ForeignKey("DimEmployee")]
public int EmployeeKey { get; set; }
public virtual DimEmployee DimEmployee { get; set; }
}
[MetadataType(typeof(FactTimeEntryMetadata))]
public partial class FactTimeEntry { }
public class DimEmployeeMetadata
{
[Key]
public int EmployeeKey { get; set; }
}
[MetadataType(typeof(DimEmployeeMetadata))]
public partial class DimEmployee { }
but was also unsuccessful this way.

Your only three options using ef-database-first:
Put your keys and relationships in your database. Relational Databases were created to be relational. If you don't do that, why use a database?
As Gert Arnold metion in his comment, edit the EDMX and assign your associations.
Edit the T4 templates with custom code to add Keys/relationships to your objects.

Related

Entity Framework and Many-to-Many relationships, controlling the Intermediate table column names

I'm trying to wrap my head around a Many-to-Many relationship with Code-First mapping.
If I have an Album Class that can have many Genres (and vice-versa), I understand that I need to have an Intermediate table and Entity Framework will automatically do that for me. However, I would like a little more control over the Intermediate table, so I am creating one myself, the main reason is that I would like to be able to mark the row as deleted from the front-end and leave it in the database.
To do this for all my Classes I have created a BaseObject that they are Inherit from (I've removed many of the Annotations and other code to simplify this post):
public class BaseObject
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Oid { get; set;
public DateTime DateCreated { get; set; }
public bool IsDeleted { get; set; }
public DateTime? DeletedDate { get; set; }
}
After that we have the Albums and Genres Classes:
public class Album : BaseObject
{
public string Name { get; set; }
public virtual List<AlbumsGenres> Albums { get; set; }
}
public class Genre : BaseObject
{
public string Name { get; set; }
public virtual List<AlbumsGenres> Genres { get; set; }
}
Finally the AlbumsGenres Intermediate Class:
public class AlbumsGenres : BaseObject
{
// Left blank because EF will create "Album_Oid" and "Genre_Oid" columns
// Tried the below code, but EF still created it's own Columns
/*
public Guid Album { get; set; }
public Guid Genre { get; set; }
*/
}
The questions that I have; Is there a way to tell EF to create Album_Oid with a different Column Name like Album?
I would accept an answer of "Just don't worry about it", if a brief explanation (or link) was provided.
You can control the intermediate table, Normally I use explicit mapping but the following works with CodeFirst:
In Album, you want a List<Genre> (not AlbumGenre)
In Genre, you want a List<Album>
In your context, add the following override for OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Album>()
.HasMany(a => a.Genres)
.WithMany(g => g.Albums)
.Map(x =>
{
x.MapLeftKey("AlbumId");
x.MapRightKey("GenreId");
x.ToTable("AlbumGenres");
});
base.OnModelCreating(modelBuilder);
}

Entity Framework 6 - How to mark a property as NOT foreign key

I'm using ASP.NET MVC5 together with EF6 and using the code first approach.
I have a property in a model that i need to to tell EF6 is NOT a foreign key:
public class LogEntry
{
public int ID { get; set; }
public int LogDayID { get; set; }
public int LogEntryTypeID { get; set; }
public int DepartmentID { get; set; }
public DateTime Clock { get; set; }
public string Text { get; set; }
public virtual LogDay LogDay { get; set; }
public virtual LogEntryType LogEntryType { get; set; }
public virtual Department Department { get; set; }
}
[NotMapped]
public class Department
{
public int ID { get; set; }
public string Title { get; set; }
}
The model Department has the [NotMapped] as this model should not be stored in the database.
I thought this was enough to make EF6 realise that DepartmentID in LogEntry shouldn't be a foreign key.. But instead it throws me an error that 'Department' is not mapped.
EDIT: Even if i remove the DepartmentID from LogEntry it still complains with the above error.
Here's the complete error message:
"The type 'SupervisorLogWeb.Models.Department' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive or generic, and does not inherit from EntityObject."
Apparently your ComplexType is discovered as a Entity - this happens, if you decided to refactor an former Entity to a ComplexType.
The ModelBuilder will decide if an type is an Entity or not (more or less) by it's presence or absence in the DbContext.
So check if your class is still defined as DbSet inside the Context and adjust accordingly.
Add the NotMapped attribute to the DeparmentID property as well. This attribute can also be applied on properties.
When all your mappings are based on conventions, EF (or any tool) can't really tell whether you broke the convention intentionally or you made a mistake. It can apply some heuristics but it's better to fail and ask the programmer than implement an unwanted mapping.

(Code First) Entity Framework foreign keys using non standard naming convention

I'm using code first in my Models and trying to add 2 properties to an assessment class which will be foreign keys back to my Provider Class.
... In Assessment Class ...
public class Assessment
{
public int AssessmentID { get; set; }
public int createdByProviderID { get; set; } // this will container a providerID
public int closedByProviderID { get; set; } // this will container a providerID
}
...
... Provider ...
public class Provider
{
public int ProviderID { get; set; }
}
...
I can't figure out how to do this because they don't follow the standard naming convention that EF looks for.
You can do it a couple of ways; I personally use mapping classes to keep the database-specific details out of my models, but I can't tell from your question if you are using that approach or not. Assuming you just have model classes, you can do the following:
1 - Add a virtual property (which will allow for lazy-loading) pointing to the Provider model for each foreign key.
2 - Decorate each of these new virtual properties with the ForeignKey attribute, pointing back to the property that is the actual foreign key.
public int createdByProviderID { get; set; } // this will container a providerID
[ForeignKey("createdByProviderID")]
public virtual Provider createdByProvider{get; set;}
public int closedByProviderID { get; set; } // this will container a providerID
[ForeignKey("closedByProviderID")]
public virtual Provider closedByProvider{get; set;}
Best of luck.

EF Code First: model type is not pluralized in the repository

I have a State model class:
public class State
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
}
And I am trying to create a Repository:
Scaffold Repository State
I've got in generated file:
public IQueryable<State> All
{
get { return context.State; }
}
instead of context.StateS.
Property
public DbSet<State> States { get; set; }
successfully has been added to the DbContext class.
I have no overrided OnModelCreating method.
Sometimes I mention such problem in different projects but can not find a reason.
I know I've had problems with namespace confusion when using the word "State" for my database tables and POCOs. So to make things easier, I rename those to something else, like USState or StateCode. That could be what's going on here for you and the scaffolding.

how do i create a composite key that comprises a foreign key with code first?

I am using EF4 code first and want to generate a composite key which is made of a class property and foreign key. I have two classes: Order and Company. The Order class holds a reference but this will not necessarily be unique between companies. So I intend to use a composite key made up of Reference and Company.CompanyId.
I have tried using the following to set it but I get an error message "Key expression is not valid".
modelBuilder.Entity<Order>().HasKey(o => new { o.Reference, o.Company.CompanyId });
I have also tried
modelBuilder.Entity<Order>().HasKey(o => new { o.Reference, o.Company });
and this fails.
these are my classes:
public class Order
{
public string Reference { get; set; }
public Company Company { get; set; }
}
public class Company
{
public int CompanyId { get; set; }
public virtual ICollection Orders { get; set; }
}
Any help would be greatly appreciated.
As Antony Highsky mentioned, you can only use scalar properties in the key.
So, you will need to add a foreign key (scalar property) to the Order class and associate it with the navigation property Company as shown below:
public class Order
{
public string Reference { get; set; }
public int CompanyId { get; set; }
[RelatedTo(ForeignKey = "CompanyId")]
public Company Company { get; set; }
}
And then create the composite key using the model builder:
modelBuilder.Entity<Order>().HasKey(o => new { o.Reference, o.CompanyId });
Note that data annotations (RelatedTo attribute) were introduced with the Entity Framework CTP 3. For another option that only uses data annotations instead of HasKey method, see this post:
http://www.luisrocha.net/2010/11/creating-composite-keys-using-code.html
One thing that doesn't look quite right is your use of the non-generic version of ICollection. Try this:
public virtual ICollection<Order> Orders { get; set; }
Did you try this?
modelBuilder.Entity().HasKey(o =>o.Reference );
modelBuilder.Entity().HasKey(o =>o.CompanyId );
According to this source, only scalar properties are allowed in the key. Navigation properties are not.

Resources