Entity Framework - Mapping Many to Many Relationships - entity-framework-4.1

I am struggling on how to map these two tables together, the Column TitleID on the Name table maps to the TitleID on the Title table. The table primary keys are NameTableID / TitleTableID and are unique, NameID, TitleID (on both tables) are not unique, the current record is found by a null in the DateEnd column.
public class Name
{
public int NameTableID { get; set; }
public int NameID { get; set; }
public int TitleID { get; set; } // Maps to Title.TitleID
public virtual Title Title { get; set; }
public string GivenName { get; set; }
public string FamilyName { get; set; }
public DateTime DateStart { get; set; }
public DateTime? DateEnd { get; set; }
}
public class Title
{
public int TitleTableID { get; set; }
public int TitleID { get; set; } // Maps to Name.TitleID
public string Description { get; set; }
public DateTime DateStart { get; set; }
public DateTime? DateEnd { get; set; }
}
I am assuming I need to add a bit of code to OnModelCreating in my DB Context class, but am struggling with the mapping / code, any ideas?
Thanks,
Martin

This is not relation at all. You cannot build relation on two arbitrary columns. You should read some introduction about how database relations work and what are requirements to build a relation.
In many-to-many you must choose unique key on both ends and there must be junction table which will build pairs of related keys. EF doesn't support unique keys so the only way how to build many-to-many relation is on top of primary keys: If you want many-to-many relation you must build it on Title.TitleTableID and Name.NameTableID.

Related

Entity Framework in MY.SQL ASP.NET Core Angular project fails with MySqlException error in syntax near CONSTRAINT when trying to DropForeignKey

