I have an existing entity User. Now I am trying to create a new entity Contact with 0-1 relation with User.
class Contact
{
public int Id {get; set;}
public string Name {get; set;}
public int? UserId {get; set;}
public virtual User TheUser{get; set;}
}
All suggestion involve about something like this:
modelBuilder.Entity<User>()
.HasOptional(t => t.TheUser)
.WithOptionalDependent(u => u.TheConatct);
But this means we have to add TheConatct property to the existed User entity. Actually I do not want to make any modification to the existed entity. All what I need to define a foreign key form Contact to User entity and can access the User entity from Contact via TheUser property.
Update:
If I use ForeignKey attributes to annotate the property:
class Contact
{
public int Id {get; set;}
public string Name {get; set;}
public int? UserId {get; set;}
[ForeignKey("UserId")]
public virtual User TheUser{get; set;}
}
Then, the result of ObjectContext.CreateDatabase() will also include create statements for already existed tables (depending on the entities that have relations with User).
Of course we are talking about "Entity Framework 6 Code First", Also, I have the same problem with 1-1 relation.
The idea, I cannot alter the existing entity User to add additional property for the new entity Contact
I wonder if there is a way to overcome this issue
Just use another overload:
modelBuilder.Entity<User>()
.HasOptional(t => t.TheUser)
.WithOptionalDependent();
I don't know which version of Entity Framework you are using and I assume you are using Code First, but you may have to consider using a one to many relationship instead of a 0-1.
I don't believe there is support for 0-1 in the way you want it, but you can simulate by having a one to many (even though your "many" will only ever by 1)
Related
I have two model classes (Tickets and Activities), where Activities is more like a look-up table, and is not suppose to hold any navigational properties or FK's of other entities.
A record in Tickets is supposed to have a single Activity, but in the whole table of Tickets, there will be many of the same Activities. Activities needs to be a table, and not (for example) an enum, because of the possibility of future updates and amendments.
Although this seems trivial enough, I keep encountering errors like Identity is Set to off.
My models:
public class Tickets
{
public int ID {get; set;}
// fk
public int ActivityID {get; set;
// nav property
public Activity Activity {get; set;}
// other properties.
}
public class Activity
{
public int ID {get; set;}
public int RankOrder {get; set;}
//other properties
}
I have specified a domainmapping for the Tickets model:
builder.HasOne(t => t.Activity)
.WithMany()
.HasForeignKey(t => t.ActivityID);
based on this SO-post and blogpost: here and here but I don't get it to work, my most recent error message is:
SqlException: Cannot insert explicit value for identity column in table 'Activity' when IDENTITY_INSERT is set to OFF.
Also, with this mapping it seems that EF created a Ticket column in the Activity table, something that I don't want.
Try this
builder.Entity<Ticket>()
.HasOne(t => t.Activity)
.WithMany(a => a.Ticket)
.HasForeignKey(t => t.ActivityID);
I am trying to create a DbQuery of ExtendedStudent, from SQL View which was constructed form 2 diffrent tables (see code SQL below).
I have looked at the following posts:
Entity Framework Core Query Types And EF Core 2.1 Query Types
Both have used a model with a navigation propery in it, and then succeeded to fetch it from the Fluent Fluent API.
But When i tried to do so too, i got exception such as "Invalid column name 'PrefixId1'
The models I use are:
public class ExtendedStudent {
public int IdNumber {get; set;}
public string FirstName {get; set;}
public string LastName {get; set;}
public virtual Prefix Prefix {get; set;}
public int Score {get; set;}
}
public class Prefix {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id {get ;set;}
[required]
public string Name {get; set;}
}
The applicationDbContext.cs file is:
public class ApplciationDbContext : DbContext{
DbSet<Prefix> Prefixes {get; set;}
DbQuery<ExtendedStudent> ExtendedStudents {get ;set;}
...
protected override void OnModelCreating(ModelBuilder builder) {
builder.Query<ExtendedStudent>.ToView("ExtendedStudent");
builder.Query<ExtendedStudent>.HasOne<Prefix>().WithMany();
}
}
At last, I tried to fetch the data like this.
var students = applciationDbContext.ExtendedStudents.Include(v => v.Prefix).ToList();
I have created the ExtendedStudents view in SQL like this:
CREATE VIEW [Organization].[ExtendedStudent] AS
SELECT [TableA].[Student].[FirstName]
,[TableA].[Student].[LastName]
,[TableA].[Student].[PrefixId]
,[TableA].[Student].[IdNumber]
,[Evaluation].[Student].[Score]
FROM [TableA].[Student] AS [Students]
INNER JOIN [Evaluation].[Student] ON [Evaluation].[Student].StudentId = [TableA].[Student].[IdNumber]
I have tried to add a PrefixId property to ExtendedStudent, or add foreign key, But nothing have worked.
I got an error saying
"An exception of type 'System.Data.SqlClient.SqlException' occured in Microsoft.EntityFrameworkCore.dll but was not handled in user code: 'Invalid column name 'PrefixId1'.'
Here
builder.Query<ExtendedStudent>.HasOne<Prefix>().WithMany();
with .HasOne<Prefix>() you are telling EF Core to create many to one relationship without navigation property at each end.
But the navigation property ExtendedStudent.Prefix already implies relationship, hence EF Core assumes a second relationship with default FK property and column name PrefixId1 (because PrefixId is already used by the "other" relationship implied from the navigation property).
To fix that, pass the navigation property to the relationship configuration:
builder.Query<ExtendedStudent>.HasOne(e => e.Prefix).WithMany();
I have an entity that consists only of foreign keys of other Entities.
My simplified class looks like this:
DeliverNote
Adress add1 {get; set;}
Adress add2 {get; set;}
I can load adresses by themselves just fine, but I can't load a DeliveryNote, because EF doesn't load the related data by default, I think.
So I saw solutions, mainly with context.notes.Include(dn => dn.Adresses), but I just can't figure out how I tell the note or the adress class how they're related to each other. Basically when I type "dn." nothing shows up.
The simplest, probably working, solution I saw was from microsoft. In the github from this page https://learn.microsoft.com/de-de/ef/core/querying/related-data you can see the Blog and the Post classes. To me the Post class looks flawed though, why would a Post have to know about the Blog it is in? This will mess up the database too in code first solutions. What if the same post is gonna be posted in several blogs?
Most solutions also seem to be lists of some kind, I don't have a list, just simple single objects. 1-1 relationship, I think.
So you have a database with a table of Addresses and a table of DeliveryNotes. Every DeliveryNote has two foreign keys to the Addresses: one From and one To (you call it addr1 and addr2)
If you follow the entity framework code first conventions, you'll have something like this:
class Address
{
public int Id {get; set;}
... // other properties
// every Address has sent zero or more delivery Notes (one-to-many)
public virtual ICollection<DeliveryNote> SentNotes {get; set};
// every Address has received zero or more delivery Notes (one-to-many)
public virtual ICollection<DeliveryNote> ReceivedNotes {get; set};
}
class DeliveryNote
{
public int Id {get; set;}
... // other properties
// every DeliveryNote comes from an Address, using foreign key
public int FromId {get; set;}
public virtual Address FromAddress {get; set;}
// every DeliverNote is sent to an Address, using foreign key:
public int ToId {get; set;}
public virtual Address ToAddress {get; set;}
}
In entity framework the columns of the tables are represented by non-virtual properties. The virtual properties represent the relations between the tables.
Note that the ICollection and FromAddress / ToAddress are virtual and thus not columns into your columns. If desired you can leave them out of your classes. However, if you have these virtual properties, you don't have to do the (Group)Joins yourself.
I can load adresses by themselves just fine, but I can't load a DeliveryNote, because EF doesn't load the related data by default ... I
From this it is not easy to detect what kind of queries you want.
One of the slower parts of database queries is the transport of the selected data from your DBMS to your local process. Hence it is wise to minimize the data being transported.
If you use Include, then the complete object is transported, inclusive the foreign keys and all properties you don't need. If you have a database with Schools and Students, then every Student will have a foreign key to the School he attends. If you ask for a 'School with his 1000 Students' of school with Id 4, using Include, you don't want to transport the foreign key SchoolId a 1000 times, because you already know it will have value 4
In entity framework only use Include if you want to change / update the fetched item, otherwise use Select
Given a bunch of DeliveryNotes, give me some AddressDetails of it:
IQueryable<DeliveryNote> deliveryNotes = dbContext.DeliveryNotes
.Where (deliveryNote => ...) // probably something with Id, or Date, or subject
.Select(deliveryNote => new
{
// select only the delivery note properties you actually plan to use
Subject = deliveryNote.Subject,
DeliveryDate = deliveryNote.DeliveryDate,
...
From = new
{
// select only the From properties you plan to use
Id = deliveryNote.FromAddress.Id,
Name = deliveryNote.FromAddress.Name,
Address = deliveryNote.FromAddress.Address,
...
}
To = new
{
// again: only properties you'll use
Name = deliveryNote.ToAddress.Name,
...
},
});
Entity framework knows the one-to-many relationship and will perform the proper join for you.
Given a bunch of Addresses give me some of the DeliveryNotes they received
var query = dbContext.Addresses
.Where(address => address.City == "New York" && ...)
.Select(address => new
{
// only properties you plan to use
Id = address.Id,
Name = address.Name,
ReceivedNotes = address.ReceivedNotes
.Where(note => note.DeliveryDate.Year == 2018)
.Select(note => new
{
// only properties you plan to use:
Title = note.Title,
...
// no need for this, you know it equals Id
// AddressId = note.FromId,
}),
});
Entity framework knows the one-to-many relationship and will do the proper groupjoin for you.
If you have a one-to-many relationship and you want the "item with its many sub-items", start on the one-side and use the virtual ICollection. If you want the sub-item with the item that it belongs to, start with the many-side and use the virtual property to the one-side
If you define your model as:
public class DeliverNote {
public int Id { get; set; }
public Adress addr1 { get; set; }
public Adress addr2 { get; set; }
}
public class Adress {
public int Id { get; set; }
}
You can then call:
context.notes.Include(dn => dn.addr1).Include(dn => dn.addr2);
Which will include the related data.
Your model doesn't define foreign keys for addr1 or addr2 so EF Core will create shadow properties for you, i.e. columns that exist in the table but not as properties in the c# model.
I am creating a property viewing app with four users: Office Manager, Property Advisor, Seller and Buyer. I would prefer to have one login for all but I don't know where I should start.
I need to have their Id's as I am using them for different functions in the application. Example a sellerId would be linked to a property. A buyerId, and PropertyAdvisorId would be linked to an appointment. I was wondering what the best approach for this would be?
Did you mean you really have four users, or four types of users? I assume the latter.
Inherited Users
If your types have a lot in common, like Name, Address, etc, it would be best to have a base type User, and several derived types: OfficeManager, PropertyAdvisor, etc.
Every User has zero or more Rights, every Right is acknowledged to zero or more Users: a simple many-to-many relationship.
Databases don't handle the concept of inheritance very well, you'll have to use a work-around to implement it. Entity framework knows several strategies to implement inheritance. Several of them are described here
In your case the Table-Per-Type would be the best: You'll have one Users table, and separate tables for the derived classes: a Sellers table, a Buyers table etc. Each of these tables will have the foreign key to the User table.
abstract class User
{
public int Id {get; set;}
// every User has zero or more rights (many-to-many)
public virtual ICollection<Right> Rights {get; set;}
... // other properties
}
class Seller : User
{
// inherit primary key Id from base class
... // seller properties
}
class Buyer : User
{
// inherit primary key Id from base class
... // buyer properties
}
class Rights
{
public int Id {get; set;}
// every right is acknowledged to zero or more Users (many-to-many)
public virtual ICollection<User> Users {get; set;}
... // properties that handle the rights.
}
You'll need to tell Entity Framework that you want separate tables for Users / Buyers / Sellers. This can be done using Attributes. I prefer using fluent API:
public MyDbContext : DbContext
{
// The tables:
public DbSet<Right> Rights {get; set;}
public DbSet<User> Users {get; set;
public DbSet<Seller> Sellers {get; set;}
public DbSet<Buyer> Buyers {get; set;}
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Buyers and Sellers are in separate tables:
modelBuilder.Entity<Buyer>().ToTable("Buyers");
modelBuilder.Entity<Seller>().ToTable("Sellers");
// if you want you could name the User and Right tables
// but that is not needed. Entity Framework already knows
// they should be in separate tables
modelBuilder.Entity<User>().ToTable("Users");
}
}
This will lead to a Users table, a Rights table, a junction table for the many-to-many relation between Users and Rights, and one separate table per user derived class, each with a foreign key to the Users table.
Did you notice that I made the User class abstract? This is to prevent users of the DbContext to Add a User. We don't know Users as object, we only know Buyers and Sellers (etc)
The nice thing about Table Per Type is that if you want to query items that all Users have, like a Name / Address, only one table is queried, no joins are needed, even if some of these Users are Buyers and some are Sellers. Also, if you only query Buyer properties, only the Buyer table is accessed.
The disadvantage is that if you want to query Buyer properties together with its User properties, a Join between the Users and the Buyer table is needed.
Whether Table-Per-Type is the best for you depends on the kind of queries you'll do most. Read all three described methods
Composition method
Another method would be not to use inheritance, but composition. This way your DbSet classes will better describe your tables. The disadvantage is that it seems a bit strange for users of your DbContext: Buyers dont't HAVE Users, they ARE Users, aren't they?
Instead of saying that an Sellers and Buyers ARE special types of Users (inheritance) , you could say that they HAVE UserInformation (composition). This is a one-to-one relation. Every UserInformation has zero or more Rights (one-to-many).
Composition will lead to the same tables as table-per-type. The only difference is that your classes represent your tables better, at the cost of that your classes represent your gut-feeling about Sellers and Buyers being Users less.
class UserInformation
{
public int Id {get; set;}
public string FirstName {get; set;}
public string MiddleName {get; set;}
...
// every UserInformation has zero or more rights: (many-to-many)
public virtual ICollection<Right> Rights {get; set;}
}
class Buyer
{
public int Id {get; set;}
// Every Buyer has some UserInformation using foreign key (one-to-one)
public int UserInformationId {get; set;}
public virtual UserInformation UserInformation {get; set;}
...
}
class Seller
{
public int Id {get; set;}
// Every Seller has some UserInformation using foreign key (one-to-one)
public int UserInformationId {get; set;}
public virtual UserInformation UserInformation {get; set;}
...
}
This will lead to a UserInformations table, a Rights table, a junction table for the many-to-many relation between UserInformations and Rights, and one separate table per user derived class, each with a foreign key to the Users table. Exactly the same tables.
The choice is yours: use inheritance if you want to hide the internal database structure to the users of your DbContext, use composition if you want to let your database design seep through to the DbContext users.
I am struggling with Entity framework. The thing I want to acheive is to have an entity with only Id which will define a foreign key without actual reference to the related entity. How can it be achieved?
Class.cs:
public class Class {
Guid Id {get; set} // this is my primary key
Guid ProfessorId {get; set; } // this has to be id of professor which is a foreign key
}
Professor.cs
public class Class {
Guid Id {get; set} // this is a primaty key of professor and it should constraint ProfessorId
}
I'm using fluent api. I cannot add any virtual properties to above classes (basically i cannot modify them), so how the mapping should be configured?
I understand that you cannot modify entities but you need to add at least one navigation property. It is necessary for Entity Framework in order that it understand the relationship.
In your code ProfessorId is only a scalar property.
The only other way is to execute sql command directly from your context
dbContext.Database.ExecuteSqlCommand("...");