Fluent Api Column order sytax - many-to-many

I'm trying to understand how to put this many to many annotation into fluent api. I just don't know the syntax to represent the column order.
public class UserNotification
{
[key]
[Column(Order = 1)]
public string UserId { get; set;}
[key]
[Column(Order = 2)]
public int NotificationId {get; set;}
public ApplicationUser User{get; set;}
public Notification Notification {get; set;}
}
I know fluent Api will look like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<UserNotification>()
.HasKey(n => new {n.UserId, n.NotificationId});
// What about the Column Order?
}

You can read the Key and Column data annotations as follows:
UserNotification has a key consisting of UserId and NotificationId columns, with UserId being first and NotificationId being second.
i.e. the column order attribute is used only to determine which column is first, second etc. in the context of the composite primary key.
Fluent API does not need that because you describe both the key columns and their order inside the HasKey expression:
modelBuilder.Entity<UserNotification>()
.HasKey(n => new { n.UserId, n.NotificationId });
// ^ ^
// first second
In other words, you did it correctly, no further action is needed.

Related

How to create a dependency graph using composite keys in EF Core

Trying to store a composite key table which is keyed for both fields to the table it defines dependencies for.
Example case
Import files: 1..10
Dependencies 1: 2,3; 2: 4,5; 4:10
Intent is to use this key-only table for code to do code first strongly typed definitions while also being light weight, and it seemed like the most straight forward way to do it before running into problems.
Current code:
public class ImportFileDependency
{
[Key]
[ForeignKey("ImportFile")]
public int ImportFileId { get; set; }
[ForeignKey("Id")]
public ImportFile ImportFile {get; set;}
[Key]
[ForeignKey("ImportFile")]
public int ImportFileDependencyId { get; set; }
[ForeignKey("Id")]
public ICollection<ImportFile> ImportFileDependencies { get; set; }
}
public class ImportFile
{
[Key]
public int Id {get; set;}
public string Name { get; set; }
public string WorkbookTab { get; set; }
public string File { get; set; }
public ICollection<ImportFileDependency> Dependencies { get; set; }
}
...
modelBuilder
.Entity<ImportFileDependency>(e =>{
e.HasKey(ifd => new { ifd.ImportFileId, ifd.ImportFileDependencyId });
e.HasOne(ifd => ifd.ImportFile)
.WithMany(i => i.Dependencies);
});
modelBuilder
.Entity<ImportFile>()
.HasMany(i => i.Dependencies)
.WithOne()
.HasForeignKey(z => z.ImportFileId);
...
After multiple revisions of following the responses of the add-migration exception response, currently on:
There are multiple properties pointing to navigation 'ImportFile' in entity type 'ImportFileDependency'. To define composite foreign key using data annotations, use ForeignKeyAttribute on navigation.
which did not update from the most recent iteration.
I seem to have recursed into a deadend so looking for guidance
Given the time you've asked it, you probably found the answer yourself or gave up on it, but if someone else struggles with this error, this solved my issue: Entity Framework Code First - two Foreign Keys from same table
You have to define the relationship using fluent API.

One-to-Many relations in RESTful api using Web Api 2

