Interfaces and multiplicity contraint violation on EF 4.1 Code-first - c#

I'm trying to define a supply chain with Suppliers, Dealers and Retailers. This entities are bound by a Contract class that also defines the ProductLine and the Products they will work with.
For a given ProductLine, there will be a contract between a Supplier (the sole owner of that ProductLine) and a Dealer, and then another contract between this Dealer and a Retailer.
The problem is that there's also a contract between two dealers so I tried creating two interfaces (ISeller and IBuyer). Supplier implements ISeller, Retailer implements IBuyer and Dealer implements both interfaces:
public class Supplier : ISeller
{
public int Id { get; set; }
public virtual ICollection<Contract> Contracts { get; set; }
}
public class Dealer : ISeller, IBuyer
{
public int Id { get; set; }
public virtual ICollection<Contract> Contracts { get; set; }
}
public class Retailer : IBuyer
{
public int Id { get; set; }
public virtual ICollection<Contract> Contracts { get; set; }
}
The Contract then bounds a ISeller to a IBuyer, like this:
public class Contract
{
public int Id { get; set; }
public virtual ISeller Seller { get; set; }
public virtual IBuyer Buyer { get; set; }
}
Creating contracts between Supplier/Dealer or Dealer/Retailer works as intended, but I get a 'Multiplicity constraint violated' when trying to create a Dealer/Dealer contract.

It seems that the problem with this code is the interfaces. As Slauma said in the comments, the interface members of Contract class are not mapped at all since EF does not know, for example, which entities - Supplier, Dealer or both - map to Seller member.
From the other direction we have that each of the supply chain participants have multiple contracts. This results in Supplier_id, Dealer_id, Reseller_id columns in Contracts table. From EF perspective, Supplier and Dealer have nothing in common, neither do Retailer and Dealer.
What you need to do is to have entity inheritance. Dealer can be both seller and buyer though so you cannot have 2 separate classes as C# does not allow multiple inheritance. Define ContractParticipant base entity and have Supplier, Dealer and Retailer inherit from it. Then your data model would look something like:
public abstract class ContractParticipant
{
public int Id { get; set; }
[InverseProperty("Seller")]
public virtual ICollection<Contract> SellerContracts { get; set; }
[InverseProperty("Buyer")]
public virtual ICollection<Contract> BuyerContracts { get; set; }
}
public class Supplier : ContractParticipant
{
<...other properties here...>
}
public class Dealer : ContractParticipant
{
<...other properties here...>
}
public class Retailer : ContractParticipant
{
<...other properties here...>
}
public class Contract
{
public int Id { get; set; }
public virtual ContractParticipant Seller { get; set; }
public virtual ContractParticipant Buyer { get; set; }
}
This model should generate database structure that would support your scenario without any other configuration. However it would also allow contracts between any types of participants but If you try to map multiple inheritance in data model you would end up with something like this - consider if you want to complicate your data model to preserve these constraints.

Trying using this one :
public class Contract
{
public int Id { get; set; }
public virtual Seller Sellers { get; set; }
public virtual Buyer Buyers { get; set; }
}

Related

Entity Framework Inheritance relational tables

I have tried several things before coming here, such as different model approach, annotation, declarations in DbContext, different fluent API usages but I can't seem to see what the issue is.
I have a YogaClass record but when I iterate over the subscriptions from a person, I have a subscription but no YogaClass (NULL) and yes I.Include(Person.Subscriptions) when querying the DB, I'm getting the subs but not the relational YogaClass/WorkShop associated with it.
In short, I have the following classes :
Subscription (base class)
public class Subscribtion
{
[Key]
public int SubscribtionID { get; set; }
public Person Person { get; set; }
public bool IsPayed { get; set; }
}
WorkshopSubscription (inherrits Subscription)
public class WorkshopSubscribtion : Subscribtion
{
[Key]
public int WorkshopSubscribtionID { get; set; }
public Workshop Workshop { get; set; }
}
YogaClassSubscription (inherrits Subscription)
public class YogaClassSubscribtion : Subscribtion
{
[Key]
public int YogaClassSubscribtionID { get; set; }
public YogaClass YogaClass { get; set; }
}
YogaClass (base class)
public class YogaClass
{
[Key]
public int YogaClassID { get; set; }
public List<Subscriptions> Subscriptions { get; set; }
}
WorkShop (base class)
public class WorkShop
{
[Key]
public int WorkShopID { get; set; }
public List<Subscriptions> Subscriptions { get; set; }
}
Now after I insert some records in the Seeder I have the following issue when I look into my DataBase:
Table Subscription : SubscriptionID:1 , WorkShop_WorkShopID:NULL , YogaClass_YogaClassID:NULL . (Why are they both NULL ?)
Table YogaClassSubscription : SubscriptionID:1 , YogaClassID:1
Same for workshop.
I don't get why the FK from Yoga & Workshop Subscription is NULL in Subscription table.
I have a DbSet declared in my Context and in modelBuilder fluent API method I have mapped both YogaClassSubscribtion & WorkShopSubscribtion to their own table.
public DbSet<Subscribtion> Subscribtions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<WorkshopSubscribtion>().ToTable("WorkshopSubscribtions");
modelBuilder.Entity<YogaClassSubscribtion>().ToTable("YogaClassSubscribtions");
}
I think your problem comes from using the base class Subscription as the type of your generic lists Subscriptions. You should use the specific derived classes YogaClassSubscription and WorkShopSubscription:
public class YogaClass
{
[Key]
public int YogaClassID { get; set; }
public virtual List<YogaClassSubscription> Subscriptions { get; set; }
}
public class WorkShop
{
[Key]
public int WorkShopID { get; set; }
public virtual List<WorkShopSubscription> Subscriptions { get; set; }
}
This way EF knows about the relationship between WorkShops and WorkShopSubscriptions, and between YogaClasses and YogaClassSubscriptions.
Another thing that seems wrong: redefining the ID property and the Key annotations in your derived classes. You only need to define the ID in the base class. Remove those properties and their annotations. EF will create a foreign key with a one-to-one relationship between your base class table and the derived classes tables.
public class WorkshopSubscription : Subscription
{
public virtual Workshop Workshop { get; set; }
}
public class YogaClassSubscription : Subscription
{
public virtual YogaClass YogaClass { get; set; }
}
An advice: define your navigation properties as virtual, in order to allow EF to use proxies to track status changes in your entities, and also to allow the use of Lazy Loading.

