Create relation code First Entity Framework - c#

I have a model:
public class Delivery
{
public Guid Id { get; set; }
public string Name { get; set; }
public Guid BusinessId { get; set; }
public virtual ICollection<PriceDisc> PriceDisc { get; set; }
}
public class PriceDisc
{
public Guid Id { get; set; }
public decimal Amount { get; set; }
public Guid BusinessId { get; set; }
}
How to create relation one to many between Delivery.BusinessId and PriceDisc.BuissnessId?
Thanks

you have already created a one to many relationship between them Delivery hold collection of PriceDisc in your code so for one Delivery.BusinessId you have collection of PriceDisc.BusinessId

Related

Entity Framework many-to-many With additional column

I have two classes:
public class Address
{
public Guid Id { get; set; }
public virtual ICollection<ToAddressMessageLink> MessagesTo { get; set; }
public virtual ICollection<CopyAddressMessageLink> MessagesCopyTo { get; set; }
}
public class Message
{
public Guid Id { get; set; }
public virtual ICollection<ToAddressMessageLink> To { get; set; }
public virtual ICollection<CopyAddressMessageLink> CopyTo { get; set; }
}
And I need to save connection between them in a single table.
If I simply put many-to-many relation between, EF wouldn't realize what type of connection is actually set(table rows will be identical for them).
So I have to create a link class with a discriminator like following:
public class AddressMessageLink
{
public int LinkType { get; set; }
public Guid AddressId { get; set; }
public Guid MessageId { get; set; }
}
But it also doesn't work because I can't set link type/
So I have to use TPH here:
public abstract class AddressMessageLink
{
public int LinkType { get; set; }
public Guid AddressId { get; set; }
public Guid MessageId { get; set; }
}
public class CopyAddressMessageLink : AddressMessageLink
{
public virtual AddressDto Address { get; set; }
public virtual MessageDto Message { get; set; }
}
public class ToAddressMessageLink : AddressMessageLink
{
public virtual AddressDto Address { get; set; }
public virtual MessageDto Message { get; set; }
}
With a composite key:
HasKey(x=>new {x.AddressId, x.MessageId, x.LinkType});
But it doesn't work either, because EF:
"The foreign key component AddressId is not a declared property on type ToAddressMessageLink".
If I put AddressId and MessageId into derived class I can't set key because there is no component of it in base class.
What can I do it this situation?
If u have to classes, that you want to connect, you need to create a class that will connect yours two tables. And you did that there:
public class AddressMessageLink
{
public int LinkType { get; set; }
public Guid AddressId { get; set; }
public Guid MessageId { get; set; }
}
But you don't join virtual attributes. So you have to do like this.
In your tables definition:
public class Address
{
public Guid Id { get; set; }
public virtual ICollection<AddressMessageLink> AddressMessageLink { get; set; }
}
public class Message
{
public Guid Id { get; set; }
public virtual ICollection<AddressMessageLink> AddressMessageLink { get; set; }
}
And in AddressMessageLink object:
public class AddressMessageLink
{
public int LinkType { get; set; }
public Guid AddressId { get; set; }
public Guid MessageId { get; set; }
public virtual Address Address { get; set; }
public virtual Message Message { get; set; }
}
That will connect your tables as many to many.

How do I establish a one-to-one relationship using Database First?

