Entity Framework Relationships with Existing Data - c#

I have a project where I am taking an existing database and converting the stored procedures into an Entity Framework respository. I am running into quite a few issues setting up the Entity relationships. I am unable to alter the structure of the database so I have to find a solution within code.
Lets say I have a Clients Table and a Notes table. Clients has a one to many relationship with Notes.
In Clients, I have a field called Client_Id(the primary key) , In the Notes table I have a Note_Id and a Account_ID. The Clients.Client_Id maps to Notes.Account_Id.
Now, in tables that have the same key value I can just create a ICollection and Enity will create the relationship just fine. But since the names are different and there is no foreign keys to map how do I get this to work?
Thanks.

You should be able to configure these mappings using either Data Annotations or the Fluent API. Here's a sample of how you might do it using the annotations:
[Table("Clients")]
class Client
{
[Key]
public int Client_Id {get;set;}
public virtual ICollection<Note> Notes {get;set;}
}
[Table("Notes")]
class Note
{
[Key]
public int Note_Id {get;set;}
public int Account_Id {get;set;}
[ForeignKey("Account_Id")]
public virtual Client Client {get;set;}
}

Related

Entity Framework: how to add an association, based on an existing property

I'm using the database-first approach while setting my first steps in Entity Framework. In my SQL Server database I have two tables, Location and Area.
Both have an Id column and the Location table already has an AreadId property. I would like to use this property for creating a one-to-many association between both tables (many Location entries for one Area entry), so I have created the following in my EDMX diagram using the EDMX-designer:
In the automatically generated Location.cs file, it looks as follows:
public partial class Location
{
...
public int AreaId { get; set; }
...
public virtual Area Area { get; set; }
}
I would like to use the already existing property Location.AreaId as the foreign key. How can I do that, using EDMX-designer?
Please keep in mind that I can modify the EDMX diagram, but not the automatically generated Location.cs file.
Thanks in advance

Realtion mapping between two tables in different schema with code first

I am using code first approach for my .net core project. We are using multiple schemas in single database.
We are maintaining models in different class library projects like Inventory,Sales,Finance etc ..
Model mapping is like ( note : below they are different name spaces)
[Table(name: "Product", Schema = "Inventory")]
public class Product
{
public int ProductId {get;set;}
public string Name {get;set;}
}
[Table(name: "Order", Schema = "Sales")]
public class Order
{
public int OrderId{get;set;}
public int ProductId {get;set;}
public virtual Product Product {get;set;}
}
With in the schema i am able to add relation by using attribute. Now i want to add relation between these tables.
I have tried some tweaks but not working.
Any help is appreciated.
Update:
DBcontext's also different for each schema and they are placed in respective class library
You have conflicting approaches in your current architecture:
On one hand, you have gone for a micro-services approach where each service is dealing with its own bounded context (e.g. Inventory, Sales, etc.). This seems to be confirmed by your use of different database schemas, which can be viewed as logically different databases that happen to be deployed in a single physical database. This is fine, and allows for future scaling / segregation where you might move the inventory data into its own database, for example.
On the other hand, you are trying to treat the datastore as a monolithic artefact where you can build table relationships across the bounded context boundary established by your micro-service approach.
If you wish to maintain your micro-services approach, which is perfectly reasonable, then you have to accept that you cannot rely on database-enforced referential integrity for table relationships that span entities in different micro-services.
You'd need a layer above that can retrieve data from separate micro-services and put them together into entities (preferably DTO entities, not the EF Data Entities used for code-first) that the consumer is looking for.
This layer would first retrieve Orders from the 'Sales' service, and then enumerate your Orders and retrieve the relevant Products from the 'Inventory' service and then map those into DTO entities that include navigation properties between OrderDTO and ProductDTO.
Your Order data entity should not have a virtual navigation property to "Product" but instead just hold a unique id of the Product that the Order relates to (not enforced as a database relationship). Personally, I would go further and introduce a GUID Unique Identifier to the Product data class that can be used in the Order to uniquely identify the product. That way, if you ever do migrate your Inventory tables to a new database, you don't have to worry about managing the Database Identity Column during that migration as the reference 'outside' of the Inventory service to the Product table would be the GUID Unique Identifier.
You have a typo
public virtal Product Product {get;set;}
should be virtual
Also you need a navigation member in Product
[Table(name: "Product", Schema = "Inventory")]
public class Product
{
public int ProductId {get;set;}
public string Name {get;set;}
public virtual ICollection<Order> Orders { get; set; }
}
[Table(name: "Order", Schema = "Sales")]
public class Order
{
public int OrderId{get;set;}
public int ProductId {get;set;}
public virtual Product Product {get;set;}
}

Saving OData entities from api with id to database in entity framework