Multiple relationships to single table Entity Framework asp.net MVC

I've just started using Entity Framework for my next project and I'm struggling with the following. I have the following ApplicationUser class:
public class ApplicationUser : IdentityUser
{
public string Name { get; set; }
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
}
I have two classes that inherent from this class:
public class TrainerUser : ApplicationUser
{
public virtual ICollection<ClientUser> Clients { get; set; }
}
public class ClientUser : ApplicationUser
{
public string TrainerId { get; set; }
public TrainerUser Trainer { get; set; }
}
The company class looks like this:
public class Company
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<TrainerUser> Trainers { get; set; }
public virtual ICollection<ClientUser> Clients { get; set; }
}
What I can't figure out is how I can use the fluent API to not include 3 different companyId columns in the ApplicationUsers table.
Currently I have the following fluent API configuration:
modelBuilder.Entity<TrainerUser>().HasRequired(c => c.Company).WithMany(t => t.Trainers).HasForeignKey(c => c.CompanyId);
modelBuilder.Entity<ClientUser>().HasRequired(c => c.Company).WithMany(c => c.Clients).HasForeignKey(c => c.CompanyId);
Can anyone point me in the right direction?
Try adding these to your code.
modelBuilder.Entity<TrainerUser>().ToTable("TrainerUser");
modelBuilder.Entity<ClientUser>().ToTable("ClientUser");
If I am getting you right. you are trying to create a structure representing Table Per Hierarchy (TPT). Read more about it at the link.
Basically what happens is when entity framework encounters inheritance in the entities. Its Default attempt to create tables is by creating column of the set of all properties of all the derived entities from a class with a discriminator column.
What you are trying to create is a separate table for every class in the hierarchy.

Entity Framework 6 - Code first - FK is generated in inherited classes but relation is defined in base class

What i want is to have a base class and two separate lists of inherited classes.
This is my model:
public class Instance
{
public int InstanceId { get; set; }
public virtual ICollection<User> Users { get; internal set; }
public virtual ICollection<MasterUser> MasterUsers { get; internal set; }
}
public abstract class CoreUser
{
[Key]
public int UserId { get; set; }
public int InstanceId { get; set; }
public virtual Instance Instance { get; set; }
}
[Table("Users")]
public class User : CoreUser
{
public string UserName { get; set; }
}
[Table("MasterUsers")]
public class MasterUser : CoreUser
{
public string MasterUserName { get; set; }
}
This is my DbContext:
public class MyContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<MasterUser> MasterUsers { get; set; }
public DbSet<Instance> Instances { get; set; }
}
This will create 4 tables with TPT inheritance model which is fine. The problem is Users and MasterUsers table will contain foreign key to Instance (it will be called Instance_InstanceId) which is redundant since this FK is defined in the CoreUser base class. These two FK columns are not even populated, they are always NULL, CoreUsers InstanceId column is populated when you add either User or MasterUser.
If I remove both referenced from Instance class like so:
public class Instance
{
public int InstanceId { get; set; }
}
Problem goes away but that also renders my application unusable.
I can also solve my problem like so:
public class Instance
{
public int InstanceId { get; set; }
public virtual ICollection<CoreUser> Users { get; internal set; }
}
And then iterate trough collection filtering out each type of user but this approach will lazy load all of the users even though I just want to iterate trough MasterUsers only.
One possible solution was to use TPC but in reality, CoreUser class will contain FKs to some other Classes which is not supported in TPC (only top level classes in hierarchy can contain FKs).
Is there any way I can get this to work in EF using two separate lists in Instance class and have them lazy loaded?
EDIT
Actually, the above code would work just fine. It will break if you introduce one more class that references CoreUser for example:
public class UserPolicy
{
public int PolicyId { get; set; }
public virtual CoreUser PolicyUser { get; internal set; }
}
Managed to get around this. Solution that I was able to use is to move relationship between CoreUser and Instance to User and MasterUser like so:
public class Instance
{
public int InstanceId { get; set; }
// Still referencing two lists
public virtual ICollection<User> Users { get; internal set; }
public virtual ICollection<MasterUser> MasterUsers { get; internal set; }
}
public abstract class CoreUser
{
[Key]
public int UserId { get; set; }
// No reference to instance. Works if you don't need it from CoreUser
}
[Table("Users")]
public class User : CoreUser
{
// FK to Instance defined in CoreUser
public int InstanceId { get; set; }
public virtual Instance Instance { get; set; }
public string UserName { get; set; }
}
[Table("MasterUsers")]
public class MasterUser : CoreUser
{
// FK to Instance defined in MasterUser
public int InstanceId { get; set; }
public virtual Instance Instance { get; set; }
public string MasterUserName { get; set; }
}