I have a question about setting up Web Api 2 so that if there is a relationship between two entities, at least querying one of those includes the other entities in the result. It's hard to explain but very easy concept if you look at the example below:
So, Imagine here is what we have in the Entity Framework:
public class student {
public int Id {get; set;}
public string Name {get; set;}
public int School_Id {get;set;}
public virtual School School {get; set;}
}
And:
public class school {
public int Id {get; set;}
public string Name {get; set;}
public IEnumerable<Student> Students {get; set;}
}
So obviously this is a very simple example. It's clear that these two classes can cause a circular reference, is there an easy way for me to generate json output that from one side, includes the related property and from the other side it doesn't? (to prevent the circular reference), to make it clear, when I query schools, I want to get this:
[{Id:1, Name: "School A", Students: [{Id:1, Name:"Mike"}, {Id:2, Name: "Sheila"}]} ,
{Id:2, Name: "School B", Students: [{Id:3, Name:"Joe"}, {Id:4, Name: "Sarah"}]}]
And when I query students, I only get this (see there is no school):
[{Id:1, Name:"Mike", School_Id:1}, {Id:2, Name:"Sheila", School_Id:1}, {Id:3, Name:"Joe", School_Id:2}, {Id:4, Name:"Sarah", School_Id:2}]
There are a few ways to handle this situation, and the method you choose depends on a few factors. I'll list the common ways this is normally dealt with, and you can evaluate each to decide which makes sense for both your client and server configuration.
Use a View Model or anonymous projection. This method involves creating a unique class which has only the properties you wish to send to the client.
public class StudentVm {
public int Id {get; set;}
public string Name {get; set;}
public string SchoolName {get;set;}
}
Use the [JsonIgnore] attribute on properties you do not want to have JSON serialize. If you prefer the Opt-In approach, use [DataMember] on properties you wish to include in serialization.
public class student {
public int Id {get; set;}
public string Name {get; set;}
public int School_Id {get;set;}
[JsonIgnore]
public virtual School School {get; set;} //omitted
}
public class student {
[DataMember]
public int Id {get; set;}
[DataMember]
public string Name {get; set;}
[DataMember]
public int School_Id {get;set;}
public virtual School School {get; set;} //omitted by default
}
Use the initializer for the JSON Formatter to preserve references. A unique $id field will be added to each object, and any object which may cause a circular reference will be replaced with a $ref pointing to that object's $id value.
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.All;
[{"$id":"1", "Id":"1", "Name":"Mike", "School_Id":"1",
{"$id":"2", "Id":"1", "Name": "School A", "Students": [{"$ref":"1"}]
}]
Note that using a combination of these methods together is acceptable; You could, for example, use a View Model and use References Handling together.
References from http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization
Could you explicitly create objects in the form you want?
Schools.Select(s => new
{
s.Id,
s.Name,
Students = s.Students.Select(st => new {st.Id, st.Name})
})
Students.Select(st => new { st.Id, st.Name, st.School_Id })

Entity Framework 4.1 Code first mapping to tables that have their primary key as the foreign key column

I have an existing database that I'm using Entity Framework Code First to map. The naming convention for columns is odd, so I decided I'd map entity properties manually, and up until now this has been fine.
The schema for the database is fairly strange to me and is definitely not how I would've done it. Unfortunately, I'm stuck with it for the time being.
Basically there is a single primary key (AccountNumber) shared by a number of tables creating a bunch of one-to-one relationships. However, the primary key is also the foreign key column. Here is what my entities look like (with a whole bunch of properties removed for simplicity). I've only included two entities to make it easy.:
public class Customer
{
public int AccountNumber { get; set; }
public String PhoneNumber { get; set; }
...
public virtual Address Address { get; set; }
}
public class Address
{
public int AccountNumber { get; set; }
public String Name { get; set; }
public String Address1 { get; set; }
public String City { get; set; }
...
public virtual Customer Customer { get; set; }
}
The two entities share the same primary key. I've created configuration classes to do the mapping like this:
public class CustomerConfiguration : EntityTypeConfiguration<Customer>
{
public CustomerConfiguration()
: base()
{
HasKey(p => p.AccountNumber);
Property(p => p.AccountNumber).
HasColumnName("cm_l_acct").
IsRequired();
Property(p => p.PhoneNumber).
HasColumnName("cm_s_phonenumber");
HasRequired(x => x.Address).
WithRequiredPrincipal(x => x.Customer).
Map(x => x.MapKey("am_l_acct"));
}
}
public class AddressConfiguration : EntityTypeConfiguration<Address>
{
public AddressConfiguration()
: base()
{
HasKey(p => p.AccountNumber);
Property(p => p.AccountNumber).
HasColumnName("am_l_acct").
IsRequired();
...
}
}
The foreign key mapping is only done on one side. This appears like it would work if not for the fact that the foreign key column is also the primary key of the table. When I try to run a query, I get the error:
(256,6): error 0019: Each property name in a type must be unique. Property name 'am_l_acct' was already defined.
Unfortunately, I can't pull the mapping for the AccountNumber property off of the Address entity because it is the primary key.
Is there a way I can accomplish this mapping, or is it impossible?
Removet this Map(x => x.MapKey("am_l_acct")) from your Customer mapping. This mapping is only used if you map want to define FK column in database and you don't have FK property in the class but you have it - it is primary key in the Address entity. If you try to map FK that way EF thinks that you are trying to create to columns with the same name.

EF 4.1 Code First Mapping two columns in one table to list

I'm having an issue figuring out how to make this work for EF 4.1 Code First. I've looked around and found a similar problem, but I couldn't get it to work for me and it sounds like it didn't get answered for this person either.
Here is a simplified version of the two objects in question.
public class Team
{
public int TeamId {get; set;}
public virtual IList<Game> Games {get; set;}
}
public class Game
{
public int GameId {get; set; }
public int AwayTeamId {get; set;}
public int HomeTeamId {get; set;}
public virtual Team HomeTeam { get; set; }
public virtual Team AwayTeam { get; set; }
}
And here is my code for registering the FKs
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Game>()
.HasRequired(a => a.HomeTeam)
.WithMany()
.HasForeignKey(u => u.HomeTeamId).WillCascadeOnDelete(false);
modelBuilder.Entity<Game>()
.HasRequired(a => a.AwayTeam)
.WithMany()
.HasForeignKey(u => u.AwayTeamId).WillCascadeOnDelete(false);
}
I want to bring back all games (home or away) that a team is in. Right now EF is creating a TeamId column in my database that never gets populated. If what I want is impossible, then I could do lists of HomeGames and AwayGames and another list of Games that is a combination of the two, but I'd like to try and avoid it if possible. I'm still learning this so any extra explanations or tips would be appreciated.
What you're asking of EF is a read only collection, i.e., an add operation would be meaningless for such a collection since EF wouldnt know into which table to insert, which I believe is unsupported.
Judging by your problem description, I would so something similar to your own suggestion and create a method such as GetGames() which would return just a unioned set of both home and away games. I think this is conceptually cleaner anyway.
EF is not able to map two relations into single navigation property. Your additional TeamId column is created because Games navigation property is considered as separate relation (your mapping says that neither HomeTeam or AwayTeam are part of that relation) so you instructed EF to create three relations for your.
You must define your model this way:
public class Team
{
public int TeamId {get; set;}
public virtual ICollection<Game> HomeGames { get; set; }
public virtual ICollection<Game> AwayGames { get; set; }
}
And mapping must be:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Game>()
.HasRequired(a => a.HomeTeam)
.WithMany(t => t.HomeGames)
.HasForeignKey(u => u.HomeTeamId).WillCascadeOnDelete(false);
modelBuilder.Entity<Game>()
.HasRequired(a => a.AwayTeam)
.WithMany(t => t.AwayGames)
.HasForeignKey(u => u.AwayTeamId).WillCascadeOnDelete(false);
}
Now if you want all team's games you can use simply:
var games = team.HomeGames.Concat(team.AwayGames);
You can wrap this into method returning IEnumerable or into property with just getter returning IEnumerable.