I have multiple projects that return the same OData entities through a API endpoint. Now i want to call all of the projects and store them in my calling projects database with entity framework.
To add them to the db the ID gets overwritten but i want to save the id that the entity has in the projects database as well. so i can still access them if need be and to check if the data isn't already in my database. Because of this i need to add another MainProjectID and projectID column to the entity.
I tried making a new class that has a reference to the entity i want to save but this used new id's for the entities. I also tried inheriting the class but this gave me key conflict issues, and generics don't work either in entity framework(i'm not saying they should). So i'm kinda at a loss right now.
I basically want to save the id as a non-key. Is there any way i can do this without writing entirely new classes and parsing them manually ?
Any help would be greatly appreciated.
We have multiple alternatives here:
In a distributed system, best way to cope with these kinds of ID clashes is to make IDs globally unique. If you can modify how IDs are generated, that would be my choice to go. You can use a UUID (or Microsoft implementation GUID) that will produce a universal unique identifier. Or if that seems like an overkill you can devise a simple mechanism that combines ID with projectID. However you should ensure that the method you will use will not produce any collisions (no two different id-projectId pair will map to same value).
This will ensure that same entity is used throughout your application and no overlaps occur if you try to put records from different sources into the same table. You only need to implement a mechanism to record which ID originated from which source. You can use a reference entity at aggregator for this purpose. You also need to disable auto increment nature of the ID column so that your global unique values are used in table.
You can use different entities for producing and aggregating applications. I don't know your application, but that seems like an OK approach to me since the aggregating application has a different idea about the entity. The aggregating application cares for which application produced the entity, that might make putting the source application identifier into the entry justifiable. Your entities will only differ in that and when you receive the OData object from API you'll need copy all other properties and put project identifier yourself.
You can use the previous solution, but you can use a derived class in order to not to repeat your object properties. This is a better design alternative. However with this method you'll have some problems with the primary key (as you've stated you had). Consider this example
public class Base {
public int ID { get; set; }
[Required]
[StringLength(50)]
[Display(Name = "Name")]
public string Name { get; set; }
}
public class Derived : Base {
[Key]
public int projectId {get; set; }
}
If you don't put [Key] to Derived then you'll have only ID as primary key. When you put [Key] to Derived then you'll have only projectId as primary key. You need to define a composite key and you can do this by removing the [Key] annotation from projectId and using the onModelCreating override of DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Derived>().HasKey(a => new { a.ID, a.projectId })
.Property(c => c.ID).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
modelBuilder.Entity<Derived>().Property(c => c.projectId).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.None);
}
You can mix these alternatives. You can drop the primary key on ID field, and then you can insert a new Entity that will model 1-M relationship between ID's and project ID's.

How do I add multiple tables using one model and one view?

I want to have a page where the user selects from a drop down list the category, then adds a small text about that category and uploads an image where the path of that image is saved in the database rather than the whole image. I have created a table "Categories" where the admin is authorized to fill it and the user only selects from the categories list.
Here is what I have done so far:
The create categories model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace DemoIdentity.Models
{
public class CategoriesAdmin
{
public int ID { get; set; }
[Required(AllowEmptyStrings = false)]
[Display(Name = "category name")]
public string categoryName { get; set; }
}
public class DefaultConnection:DbContext
{
public DbSet<CategoriesAdmin> categories { get; set; }
}
}
Now I want to have another table (Data) which includes (ID, Category (category name selected from table categories), News, Image_Path). This table is in the Default Connection database. The category name is the selected category name from a drop down list, and the image path is an upload image which saves the path rather than the whole image.
I am unsure of how to achieve this.
It appears that you are confusing components of ASP.NET MVC and Entity Framework.
As the Entity Framework site states:
Entity Framework (EF) is an object-relational mapper that enables .NET
developers to work with relational data using domain-specific objects.
It eliminates the need for most of the data-access code that
developers usually need to write.
And the MVC site states that:
The ASP.NET MVC is an open source web application framework that
implements the model–view–controller (MVC) pattern.
The two frameworks meet through your model classes. MVC uses the model class to define the data, logic and rules of the application. In Entity Framework, your model class is mapped to tables in your database where it handles the direct reads and writes for you.
By creating your CategoriesAdmin model class and exposing it as a property in your DbContext class as such:
public class DefaultConnection:DbContext
{
public DbSet<CategoriesAdmin> categories { get; set; }
}
Entity Framework will have mapped your model class to a database table called CategoriesAdmins. If this table does not yet exist in your database, it will automatically create it for you. This approach in Entity Framework is known as Code First to a new Database.
Now since you already have a table that stores the available categories (CategoriesAdmin), you will need to create a second model class (called Data for the sake your example) which contains properties for the other bits of information that you want to store.
public class Data
{
// gets or sets the ID of this Data record.
public int ID {get;set;}
public string ImagePath {get;set;}
// other properties
...
}
Now that you have two model classes, you need to create a relationship between the two. In a SQL database this is achieved by Foreign Keys. In Entity Framework, you can achieve the same by using Navigational Properties.
So we update the Data model class as such:
public class Data
{
// gets or sets the ID of this Data record.
public int ID {get;set;}
public string ImagePath {get;set;}
// gets or sets the ID of the related CategoriesAdmin record.
public int CategoriesAdminId {get;set;}
// gets or sets the related CategoriesAdmin record. Entity Framework will
// automatically populate this property with an object for the related
// CategoriesAdmin record.
[ForeignKey("CategoriesAdminId")]
public virtual CategoriesAdmin CategoriesAdmin {get;set;}
// other properties
...
}
The ForeignKeyAttribute on the CategoriesAdmin property is there to give Entity Framework a further hint of the foreign key column to load the navigational property from.
Finally to be able to use your new Data model class with Entity Framework, you need to add another property to your DbContext class so that you have a means of accessing your data:
public class DefaultConnection:DbContext
{
public DbSet<CategoriesAdmin> Categories { get; set; }
public DbSet<Data> Data { get; set; }
}
Now that you have created your model classes and wired them into Entity Framework, you will now be able to use them in MVC. If you load your Data model into your view (using DefaultConnection.Data), you will be able to access the related CategoriesAdmin record by accessing the CategoriesAdmin property on the Data object.
In short: two tables means you need two models. Both models can be loaded into the single view.
Footnote: Apologies if there are large gaps in my answer as there is a lot to explain that have already been explained in other places far better than what I can. The references I have linked should hopefully fill in the gaps.
Should you need more help, please see all of the tutorials on the ASP.NET MVC website on working with data. They're much better written than my concise attempt. I would recommend following them exactly and getting the examples to work before completing your own project so that you have a better understanding of how the two frameworks work and interact with each other.