When my models were generated, many relationships were mapped automagically. However, some of the relationships are "incorrect" (or at least, not what I want), or missing.
I don't doubt that this is because of poor database design, but based on my role in this project there is not much I can do to fix that. However, is there something I can do in my application code to fix the mapping?
Here is one example:
I would like to map the StoreProductId property to the StoreProducts table.
ProductAttributePriceAdjustment
public partial class ProductAttributePriceAdjustment
{
public int AdjustmentId { get; set; }
public int StoreProductId { get; set; }
public int StoreId { get; set; }
public string ProductId { get; set; }
public Nullable<int> ProductSizeId { get; set; }
public Nullable<decimal> Adjustment { get; set; }
public int PointsAdjustment { get; set; }
public Nullable<int> ProductColorID { get; set; }
public StoreProduct StoreProduct { get; set; }
}
StoreProduct
public partial class StoreProduct
{
public int StoreProductID { get; set; }
public int StoreID { get; set; }
public string ProductID { get; set; }
public bool Featured { get; set; }
public bool Clearance { get; set; }
}
In my view, when I try calling something like:
#adjustment.StoreProduct.ProductID
I get this error:
Object reference not set to an instance of an object.
Update 1
I followed Frans' advice and updated my model to this:
public partial class ProductAttributePriceAdjustment
{
public int AdjustmentId { get; set; }
public int StoreProductId { get; set; }
public int StoreId { get; set; }
public string ProductId { get; set; }
public Nullable<int> ProductSizeId { get; set; }
public Nullable<decimal> Adjustment { get; set; }
public int PointsAdjustment { get; set; }
public Nullable<int> ProductColorID { get; set; }
public virtual StoreProduct StoreProduct { get; set; }
}
but am still getting the same error.
You cannot create a 1:1 mapping in entity framework like this. It's not supported.
Entity Framework only supports 1:1 mappings in which both tables have a shared primary key (ie they have the same primary key, and one of them is a foreign key to the other). In your situation, you are actually creating a 1 to many, because there is no guarantee that StoreProductId is unique.

Relationships in Entity Framework Code First

yesterday I created database in Management Studio and now I want to create it in program using EF Code First.
Here is link to my database: http://s11.postimg.org/6sv6cucgj/1462037_646961388683482_1557326399_n.jpg
And what I did:
public class GameModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreationTime { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public string TotalTime { get; set; }
public DateTime RouteStartTime { get; set; }
public DateTime RouteEndTime { get; set; }
public int MaxPlayersPerTeam { get; set; }
public int CityId { get; set; }
public int CreatorId { get; set; }
[InverseProperty("Id")]
[ForeignKey("CreatorId")]
//public int TeamId { get; set; }
//[ForeignKey("TeamId")]
public virtual UserModel Creator { get; set; }
public virtual CityModel City { get; set; }
//public virtual TeamModel WinnerTeam { get; set; }
}
public class RegionModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<CityModel> Cities { get; set; }
}
public class CityModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int RegionId { get; set; }
public virtual RegionModel Region { get; set; }
public virtual ICollection<UserModel> Users { get; set; }
public virtual ICollection<GameModel> Games { get; set; }
}
public class UserModel
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public DateTime RegistrationDate { get; set; }
public string FacebookId { get; set; }
public int CityId { get; set; }
public virtual CityModel City { get; set; }
public virtual IEnumerable<GameModel> Games { get; set; }
}
For now I wanted to create 4 tables but I have some problems... I want to make CreatorId in GameModel, but it doesn't work... When i wrote UserId instead of CreatorId it was working ( without [InverseProperty("Id")] and [ForeignKey("CreatorId")]).
This is what i get:
The view 'The property 'Id' cannot be configured as a navigation property. The property must be a valid entity type and the property should have a non-abstract getter and setter. For collection properties the type must implement ICollection where T is a valid entity type.' or its master was not found or no view engine supports the searched locations.
edit:
I changed it like this:
public int CityId { get; set; }
public int CreatorId { get; set; }
[ForeignKey("CityId")]
public virtual CityModel City { get; set; }
[ForeignKey("CreatorId")]
public virtual UserModel Creator { get; set; }
And there is another problem.
The view 'Introducing FOREIGN KEY constraint 'FK_dbo.UserModels_dbo.CityModels_CityId' on table 'UserModels' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.' or its master was not found or no view engine supports the searched locations.
And I have no idea how to solve it.
The InversePropertyAttribute specifies, which navigation property should be used for that relation.
A navigation property must be of an entity type (the types declared in your model, GameModel for example) or some type implementing ICollection<T>, where T has to be an entity type. UserModel.Id is an int, which clearly doesn't satisfy that condition.
So, the inverse property of GameModel.Creator could be UserModel.Games if you changed the type to ICollection<GameModel>, or had to be left unspecified. If you don't specify an inverse property, EF will try to work everything out on its own (in this case it would properly recognize GameModel.Creator as a navigation property, but UserModel.Games would most likely throw an exception, as it is neither an entity type, nor does it implement ICollection<T> with T being an entity type, nor is it a primitive type from a database point of view). However, EF's work-everything-out-by-itself-magic doesn't cope too well with multiple relations between the same entity types, which is when the InversePropertyAttribute is needed.
A quick example that demonstrates the problem:
class SomePrettyImportantStuff {
[Key]
public int ID { get; set; }
public int OtherId1 { get; set; }
public int OtherId2 { get; set; }
[ForeignKey("OtherId1")]
public virtual OtherImportantStuff Nav1 { get; set; }
[ForeignKey("OtherId2")]
public virtual OtherImportantStuff Nav2 { get; set; }
}
class OtherImportantStuff {
[Key]
public int ID { get; set; }
public virtual ICollection<SomePrettyImportantStuff> SoldStuff { get; set; }
public virtual ICollection<SomePrettyImportantStuff> BoughtStuff { get; set; }
}
Here, EF knows that it has to generate 2 FKs from SomePrettyImportantStuff to OtherImportantStuff with the names Id1 and Id2, but it has no way to tell which of the IDs refers to the entity where it was sold from and which is the one it was bought from.
Edit: How to fix the cyclic reference problem
To fix that problem, your context class should override OnModelCreating and configure the foreign keys which shouldn't cascade on delete accordingly, like this:
protected override void OnModelCreating(DbModelBuilder builder)
{
builder.Entity<CityModel>().HasMany(c => c.Users).WithRequired(u => u.City)
.HasForeignKey(u => u.CityId).WillCascadeOnDelete(value: false);
// Add other non-cascading FK declarations here
base.OnModelCreating(builder);
}