Entity Framework 6 multiple table to one foreign key relationship code first

I am wondering if anyone could advise me on how to accomplish the below using code first in EF6
If I add the Table_3 as a List on to Table_1 & Table_2 in my entities. EF automatically generates a foreign key column for both tables in Table_3 instead of recognizing that they are of the same type.
My model classes are set as follows.
public interface IParent
{
int ID { get; set; }
List<Table_3> Children { get; set; }
}
public class Table_1 : IParent
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Table_3> Children { get; set; }
}
public class Table_2 : IParent
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Table_3> Children { get; set; }
}
public class Table_3
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public virtual IParent Parent { get; set; }
}
EF code first generates the below
Edit
Just to let anyone having the same problems know
I have now resolved this by changing the IParent interface to an abstract class
my classes now look like the following
[Table("ParentBase")]
public abstract class ParentBase
{
[Key]
public int ID { get; set; }
public List<Table_3> Children { get; set; }
}
[Table("Table_1")]
public class Table_1 : ParentBase
{
public string Name { get; set; }
}
[Table("Table_2")]
public class Table_2 : ParentBase
{
public string Name { get; set; }
}
[Table("Table_3")]
public class Table_3
{
[Key]
public int ID { get; set; }
public int ParentID { get; set; }
[ForeignKey("ParentID")]
public virtual ParentBase Parent { get; set; }
}
with a table arrangement of
this will work although it would have been nicer if the original could have been met.
I had this problem too, and I used abstract class instead of interface from the beginning.
The problem for mine was my table_3 have two navigation properties:
one is public virtual Table_1, another is public virtual Table_2, and then EF just provisioned these extra foreign key columns,
I merged the two navigation properties into one to
public virtual parentbase {get;set;}. And then it worked. Hope this helps.
Side Note,Would suggest to add virtual keyword on public List Children { get; set; } in parentbase class, because in your previous example , it was already like that.
Thanks for posting this, i came across this issue too.
You can also do like the following where you make a 1 to many relationship between Table_1 and Table_2 with Table_3 respectively:
modelBuilder.Entity<Table_3>().HasOptional(/*Nav Prop*/).WithMany(m => m.Table_3s).HasForeignKey(f => f.ParentId).WillCascadeOnDelete(false);
modelBuilder.Entity<Table_3>().HasOptional(/*Nav Prop*/).WithMany(m => m.Table_3s).HasForeignKey(f => f.ParentId).WillCascadeOnDelete(false);
Let me know if anymore clarification is required.

Entity Framework data modelling best practices

I have Entity structure like below
public abstract class Entity
{
public int Id { get; set; }
}
public class User : Entity
{
public ICollection<Product> Products { get; set; }
}
public class Warehouse : Entity
{
public ICollection<Product> Products { get; set; }
}
public class Product : Entity
{
public Warehouse Warehouse { get; set; }
public User User { get; set; }
}
As you can see User can has products and Warehouse also can have products. So Entity framework put 2 foreign keys over Product table that can be nullable.
We could also achieve similiar structure by bit of different entity modelling like below
public class User : Entity
{
public ICollection<UserProduct> Products { get; set; }
}
public class Warehouse : Entity
{
public ICollection<WarehouseProduct> Products { get; set; }
}
public class Product : Entity
{
}
public class WarehouseProduct : Entity
{
public Product Product { get; set; }
public Warehouse Warehouse { get; set; }
}
public class UserProduct : Entity
{
public Product Product { get; set; }
public User user { get; set; }
}
First Design look simpler without introduce new entitties but not sure that it is better or not.
I am trying to find which is best or which circumtances makes one of it better than other.
Inheritance would also be possible (EF/CodeFirst):
public abstract class Entity
{
public int Id { get; set; }
}
public class Product : Entity
{
}
public class Warehouse : Product
{
/* all product fields are available */
}
public class User : Product
{
/* all product fields are available */
}
this is more DRY in my point of view => "CodeFirst view".
good post about Inheritance: http://goo.gl/1igQ3

Categories