I am running a project using code first migrations. I have a big model and everything ran smoothly untill this happened. So part of the big picture was like looking this. Initial state model number one:
public class WebClient
{
public int Id { get; set; }
public string FirstName { get; set; }
public IList<Trade> Trades { get; set; }
public IList<Portfolio> Portfolios { get; set; }
public IList<Strategy> Strategies { get; set; }
[Required]
public string EMail { get; set; }
}
And the second model:
public class Strategy
{
public int Id { get; set; }
public string Name { get; set; }
public string ShortDesc { get; set; }
public string EntryRules { get; set; }
public string ExitRules { get; set; }
public IList<Trade> Trades { get; set; }
}
When I ran this migration to MYSQL database Entity Framework created a webClientId column in the strategies table and set it to be the foreign key for WebCLients.Id (for the id in the webclients table) and also created an index for that which is pretty cool.
After this I realized I forgot to input a relation to the webclient inside the strategy model. So I put two lines in and got this.
public class Strategy
{
public int Id { get; set; }
public string Name { get; set; }
public string ShortDesc { get; set; }
public string EntryRules { get; set; }
public string ExitRules { get; set; }
public IList<Trade> Trades { get; set; }
public virtual WebClient WebClient { get; set; } //new stuff
public int WebClientId { get; set; } //new stuff
}
For this Entity Framework suggested a following migrations which is a bit weird to start with.
migrationBuilder.DropForeignKey(
name: "FK_Strategies_WebClients_WebClientId",
table: "Strategies");
migrationBuilder.AlterColumn<int>(
name: "WebClientId",
table: "Strategies",
nullable: false,
oldClrType: typeof(int),
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_Strategies_WebClients_WebClientId",
table: "Strategies",
column: "WebClientId",
principalTable: "WebClients",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
So it drops the old key to create a new one which is exactly the same apart from that it is not nullable. Ok well let's do it. However when I run a database update on that I get an error and I have no idea on how to deal with it.
MySql.Data.MySqlClient.MySqlException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CONSTRAINT FK_Strateg
ies_WebClients_WebClientId' at line 1
If I run the command with a --verbose flag I can catch the bit of SQL and see where it crashes...
ALTER TABLE Strategies DROP CONSTRAINT FK_Strategies_WebClients_WebClientId;
Has anyone come across this issue ? Will be real glad to hear any hints, Thanks!
Ok so the work around is like this. Seems to me MySQL doesn't understand:
ALTER TABLE Strategies DROP CONSTRAINT FK_Strategies_WebClients_WebClientId;
That is for SQL Server / Oracle / MS Access. More on this here
I just changed that line in the migrations to
migrationBuilder.Sql("ALTER TABLE Strategies DROP FOREIGN KEY FK_Strategies_WebClients_WebClientId;");
Everything updated fine after that. Result - use DROP FOREIGN KEY in MySql instead of DROP CONSTRAINT. No idea why that is not fized in the MySql Adapter for Entity Framework.
This is happening because Entity Framework doesn't understand that WebClientId is a foreign key so it is adding a new foreign key field for you. The Entity Framework convention for naming automatically inserted foreign key fields is TableName_Id,
Entity Framework Code First provides a set of data annotation attributes that can be applied on domain classes or the properties of domain classes.The ForeignKey attribute is used to specify which property is the foreign key in a relationship (ForeignKey Attribute specifies the foreign key for the Navigation property in Entity Framework).
Example:
public class Strategy
{
public int Id { get; set; }
public string Name { get; set; }
public string ShortDesc { get; set; }
public string EntryRules { get; set; }
public string ExitRules { get; set; }
public IList<Trade> Trades { get; set; }
public int WebClientId { get; set; } //Foreign Key property
[ForeignKey("WebClientId")]
public WebClient WebClient { get; set; } //Respective Entity
}
public class WebClient
{
public int Id { get; set; }
public string FirstName { get; set; }
[Required]
public string EMail { get; set; }
public IList<Trade> Trades { get; set; }
public IList<Portfolio> Portfolios { get; set; }
public IList<Strategy> Strategies { get; set; }
}
You can get more information from this link.

AspNet EF referencing foreign key to field

Im having two models:
public class Customer
{
public int Id { get; set; }
public int Number { get; set; }
public int ParentNumber { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Language { get; set; }
}
and
public class Batch
{
public int Id { get; set; }
public int Number { get; set; }
public string FileName { get; set; }
public string ArticleNumber { get; set; }
public string ArticleDescription { get; set; }
public int Weight { get; set; }
public DateTime ProductionDate { get; set; }
public DateTime DeliveryDate { get; set; }
public DateTime BestBeforeDate { get; set; }
public DateTime? ApprovedDateTime { get; set; }
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
One batch can have a customer attached to it. But since we're importing the data from another system we decided not to take over their id's.
Right now the foreign key says try to find a customer by the property Customer.Id
I'm trying to achieve to get the foreign key point to Customer.Number from Batch.Customer(Id)
How would i succeed in this?
I've tried by defining the Customer.Number to be a Key with the Key attribute.. but this made the primary key go from Id to Number which is not what i wanted...
What are you asking was impossible in EF prior to EF Core. Fortunately in EF Core it can be done by using Alternate Keys feature. But please note that in order to be able to use it, your Cusomer.Number field should be unique.
The solution requires Fluent API configuration.
Start by defining Customer.Number as alternate key:
modelBuilder.Entity<Customer>()
.HasAlternateKey(e => e.Number);
Then set up the relationship as follows:
modelBuilder.Entity<Batch>()
.HasOne(e => e.Customer)
.WithMany()
.HasForeignKey(e => e.CustomerId)
.HasPrincipalKey(e => e.Number);
The last two lines will do what you are seeking for.
As a side note, it would be better to name the property (and column) CustomerNumber in order to avoid confusion of what the value is in it.

How to limit data in a mobile API using EF and WebAPI/JSON

I am writing a PhoneGap/Web/JS mobile application that uses the WebAPI and Entity Framework in the backend.
I have a class called Thing which references the User table 4 times (ChangedByUserId, CreatedByUserId etc. The User table is really large (30 user-related fields)
I want to pass as little data over each call as possible, but I need the User's Name for each of these UserID foreign keys. (this is the only information from the user record I need).
When I use the object graph in EF it returns the FULL user record for each foreign key, so a single Thing object becomes massively bloated. I don't want to make multiple calls to get the Thing POCO object and then the User's name by UserID.
What I really want to do is a sort of flattened DTO object which is just the Thing class below but with a string for each user name, e.g. CreatedByUserName, ChangedByUserName etc. Then I would return this DTO as my hydrated POCO object and the data would be small.
So my question is: How do I do this using Entity Framework? (limit related record's return data?)
public partial class Thing
{
public int ThingId { get; set; }
public int FromUserId { get; set; }
public int ToUserId { get; set; }
public string ThingText { get; set; }
public int StatusId { get; set; }
public int ChangedByUserId { get; set; }
public int CreatedByUserId { get; set; }
public virtual User FromUser { get; set; }
public virtual User ToUser { get; set; }
public virtual User CreatedByUser { get; set; }
public virtual User ChangedByUser { get; set; }
}
As you said, you need to flatten Thing
public class FlatThing
{
public int ThingId { get; set; }
public int FromUserId { get; set; }
public int ToUserId { get; set; }
public string ThingText { get; set; }
public int StatusId { get; set; }
public int ChangedByUserId { get; set; }
public int CreatedByUserId { get; set; }
public string FromUserName { get; set; }
public string ToUserName{ get; set; }
}
// assume you have your things
var flatThings = new List<FlatThings>;
foreach (Thing t in things)
flatThings.Add(new FlatThing{ ThingId = t.ThingId, FromUserId = t.FromUserId,
FromUserName = t.FromUser.Name .....});
return flatThings;

How can we manage the Relation between two table in POCO Entity?

I am a newbie to POCO.I have two tables like tb1 and tb2.Suppose we have a PK and FK relation between these tables.When it come to POCO CF how can we manage this relations?I have a done a sample by following a article.
public abstract class Person
{
public string Name { get; set; }
public int DepartmentId { get; set; }
public virtual Department Department { get; set; }
}
public class Collaborator : Person
{
public int CollaboratorId { get; set; }
public string ManagerCode { get; set; }
public virtual Manager Manager { get; set; }
}
Why they have used the abstract and virtual keywords? Can any one explain me the how can we manage the relations?
I assume you are using a model-first approach. You will want to use the Fluent API to define the relationships. Here is a good article on how to do this.

Entity Framework - Make Category field not required

I have two POCO objects:
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public int CategoryID { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string Name { get; set; }
}
So obviously, when I create a Product, I can select a category for that product. Or rather, a category is required.
I can't create a product without explicitly selecting a category, and my data is structured in such a way, that I don't want to create a "No Category" category entry.
I've thought about doing a many-to-many mapping between these two tables... but would like to avoid it if possible.
Either I'm doing something silly, or there really is no way to do this.
Any help would be appreciated!
Make the CategoryID nullable. If you do not supply value for CategoryID it will be set to NULL in database.
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public int? CategoryID { get; set; }
public virtual Category Category { get; set; }
}