I've been searching to see if what I want is possible in EF6 Code First.
I have added a View in my database.
CREATE VIEW MyView AS
SELECT x.Id, x.Something, y.SomethingElse
FROM ....
I also have an entity with primary key Id:
public class MyEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
}
So, now, what I would like to do, is add a navigation property to MyEntity, like so:
public class MyEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public ICollection<MyViewEntity> MyView { get; set; } = new Collection<MyViewEntity>();
}
Note: I've found this question. What I would like to do is the opposite.
For this purpose, I have created a class and added a foreign key attribute to indicate the relationship.
[Table("MyViewEntity")] // Hardcoded name, no -s suffix
public class MyViewEntity
{
public int MyEntityId { get; set; }
[ForeignKey("BusinessId,StatementId")]
public MyEntity MyEntity { get; set; }
public int Something { get; set; }
public int SomethingElse { get; set; }
}
Either I've forgotten something or what I want is not possible, because I get the error that there's a pending migration. If I run Add-Migration test, EF Code First tries to create a table "MyViewEntity" with the properties MyEntityId, Something, SomethingElse.
How can I tell Entity Framework that the navigation property I want to use comes from a View that's already there?
Related
I have two tables: Place, and MenuSection, that currently have a one-to-many relationship defined like so:
public class Place
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int PlaceID { get; set; }
public virtual ICollection<MenuSection> MenuSections { get; set; }
}
public class MenuSection
{
[Key]
public int MenuSectionID { get; set; }
public int PlaceID { get; set; }
}
However, I now need a many-to-many relationship. If I was just starting out then this would be achieved by changing the MenuSection class to look like this:
public class MenuSection
{
[Key]
public int MenuSectionID { get; set; }
public virtual ICollection<Place> Places { get; set; }
}
The problem is I already have vast amounts of data and business logic associated with the current relationship. So I figure I'll have to leave the PlaceID property in for now and add the places collection.
My question then is: how do I then tell EF the relationship is now many-to-many and to populate the auto-generated joining table with the existing relationships so that I can then remove the PlaceID property from the MenuSection class?
Alternatively I suppose I could manually create a joining table and rewrite all the business logic, manually move the existing relationships over and rewrite all the business logic like so:
public class Place
{
[Key]
[ForeignKey("Place")]
public int PlaceID { get; set; }
[Key]
[ForeignKey("MenuSection")]
public int MenuSectionID { get; set; }
public virtual Place Place { get; set; }
public virtual MenuSection MenuSection { get; set; }
}
I'm surprised this question hasn't been asked before so I just wanted to check I haven't missed a trick?
I am using Entity Framework Database First, but I would like to replicate the following behavior from the Code First paradigm:
In Entity Framework Code First, you can do something along these lines:
public class Thing
{
public int ID { get; set; }
ICollection<Stuff> Stuffs { get; set; }
}
public class Stuff
{
public int ID { get; set; }
ICollection<Thing> Things { get; set; }
}
And the database will generate and Associative table to represent the many to many relationship.
I'm using Database First with a legacy database. I pulled in the entities and it included the associative table representing a many-to-many relationship between two of our tables.
Since the associative table is included as an entity, the navigation properties are as such:
public class Thing
{
public int ID { get; set; }
public ICollection<ThingStuff> ThingStuffs { get; set; }
}
public class ThingStuff
{
public int ThingID { get; set; }
public int StuffID { get; set; }
ICollection<Thing> Things { get; set; }
ICollection<Stuff> Stuffs { get; set; }
}
public class Stuff
{
public int ID { get; set; }
public ICollection<ThingStuff> ThingStuffs { get; set; }
}
So to navigate, I have to:
var stuff = Thing.ThingStuffs.Select(ts => ts.Stuff);
Instead of:
var stuff = Thing.Stuffs;
So The Question Is:
Is there any way to drop the entity representing the association (ThingStuff) and tell EntityFramework about the existing table to create the many-to-many navigation properties?
Wouldn't it be better if you map your composite keys, as stated in the fluent api documentation? http://msdn.microsoft.com/en-us/data/jj591617.aspx
I have got a User entity there are my users are stored in. For some users (admins) I would like to add additional details.
I have written following code.
public partial class UserProfile
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Display(Name = "EMail")]
[Required]
public string UserName { get; set; }
[ForeignKey("AdminDetailID")]
public virtual AdminDetail AdminDetail { get; set; }
public int? AdminDetailID { get; set; }
}
public class AdminDetail
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AdminDetailID { get; set; }
[ForeignKey("UserId")]
public virtual UserProfile UserProfile { get; set; }
public int UserId { get; set; }
}
I like to navigate from my AdminDetail table back to my User Profile table by writing eg. admin.UserProfile.UserName. However, when I run Database-Update I receive:
The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
When I delete the UserProfile property everything works great.. How can I create a "back" navigation within my AdminDetail class?
Entity Framework Code-First allows for polymorphic classes to be stored in the same table. Have you considered using a relationship like this instead?
public partial class UserProfile
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Display(Name = "EMail")]
[Required]
public string UserName { get; set; }
}
public class AdminProfile : UserProfile
{
// AdminProfile members.
}
This results in a UserProfile table with an additional column called Discriminator that EF creates and manages for you. This column indicates whether each row in the table is a UserProfile or an AdminProfile. Rows which are of type UserProfile ignore the columns that are specific to AdminProfile when accessed by EF.
Entity framework handles all of the type discrimination for you so you don't need to worry about that directly. Your DbContext will simply have a DbSet which can also store entities of type AdminProfile.
You don't need to have a FK in your UserProfile class. To set up a proper 1:1 only the AdminDetail class would actually need to have the foreign key to the UserProfile class. You can still keep the virtual property to be able to navigate back and forth, and EF will know what it is that you're doing. Similar to this:
public partial class UserProfile
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Display(Name = "EMail")]
[Required]
public string UserName { get; set; }
public virtual AdminDetail AdminDetail { get; set; }
}
Say you have an order class with an order status, I want to declare the OrderStatusId inside the OrderStatus class. However, no foreign key relationship is set-up by default. If I use [ForeignKey] attribute on the column it seems to demand a navigation property which I don't want as this would mean having to carry out joins on the navigation property in all of my queries just to check the status.
How do I accomplish this in EF codefirst? Define a property as a foreign key without using a navigation property.
public class Order
{
public int OrderId;
public int OrderStatusId;
// properties...
}
public class OrderStatus
{
public int OrderStatusId;
public string Status;
}
You always need navigation property on at least one side to build a relation. If you don't have navigation properties you have nothing to bind your your foreign key with and it will remain as common column.
Create your model like this instead
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string StreetAddress { get; set; }
//etc...
//navigation properties
public virtual List<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public string OrderStatus { get; set; }
//navigation properties
public virtual Customer OrderedBy { get; set; }
//etc..
}
EF will create your foreign keys on its own using you navigation properties
no reason to expose them to the model as it is unnecessary you can access the id if necessary using the navigation properties
I'm currently getting the following error when trying to create an one to one relationship using Code First:
System.Data.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'C001_Holding_Teste_C001_Holding_Source' in relationship 'C001_Holding_Teste_C001_Holding'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be 1.
My entity definitions are the following:
[Table("C001_Holding", Schema = "Cad")]
public partial class C001_Holding
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int C001_Id { get; set; }
[MaxLength(16)]
public string C001_Codigo { get; set; }
[MaxLength(100)]
public string C001_Descricao { get; set; }
}
public class C001_Holding_Test
{
[Key]
public int C001_Id { get; set; }
[MaxLength(100)]
public string C001_TestInfo { get; set; }
[ForeignKey("C001_Id")]
public virtual C001_Holding C001_Holding { get; set; }
}
I didn't want to use Fluent to create these relationships, does anyone knows why this is happening?
Tks.
It is possible to place the ForeignKey attribute either on a navigation property and then specify the name of the property you want to have as the foreign key (that's what you did). Or you can place it on the foreign key property and then specify the name of the navigation property which represents the relationship. This would look like:
public class C001_Holding_Test
{
[Key]
[ForeignKey("C001_Holding")]
public int C001_Id { get; set; }
[MaxLength(100)]
public string C001_TestInfo { get; set; }
public virtual C001_Holding C001_Holding { get; set; }
}
For some reason this second option works while the first throws an error. (It feels like a bug to me because both options should represent the same relationship. Or there is actually a semantic difference which I don't see...)