I have (can`t change) EF DataBase first project without navigation property in models.
I want extend autogenerated models and add navigation property
Generated model
//generated.cs
public partial class company
{
public int id { get; set; }
public string name { get; set; }
}
public partial class user
{
public int id { get; set; }
public int company_id { get; set; }
}
I want add navigation property from code
//model_extension.cs
public partial class user
{
public company Company { get; set; }
}
I have exception "The specified type member 'Company' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."
I work with CodeFirst before.
I understand, I must link user.company_id to Company
But not understand how make this with code (not designer)
In Database First Approach, You are generating your POCO objects from database schema via Entity Framework Designer/ADO.NET Entity Data Model so it is not flexible as Code-First, you need to go on database, and change the schema yourself and update your .edmx file. while adding properties to these Models are possible in c# side, but they are not going to be added to your database schema,
I suggest your reverse your database schema and go as Code-First Approach, This nuget package can do this for you.
After Reversing It's all about Code-First then, creating your own DbContext and OnModelCreating and let the Migration handle the rest. Then you can use Eager Loading of EF to load your data,
Related
Background Information
I am currently working with EF Core using a database first implementation.
Current tables
Fizz
{
[Id] INT
[Category] varchar
[Value] varchar
}
Buzz
{
[Id] UniqueIdentifier
[TypeId1] INT
[TypeId2] INT
CONSTRAINT [FK_Buzz_Fizz_1] FOREIGN KEY ([TypeId1] REFERENCES [Fizz][Id])
CONSTRAINT [FK_Buzz_Fizz_2] FOREIGN KEY ([TypeId2] REFERENCES [Fizz][Id])
}
Fizz currently acts a lookup table. Doing this allows for a single data repository to be used to find different values by category.
Buzz is a table that has two different type values to be stored e.g. TypeId1 could be brand which would exist in Fizz as (id, Brands, Nestle) and TypeId2 could be a flavor which would exist in Fizz as (id, Flavors, Grape).
The Issue
I scaffold the db to create the Data Models.
When running the application the following occurrs:
InvalidOperationException: Unable to determine the relationship represented by navigation property 'Buzz.TypeId1' of type 'Fizz'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
One solution that has occurred to me is to break this lookup table (Fizz) into multiple tables that way the references could be resolved by not having duplicate types used for Foreign Keys.
This would require re-work of the logic for the current data repository to either access multiple tables or be split into multiple data repos.
Another solution would be to modify the DBContext that is generated and use DataAnnotations on the DataModel. I would like to avoid doing this as the Context and Models will be regenerated in the future and these changes will be overwritten.
Is there a way to have a datamodel generated from a table that has multiple Foreign Keys to a single table without having to modify the generated code?
For posterity:
With the database approach a scaffold of the db is done to create the context and data models.
The data models generated (using the example tables above) look something like this -
public partial class Buzz
{
public Buzz()
{ }
public Guid Id { get; set; }
public int TypeId1 { get; set; }
public int TypeId2 { get; set; }
public Fizz TypeId1Fizz { get; set; }
public Fizz TypeId2Fizz { get; set; }
}
public partial class Fizz
{
public Fizz()
{ }
public int Id { get; set; }
public string Category { get; set; }
public string Value { get; set; }
public ICollection<Buzz> TypeId1Fizz { get; set; }
public ICollection<Buzz> TypeId2Fizz { get; set; }
}
The issue is that the relationship in Buzz could not be resolved.
The solution
When using scaffold on the database all models are generated as partials to a specified folder. I created a partial for the Buzz class in another directory that lives inside of the directory created by the scaffold (be sure that the namespaces match VS likes to add the directory name to the namespace and the partials won't be matched).
public partial class Buzz
{
[NotMapped]
public Fizz TypeId1Fizz { get; set; }
[NotMapped]
public Fizz TypeId2Fizz { get; set; }
}
but Leustherin then you lose the ability to utilize .Include for Fizz! EntityFramework won't create an SQL join statement for you so you will have to make an extra trip to the DB to obtain your look up value!
To get around this, override the Get or GetAll function of your data repository and create your own join statement.
Why I chose this solution
Maintainability.
Anytime the DataModels are regenerated instead of getting a runtime error there is now a compile error reminding the dev to delete the extra properties from the generated data model.
There is no other modification of automatically generated files.
There are no major schema changes done to accommodate the change.
I will do my best to keep this updated.
Trying to iron out some issues with a an MVC project using models derived from existing database tables the developer built, but none of those tables has its relationships set up (they all have primary keys, just no relationships). As such the project uses ViewModels to get some things done when more than one table is needed.
I'm attempting to get around this by adding the necessary items to relate two of the tables.
Table One's POCO:
namespace Project.Models
{
using System;
using System.ComponentModel.DataAnnotations;
public partial class Table_One
{
[ScaffoldColumn(false)]
public short ID { get; set; }
[Display(Name="Name")]
public string NAME { get; set; }
[Display(Name = "Owner")]
public string OWNER { get; set; }
[Display(Name = "Property")]
public Nullable<decimal> PROPERTY { get; set; }
public virtual Table_Two Table_Two { get; set; }
}
}
Table Two's POCO:
namespace Project.Models
{
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public partial class Table_Two
{
public Table_Two()
{
this.Table_One = new HashSet<Table_One>();
}
[ScaffoldColumn(false)]
public short ID { get; set; }
[Display(Name="Property")]
[MaxLength(20)]
public string Property { get; set; }
public ICollection<Table_One> Table_One { get; set; }
}
}
Were these tables set up with their relationships, they'd be joined on the Property values (I've sanitized the table names and properties). As far as I can tell I've set things up to mirror the way another project I've been working on, which has tables that are related, has been set up to include the relationships, but when I run this LINQ query:
var model = context.Table_One.Include(t => t.Table_Two);
I get the following error message:
"A specified Include path is not valid. The EntityType 'X.Table_One'
does not declare a navigation property with the name 'Table_Two'."
Originally these were being joined via a LINQ query using query syntax to select each of the table's properties into the ViewModel's properties.
I've tried removing the include, but that doesn't gel with other code in the controller. I've tried changing the ICollection to an IList to no avail. I've searched other answers here but none of them seem to solve the problem I'm having.
As far as I know the developer who started the project built the POCOs using a code generation tool that was run against the EDMX in the project. The only other thing I can think of at this point would be to have the developer add the relationships, then update the POCOs to pull in the updated tables via the EDMX.
I should also specify that the ID in Table_Two would be a foreign key in the PROPERTY column of Table_One.
You should use Include with properties which are collections of related entities
var model = context.Table_Two.Include(t => t.Table_One);
Include tries to fetch collection of related entities by using joins on sql query.
If you want to load a related entity you can use lazy loading or load it using the code below
context.Entry(table_one).Reference(x => x.Table_Two).Load();
To rely on Entity Framework's related entities loading, you need to set the entities relations.
Since you said "but none of those tables has its relationships set up", you won't be able to use nor lazy neither eager loading, you have to fetch the other entities by hand.
I'm using EF5 to produce a model from an existing DB structure. I map Insert/Update/Delete Stored Procedures to the entities. This is working fine.
What I would like to do next is pass a UserId to these SPs as a parameter but not have the UserId as a column within the underlying table (the SPs will utilize this parameter). I have lots of entities. Is it possible to somehow add a property that will always be added back in even after updating the model from the DB?
Many Thanks
If you are using EDMX to generate the Entity Framework object model, your classes are partial and you can add properties to the partial classes of your entities which will survive database regeneration.
If you have a ParticularEntity table in the DB and referenced in the EDMX, you may add a partial class file ParticularEntity.Augments.cs (the name is for your reference, and you can have multiples as normal with partial classes) to your project and within it
public partial class ParticularEntity
{
public string UserId { get; set; }
public void DoSomething(string userId)
{
someFunctionThatYouWantToNotBeAnExtension();
}
}
Alternatively, you could write a set of extension methods which your maps utilize. I don't think that's as clean as extending the EF classes with partials, though.
Entity created by EF are partial class so you can extend that class with your custom properties
YourEntity.cs //created by EF
public partial class YourEntity
{
public string Name { get; set; }
...
}
YourEntityExtended.cs // created by you
public partial class YourEntity
{
public int Id { get; set; }
}
I had started a project with Model-First, with one existing base, now I need to change to code-first to change some specifics things in FK´s.
So How I keep the classes and change to code-first? It´s even possible?
Assuming you have already generated your database from your model, you can use the "Reverse Engineer Code First" feature of Entity Framework Power Tools. This will generate both your POCO model classes and Fluent API mapping classes for you.
I did this myself fairly recently. The expressive powers of Model-First and Code-First are identical. If you write your Code-First classes such that the property names and types match what you had in your Model-First types, the transition should be very easy.
For example, if you have a Model-First model Item with int ID key, string Name, and int ListID foreign key, with List List navigation property, you can make the Code-First class as follows.
class Item
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public int ListID { get; set; }
[ForeignKey("ListID")]
public virtual List List { get; set; }
}
All of your old code that uses Item should likely remain working.
I have two tables in a database. One is for a member and one is for a client. The client table has two columns for who created the row, and who has modified the row. Foreign keys were set up from each column to map back to the member table. All of this makes sense until
one runs Entity Framework against the database and I get the following code generated for me.
public Member()
{
public virtual ICollection<Client> Clients { get; set; }
public virtual ICollection<Client> Clients1 { get; set; }
}
public Client()
{
public virtual Member MemberForCreated { get; set; }
public virtual Member MemberForModified { get; set; }
}
My question is why would Entity Framework think to make a backing collection in the member table for each foreign key relationship to the client table? Do I really need this relationship or is this something that I can remove? Any information would be useful.
As a side note: These collections and relationships are found in the .edmx file under the navigation properties collection of the entities.
EF relationships are bidirectional by default. You can remove either direction if you don't need it.
You can also rename them. You might, e.g., want to call them Member.ClientsCreated and Member.ClientsModified.
Julie Lerman has a video examining unidirectional relationships.