Entity Framework 4.1 Code First, One-to-One with one table joining to a single key field of of composite key

I'm just beginning with EF4.1 Code First, and I pretty like it.
Here's the story :
A Codif class is composed of a key from a Domaine class, an Entite class, and Reference class, and a fourth field which is some text.
Reference and Codif have an one-to-one relationship.
Thing is, when it creates the Database, it creates some ugly fields in my Reference entity, creating duplicate fields of the Codif Entity.
Good point : When I manipulate my Reference object however, I have the expected behaviour of accessing the Codif property, and the duplicate fields are invisible.
Here's the code :
public class Reference
{
public int ReferenceId { get; set; }
public string Libelle { get; set; }
public virtual Codif Codif { get; set; }
}
public class Domaine
{
public int DomaineId { get; set; }
public string Libelle { get; set; }
}
public class Codif
{
[Key, Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int DomaineId { get; set; }
[InverseProperty("DomaineId")]
public virtual Domaine Domaine { get; set; }
[Key, Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int EntiteId { get; set; }
[InverseProperty("EntiteId")]
public virtual Entite Entite { get; set; }
[Key, Column(Order = 2)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ReferenceId { get; set; }
[InverseProperty("ReferenceId")]
public virtual Reference Reference { get; set; }
[Key, Column(Order = 3)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Codification { get; set; }
}
public class Entite
{
public int EntiteId { get; set; }
public string Nom { get; set; }
public string Email { get; set; }
}
And here's the result in the tables (images) :
Codif
Reference
In the Reference class, how can I specify that ReferenceId is the foreign key to be used against a SINGLE field of Codif ?
How to get rid of those duplicate fields in Reference ?
How to remove the Reference_ReferenceId in Codif table while preserving the navigation property ?
Thank you for your support.
Marc
Edit : I'm working with an SQL Compact Edition 4 database
Replace all your [InverseProperty("xxx")] attributes by [ForeignKey("xxx")]. I think that this is what you actually want. [InverseProperty] refers to the navigation property on the other side of the relationship which can never be a scalar property.
Edit
You could in addition to the FK attribute set the [InverseProperty] attribute on the Reference property in your Codif class:
public class Codif
{
//...
[Key, Column(Order = 2)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ReferenceId { get; set; }
[ForeignKey("ReferenceId")]
[InverseProperty("Codif")] // <-- refers to Codif property in Reference class
public virtual Reference Reference { get; set; }
//...
}
But it think it's not really necessary because EF should detect the correct relationship between Reference and Codif by convention. (I'm not sure though for one-to-one relationships.)
Edit
Problems!
First: As far as I can see you must specify the one-to-one relationship in Fluent API because EF cannot determine otherwise what's the principal and what's the dependent:
modelBuilder.Entity<Reference>()
.HasOptional(c => c.Codif)
.WithRequired(c => c.Reference);
Second: EF will still complain because of the composed key or because ReferenceId is not the key alone. If ReferenceId were the only key in Codif it would work.
Edit
I'm trying to understand what you want to achieve. Apparently your composed key in Codif is supposed to ensure that any combination of the four field values can exist only once. But this conflicts with the one-to-one relationship imo, for example this would be valid table entries:
Table Codif:
DomaineId EntiteId ReferenceId Codification
----------------------------------------------------
1 1 1 "A"
2 1 1 "A"
1 2 1 "A"
1 1 2 "A"
1 1 1 "B"
etc...
But as you can see: You can have multiple rows with the same ReferenceId which means that you cannot have a one-to-one relationship to Reference. Here you have 4 Codif entities which refer to the same Reference entity with Id = 1.
Now, I guess, the fact that you want to have a one-to-one relationship means that there is an additional constraint so that ReferenceId in Codif table can occur only once. In other words: The rows 2, 3 and 5 in the example above are invalid from business viewpoint (although valid from DB viewpoint).
If this is the case I would actually make ReferenceId the single key in Codif and make sure from business logic that the other combinations of values in the DB are unique (Query if exists before you insert a new Codif). On database side you could create a unique index over the other three fields to ensure that the combinations are always unique in the database. EF cannot check this internally though since unique constraints are not yet supported.