I'm trying to create the POCO entity within my datacontext for the join table (the one created for the m2m relationship).
The reason I'm doing that is that I want to handle keys inserting in the table by my own. (Don't ask me why, several performance issues.)
So the algorithm is like that:
I generate the POCO class using native ADO.NET tools based on the existing table, let's say TableAnotherTable (this table joins two others Table and AnotherTable). Or just creating it manually.
I'm trying to add the migration for it. Either with -IgnoreChanges or not. Without -IgnoreChanges it tries to rename the existing table TableAnotherTable to TableAnotherTable1. Which sounds fair enough but why? It should just map the existing table to newly created POCO class.
I'm cleaning the Up() and Down() methods.
Trying to run the app and do some CUD operations within the context and constantly getting an error: Invalid object name dbo.TableAnotherTable1.
So the main question: How can I map the join table created by entity framework to my own class in order to work with it like with regular entity?
Update:
public class Client
{
public int Id {get;set;}
public ICollection<Group> Groups {get;set;}
}
public class Group
{
public int Id {get;set;}
public ICollection<Client> Clients {get;set;}
}
There is no additional configurations or something.
the name of join table in database is GroupClient
The poco class I'm retrieving with ADO.NET poco generation tools is:
[Table("GroupClient")]
public partial class GroupClient
{
[Key]
[Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Group_Id { get; set; }
[Key]
[Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Client_Id { get; set; }
}
The initial model with auto link table should have generated GroupClient table with two columns Group_Id and Client_Id forming the PK.
You should be able to map it to a model with the generated explicit GroupClient entity shown, which already defined the properties and the PK, but you need to change the type of the existing entity navigation properties and also specify the FK's:
public class Client
{
public int Id { get; set; }
[ForeignKey("Client_Id")]
public ICollection<GroupClient> Groups { get; set; }
}
public class Group
{
public int Id { get; set; }
[ForeignKey("Group_Id")]
public ICollection<GroupClient> Clients { get; set; }
}
I personally find using Fluent configuration much easier to follow:
Model:
public class Client
{
public int Id { get; set; }
public ICollection<GroupClient> Groups { get; set; }
}
public class Group
{
public int Id { get; set; }
public ICollection<GroupClient> Clients { get; set; }
}
public class GroupClient
{
public int Group_Id { get; set; }
public int Client_Id { get; set; }
}
Configuration:
modelBuilder.Entity<GroupClient>()
.ToTable("GroupClient")
.HasKey(e => new { e.Group_Id, e.Client_Id });
modelBuilder.Entity<Group>()
.HasMany(e => e.Clients)
.WithRequired() // or (e => e.Group) in case you add nav property
.HasForeignKey(e => e.Group_Id);
modelBuilder.Entity<Client>()
.HasMany(e => e.Groups)
.WithRequired() // or (e => e.Client) in case you add nav property
.HasForeignKey(e => e.Client_Id);
Related
I've got 2 entities with a 1-0..1 relationship between them, but restrictions on what the generated DB schema can look like.
So 1 Vehicle to 0 or 1 RecVehicle entity
I need to be able to have a navigation property from Vehicle to RecVehicle, but without the DB Schema for the Vehicles table having a FK to RecVehicle. The PK of the RecVehicle table should be the Id of the Vehicle entity it relates to.
We are using EF code first
public class Vehicle
{
[Key]
public int Id { get; set; }
public virtual RecVehicle RecVehicle { get; set; } // Need to be able to use as navigation
}
public class RecVehicle
{
[Key]
public int VehicleId { get; set; }
[ForeignKey("VehicleId")]
public Vehicle Vehicle { get; set; }
}
The generated schema needs to be something like this:
Vehicles
[ Id(int, pk, not null), ...] <-- no FK column to RecVehicles
RecVehicles
[ VehicleId(int, pk, fk, not null), ...]
Originally what I had tried something like this:
public class Vehicle
{
[Key]
public int Id { get; set; }
[InverseProperty("Vehicle")]
public virtual RecVehicle RecVehicle { get; set; } // Need to be able to use as navigation
}
but this causes this exception:
Unable to determine the principal end of an association between the types 'Contract.Entities.Vehicle' and 'Contract.Entities.RecVehicle'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
I'm not sure what fluent API relationships to setup to make this work, nor the correct set of data annotations to make this work, or if it's even possible.
Reasoning
The reason there is strict limitations on the DB schema is our Data team has a migration/data import process that we can not alter
We have an existing code base that uses the navigation property in many places (2 teams, desync in schema) so changing to use a lookup in code requires many changes in the code base that we are trying to avoid.
The RecVehicle can be connected to multiple Vehicles
Can you try the following navigation property?
public virtual ICollection<RecVehicle> RecVehicle { get; set; }
instead of
public virtual RecVehicle RecVehicle { get; set; }
Due to the RecVehicle primary key this list only maximum contains one element
Ended up being able to get this relationship to work like this:
public class Vehicle
{
[Key]
public int Id { get; set; }
public virtual RecVehicle RecVehicle { get; set; }
}
public class RecVehicle
{
[Key]
public int VehicleId { get; set; }
[ForeignKey("VehicleId"), Required] //<--- Required attr fixed the principal/dependent confusion EF was having
public virtual Vehicle Vehicle { get; set; }
}
I am using EF Core 3.1 and I have five Models: Plant, Area, Unit, Schema, and EntitiesSchema.
In the EnititiesSchema, the EntityId may be a foreign key of Plant(PlantId), Area(AreaId), Unit(UnitId) tables.
How to handle this optional Relationship between these tables?
Thanks
public class EntitiesSchema
{
public int Id { get; set; }
public int EntityId { get; set; }
public int TopicId { get; set; }
public int SchemaId { get; set; }
public string Description { get; set; }
public Schema Schema { get; set; }
public ICollection<Topic> Topic { get; set; }
}
No, you can't relate a foreign key to multiple tables. But you can put another property named EntityType to store the type of entity. Then on the client-side, you can handle it. The EntityType can be an enum type.
Another approach is that storing "EntitesSchemaId" in the Plant, Area, Unit, etc models and relate them to the EntitiesSchema.
You can create an intermediary entity to map to different entity types. :
Public class EntityMap
{
public int Id {get;set;}
public string EntityKind {get;set;} // could be "Plant", "Area", "Unit", "Schema"
}
public class Plant
{
public int Id {get;set;}
public string EntityKind {get;set;} = "Plant";
}
public class EntitySchema
{
public int Id {get;set;}
public int EntityMapId {get;set;}
public EntityMap Map {get;set;}
}
The logic to read data from individual schema, has to be implemented in the client,but common properties of the entities can be added in EntityMap.
Here's a similar answer you might want to reference : https://stackoverflow.com/a/53649452/7491048
I have 2 tables in database: ReceivedGoods and ReceivedGoodsProperties
ReceivedGoods contains ReceivingId as PK and must have its extending data in ReceivedGoodsProperties which contains ReceivingId as FK referencing to the ReceivedGoods's ReceivingId. Current ReceivedGoodsProperties, however, has its own PK Id and is therefore distinct from FK. So I have following:
public class ReceivedGoods
{
...
public int ReceivingId { get; set; }
...
public virtual ReceivedGoodsProperties properties { get; set; }
}
public class ReceivedGoodsProperties
{
...
public int Id { get; set; } // This is PK
public int ReceivingId { get; set; } // This is FK
...
public virtual ReceivedGoods goods { get; set; }
}
I would like to get ReceivedGoods object and have properties automatically loaded as well but I am not able to figure out, how to set up this within EF.
I've tried something like this (from the ReceivedGoodsProperties side mapping):
this.HasRequired(p => p.goods)
.WithRequiredDependent(d => d.properties)
.Map(m => m.MapKey("ReceivingId"));
but I am ending up with following error:
ReceivingId: Name: Each property name in a type must be unique. Property
name 'ReceivingId' is already defined.
When commenting out ReceivingId in ReceivedGoodsProperties, upper exception is not thrown, ReceivedGoods is loaded correctly except the properties property.
Can somebody explain me, how to do one-to-one mapping in situation like this?
Could you try:
public class ReceivedGoods
{
...
public int ReceivingId { get; set; }
...
public virtual ReceivedGoodsProperties properties { get; set; }
}
public class ReceivedGoodsProperties
{
...
public int Id { get; set; } // This is PK
[ForeignKey( "goods " )]
public int ReceivingId { get; set; } // This is FK
...
[Required]
public virtual ReceivedGoods goods { get; set; }
}
BTW, in C# the standard guidelines is to PascalCase members, so Goods and Properties
Try defining the relationship this way:
this.HasRequired(p => p.goods)
.WithRequiredDependent(p => p.properties)
.HasForeignKey(p => p.ReceivingId);
If you follow the standard EF naming conventions, it can usually figure out these relationships on its own. You only really run in to trouble when your navigation property names don't correspond to the class name, or if you have multiple FKs to the same destination in the source table.
If you want the navigation properties to get filled out "automatically", use the Include extension method on the query, as in:context.Goods.Include(g=>g.properties). You don't have to declare them as virtual unless you want to make use of lazy loading.
You may need to come at this from the other entity:
this.HasRequired(p => p.properties)
.WithRequiredPrincipal(p => p.goods)
.HasForeignKey(p => p.ReceivingId);
I'm using Entity Framework 6.1.3, .Net Framework 4.5.1
Is it possible to create a 1-1 Entity Framework relationship between two entities based on multiple fields using Data Annotations?
In the example below, I want to be able to include Dog.Dogform when Dog is loaded. The two are related on OwnerId + DogTypeId. DogForm contains a unique index on OwnerId + DogTypeId, so there is always 1 or zero DogForms for every Dog.
public class Dog
{
[Key]
public int DogId { get; set; }
public virtual DogForm DogForm { get; set; }
public int OwnerId { get; set; }
public int DogTypeId { get; set; }
}
public class DogForm
{
[Key]
public int DogFormId { get; set; }
public int OwnerId { get; set; }
public int DogTypeId { get; set; }
}
The obvious answer here is to add "DogFormId" to the "Dog" table and create a foreign key relationship, but I'm dealing with a legacy database that for multiple reasons cannot be altered.
If this is not possible using Data Annotations, is it possible using Fluent Api?
I don't know of a way to do it with DataAnnotations, but it's pretty easy with the Fluent API. The below should work. I'm coding from memory, so it may need a tweak or two.
modelBuilder.Entity<Dog>().HasOptional(a => a.DogForm).WithRequired().HasForeignKey(a => new { a.OwnerId, a.DogTypeId });
If you add a navigation property to DogForm just change WithRequired() to WithRequired(a => a.Dog)
I am currently making a web app for MVC 3 using Entity Framework but I'm a beginner and I can't make the Code First mapping work properly and for some reason my Visual Studio doesn't have Database First and Model First functionality.
I have three model classes: Contacto, Proveedor and Usuario, each one of them corresponding to a table on an database existing database and I want to make those classes with Code First to map to this database. Contacto has a one-to-one relationship with Proveedor and Usuario. I declared the model classes like this:
public class Contacto
{
public int ID { get; set; }
public string Nombre { get; set; }
public string Telefono { get; set; }
public Proveedor ProveedorID { get; set; }
public Usuario UsuarioID { get; set; }
}
public class Proveedor
{
public short ID { get; set; }
public string NombreProveedor {get;set;}
}
public class Usuario
{
public short ID { get; set; }
public string NombreUsuario {get;set;}
}
The context class is the following:
public class Contexto : DbContext
{
public DbSet<Contacto> Contactos { get; set; }
public DbSet<Proveedor> Proveedores { get; set; }
public DbSet<Usuarios> Usuarios { get; set; }
}
I made a controller and view with CRUD methods but when the code gets to the EditorFor for the Proveedor attribute in Contacto I get a Invalid column name 'ProveedorID' and the same for UsuarioID. Changing the table names on the existing database doesn't fix this but sometimes makes the Invalid column name error refer to Contacto_ID instead of ProveedorID.
How do I make the reference to the Proveedor and Usuario model in Contacto work? And how override the automatic table mapping and specify the mapping manually? The name conventions don't work well in Spanish and don't detect properly that there is a relationship in a database.
When you don't tell EF anything about how entities and properties map to table and column names, it will make its own assumptions by following a number of conventions. One of them is to assume that a foreign key column is the name of the referred entity with _ID appended to it.
If you don't want EF to follow these default conventions, you have to add your own mappings. I'll show an example of how you can do this.
First, I'd remove the "ID" part from the reference properties, and add primitive foreign key properties to the Contacto class:
public class Contacto
{
public int ID { get; set; }
public string Nombre { get; set; }
public string Telefono { get; set; }
public short ProveedorID { get; set; }
public Proveedor Proveedor { get; set; }
public short UsuarioID { get; set; }
public Usuario Usuario { get; set; }
}
One way to tell EF about database names of entities and properties is fluent mapping. You can either do this in the OnModelCreating override of your context class, or in an EntityTypeConfiguration override:
public class ContactoMap : EntityTypeConfiguration<Contacto>
{
public ContactoMap()
{
ToTable("tblContacto");
Property(c => c.ProveedorID).HasColumnName("ProveedorId");
HasRequired(x => x.Proveedor).WithMany().HasForeignKey(c => c.ProveedorID);
Property(c => c.UsuarioID).HasColumnName("UsuarioId");
HasRequired(x => x.Usuario).WithMany().HasForeignKey(c => c.UsuarioID);
}
}
I just make up some names, since you don't mention which database names you want to have, but you get the idea.
The final step is to add this mapping to the model by overriding OnModelCreating in the context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ContactoMap());
}
By the way, if you have these properties like ProveedorID, EF will also infer these as foreign keys to the matching entity. Only when you don't include these primitive foreign key properties, EF will expect the column names with underscores in the database.