Entity framework navigation properties naming convention

I have two tables named as Profile and ProfileHistory.
Each record in ProfileHistory has to belong to a profile in Profile table, so there is a foreign key relation between two tables. Besides, in ProfileHistory table, there is a column named as ManagerId which also relates to Profile table with foreign key relation.
Profile table structure
Id int primary key
....
....
ProfileHistory table structure
Id int primary key
ProfileId int foreign key to Profile table
ManagerId int foreign key to Profile table
....
My question is:
Since currently I only know this, I am creating my entity model from database.
Model and therefore entity classes are created with navigation properties in
ProfileHistory entity like following:
public virtual Profile Profile { get; set; }
public virtual Profile Profile1 { get; set; }
It is so confusing. Because it is not clear which navigation property for which relation.
Even it is worse if I have more relations between two tables. navigation property names are becoming Profile, Profile1, Profile2, etc.
I was expecting to have the name of the navigation properties related with its foreign key relations.
How can I make my navigation property names something that related to its foreign key relation, in my case "from Profile1 to ProfileManager" ?
Thank in advance for your kind helps.
Muharrem
You can always rename the properties in model diagram. The name can be found in Properties window when you click on a navigation property.
I haven't tested it, but you can map a property to a column using an attribute:
[Column(“BlogDescription", TypeName="ntext")]
public virtual Profile Profile { get; set; }
[Column("Profile1", TypeName="int")]
public virtual Profile ProfileManager { get; set; }
Change the type and the name of the column as it is in the database.
The way I usually solve this is to add properties through partial classes that better represent what I'm after. This way if I need to delete the entity from the diagram and re-add it, I don't lose any renamed columns from the model.
The downside to this is that you need to remember that you cannot use them in Queries because EF won't know how to translate it into a SQL query. But if you've already got your Profile object, it's a lot easier to access myProfile.Manager than myProfile.Profile1.
So, for example, if EF created this for you:
public partial class ProfileHistory
{
public virtual Profile Profile { get; set; }
public virtual Profile Profile1 { get; set; }
}
I would end up creating a partial class like this to re-map the columns:
public partial class ProfileHistory
{
public Profile Manager
{
get
{
return this.Profile1;
}
set
{
this.Profile1 = value;
}
}
}
I did face the same problem some time ago. Well, it is even bigger then just confusing names. If you have navigation properties to another table, like Profile, Profile1, Profile2, next you delete/edit the corresponding foreign keys you may end up having those mixed. And if you used EntitySQL to query data you'll end up having bugs because of incorrect data retrieved/wrong table join conditions...
What I did was changing the t4 template and modified the way properties are generated. When property code text is being written you have the information about association and foreign key related to it. Foreign key names are unique in database and I named those with following pattern
FK_[Table]_[Meaning]
...
FK_ProfileHistory_InitialProfile
FK_ProfileHistory_UpdatedProfile
Next, having this information, I named the properties with the [Meaning] part of the foreign key name.

Categories

Resources