Only mapping to subset of a table

Weird question here.
I have a bad situation with a database I can't change.
[Table("PROJTABLE")]
public class Certifikat {
[Key]
public long Recid { get; set; }
public String DATAAREAID { get; set; }
public String Projid { get; set; }
public virtual StandardAndScope StandardInfo { get; set; }
}
[Table("DS_CRT_PROJSTANDARDSCOPE")]
public class StandardAndScope {
[Key]
public long RECID { get; set; }
public String DATAAREAID { get; set; }
public String Standard { get; set; }
public String Scope { get; set; }
}
I have an optional one-to-many relationship from Certifikat to StandardAndScope. However! It's only one-to-many if the DATAAREAID column is a certain value ("crt").
Do I have any way of telling EntityFramework only to map rows where the value of that column is crt?

Many to many mapping not creating correct tables

I have a Template class
public class Template
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual Template RelatedTemplate { get; set; }
public virtual Field RelatedTemplatePrimaryField { get; set; }
public virtual ICollection<Field> Fields { get; set; }
}
And a Field class
public class Field
{
public int Id { get; set; }
public string Name { get; set; }
public int Min { get; set; }
public int Max { get; set; }
public bool AllowEmpty { get; set; }
public bool IsCollection { get; set; }
public virtual ICollection<Template> Templates { get; set; }
}
The problem is it's not creating a many to many relationship, it just adds a FK on the fields table, I want a many to many relationship on
Fields ICollection<Field> Fields
and
ICollection<Template> Templates
EDIT:
If I remove
public virtual Template RelatedTemplate { get; set; }
public virtual Field RelatedTemplatePrimaryField { get; set; }
It works... Any ideas?
This is a case where you must help EF to correctly recognize your relations. You can do it either by data annotations:
[InverseProperty("Fields")]
public virtual ICollection<Template> Templates { get; set; }
or by fluent-API:
modelBuilder.Entity<Template>()
.HasMany(t => t.Fields)
.WithMany(f => f.Templates);

Categories

Resources