Introduction
I am new to Entity Framework
I am using Code-first
Use-case
I have to following tables
[Table("TBL_UserVariant")]
public class UserVariant
{
[Key, Column(Order = 0)]
public int UserId { get; set; }
[Key, Column(Order = 1)]
public int VarId { get; set; }
public string Value { get; set; }
}
[Table("TBL_UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string eMail { get; set; }
}
I want TBL_UserProfile to refer a list of all TBL_UserVariant entries where TBL_UserProfile::UserId == TBL_UserVariant::UserId
The following is an example of my aim
[Table("TBL_UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string eMail { get; set; }
public UserVariant[] variants;
}
Where 'UserProfile::variants' should include a list of items where 'TBL_UserProfile::UserId == TBL_UserVariant::UserId'
Question
Is this directly possible using EF ? OR, should I implement a wrapper populating 'UserProfile::variants' ~manually~ ?
You have to just add a navigation property to the UserProfile entity.
[Table("TBL_UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string eMail { get; set; }
public virtual ICollection<UserVariant> UserVariants { get; set; }
}
The following is what you should need. EF will take care of the rest.
[Table("TBL_UserProfile")]
public class UserProfile
{
[Key]
public int UserId { get; set; }
public string eMail { get; set; }
public virtual ICollection<UserVariant> Variants { get; set; }
}
[Table("TBL_UserVariant")]
public class UserVariant
{
[Key]
public int VarId { get; set; }
public UserProfile User { get; set; }
public string Value { get; set; }
}
I think what you're asking for is that you want to have one UserProfile, mapped to Many UserVariants
In that case you'll need to add a collection to your UserProfile class.
public virtual ICollection<UserVariant> UserVariants { get; set; }
You'll also need to fix the [Key] property on the UserVariant class as I believe it should be on VarId. You can then just specify a navigation property
[Key]
public int VarId { get; set; }
public UserProfile User { get; set; }
Edit
As an aside, your naming conventions are all over the place. Don't prefix your table names with TBL_. Capitalise all your properties/Columns. e.g. Email not eMail
Related
I have this table using Entity Framework code first approach :
public class WebsitePart
{
public WebsitePart()
{
SubParts = new HashSet<WebsitePart>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public Nullable<int> ParentId { get; set; }
[StringLength(100)]
[Index("UQ_WebsitePart_Key", IsUnique = true)]
public string Key { get; set; }
public virtual WebsitePart Parent { get; set; }
public virtual ICollection<WebsitePart> SubParts { get; set; }
}
I need after getting the list of WebsiteParts to map it into List of another model where each element of this list has ParentId=null and down to the end of its grandsons(traversing) .
This the model I want to map to:
public class WebPartViewDto
{
public int Id { get; set; }
public string Key { get; set; }
public IList<WebPartViewDto> SubWebParts { get; set; }
}
Could you please show me how to map it with performance is taken into account?
Using Entity Framework Code first, I have several entities that share some fields, so I've created a base entity:
public class EntityBase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTimeOffset CreationDate { get; set; }
}
public class Customer : EntityBase
{
public string Code { get; set; }
public string Name { get; set; }
}
public class Product : EntityBase
{
public string Code { get; set; }
public string Name { get; set; }
}
Now lets say that I want to provide a table for related images or attachments if you prefer, to those (and more of this) tables. An entity defined like:
public class Attachment
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
//For linking?
public Guid ParentId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTimeOffset CreationDate { get; set; }
public byte[] Content { get; set; }
}
Is there a way of adding this relation to EntityBase so every entity that inherites it has a relation to the table and navigation properties?
I've spent hours on this and I hadn't found a way for it to work.
Edit: It finally happened not being possible as per v 1.1.1 Entity Framework Core does not support inheritance as I thought about it and it focuses it as a Table per Hierarchy representation of the DB: learn.microsoft.com/en-us/ef/core/modeling/relational/…
Just add the list of attachment to the base class, and a reference and referring id to the attachments. This works:
public class Attachment
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTimeOffset CreationDate { get; set; }
public byte[] Content { get; set; }
public Guid ParentId { get; set; }
public virtual EntityBase Parent { get; set; }
}
public class EntityBase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTimeOffset CreationDate { get; set; }
public ICollection<Attachment> Attachments { get; set; }
}
public class Customer : EntityBase
{
public string Code { get; set; }
public string Name { get; set; }
}
public class Product : EntityBase
{
public string Code { get; set; }
public string Name { get; set; }
}
Here's the database schema generated from this model (you can see that the default TPH inheritance works by convention):
Problem is that Attachment cannot have a foreign key to either Customer or Product. The FK can point only to one table. So you need a common table where the FK can point to. One solution is shown above, where the one common table holds all the information for the entities in the inheritance tree (TPH inheritance).
The other solution is to use TPT inheritance. You still need a common table, where the FK can point to. That will be the EntityBases table. And then you can create two other tables, one for the Customer and one for the Product entity, which will use their own FK to refer to the correspoing EntityBases (through which, you can associate your attachments).
Whether this works or not depends on the actual EF-MySQL provider you are using. But if it is supported, here's a way you can configure it:
public class Attachment
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTimeOffset CreationDate { get; set; }
public byte[] Content { get; set; }
public Guid ParentId { get; set; }
public virtual EntityBase Parent { get; set; }
}
public class EntityBase
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTimeOffset CreationDate { get; set; }
public ICollection<Attachment> Attachments { get; set; }
}
public class Customer : EntityBase
{
public string Code { get; set; }
public string Name { get; set; }
}
public class Product : EntityBase
{
public string Code { get; set; }
public string Name { get; set; }
}
public class MyCtx : DbContext
{
public DbSet<Attachment> Attachments { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().ToTable("Products");
modelBuilder.Entity<Customer>().ToTable("Customers");
}
}
This will result in a different schema than before:
I am trying to create my first app using ASP.NET MVC framework and Entity Framework 6.
I chose to use code first approach and I started by defining my Models.
I have a model called Client with an identity attribute called Id. I have multiple Models that has an attribute called ClientId. The ClientId attribute should have virtual link to the Clients Model.
Here is how my Client model looks like
[Table("clients")]
public class Client
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string status { get; set; }
public DateTime created_at { get; set; }
public DateTime? modified_at { get; set; }
public Client()
{
status = "Active";
created_at = DateTime.UtcNow;
}
}
Then here is how I am creating a belong to relation using other models.
[Table("BaseClientsToUsers")]
public class ClientToUser : ModelDefault
{
[ForeignKey("User")]
public int UserID { get; set; }
[ForeignKey("Client")]
public int ClientId { get; set; }
[ForeignKey("Team")]
public int DefaultTeamId { get; set; }
public DateTime? JoinedAt { get; set; }
public bool IsActive { get; set; }
public virtual User User { get; set; }
public virtual Client Client { get; set; }
public virtual Team Team { get; set; }
public ClientToUser()
{
DateTime UtcNow = DateTime.UtcNow;
IsActive = true;
CreatedAt = UtcNow;
LastUpdatedAt = UtcNow;
}
[Table("BaseTeams")]
public class Team : ModelDefault
{
[MaxLength(250)]
public string Name { get; set; }
[ForeignKey("Client")]
public int ClientId { get; set; }
public bool IsActive { get; set; }
public virtual Client Client { get; set; }
public Team()
{
DateTime UtcNow = DateTime.UtcNow;
IsActive = true;
CreatedAt = UtcNow;
LastUpdatedAt = UtcNow;
}
}
But, when I try to update my databases I get the following error
Introducing FOREIGN KEY constraint
'FK_dbo.BaseTeams_dbo.BaseClients_ClientId' on table 'BaseTeams' 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 or index. See previous errors.
I am not really sure what could be causing the error but it seems it is because I am creating multiple Foreign keys to the same `Clients model.
How can I fix this error?
Hello #Mike A When I started MVC I got this error too, so you need aditional tables that connects your DB items.
So try connect your database items with tables like that:
Here is my working example:
[Table("Products")]
public class Product
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public decimal InternalPrice { get; set; }
public string Url { get; set; }
}
[Table("Categories")]
public class Category
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
public string Url { get; set; }
}
[Table("ProductCategories")]
public class ProductCategory
{
[Key]
[Column(Order = 0)]
public string ProductId { get; set; }
[Key]
[Column(Order = 1)]
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
So you can connect your items without problems hope this will help you.
In ASP.NET MVC 5, I have the following models:
JoinModel.cs
// Many-to-many join model
public class JoinModel
{
[Key]
[Column(Order = 0)]
public int ModelAID { get; set; }
[Key]
[Column(Order = 1)]
public int ModelBID { get; set; }
public virtual ModelA ModelA { get; set; }
public virtual ModelB ModelB { get; set; }
public virtual ICollection<ValueModel> Values{ get; set; }
}
ValueModel:
public class ValueModel
{
public int ID { get; set; }
// public int JoinModelID { get; set; }
[DefaultValue(0)]
public int Value { get; set; }
public virtual JoinModel JoinModel { get; set; }
}
I want change it in such a way that I have an ID property in JoinModel, so I can use JoinModelID in ValueModel. I also want to keep ModelAID and ModelBID as composite surrogate/candidate keys (just for uniqueness) and ID as primary key. Is there a way to do so?
Note: making all three ID, ModelAID and ModelBID as composite ID is not what I want.
I just started playing around with the CTP4 and Code-First. I have the following setup for a possible dating site:
public class User
{
[Key]
public int Id { get; set; }
[Required]
public string LoginName { get; set; }
[Required]
public string Firstname { get; set; }
[Required]
public string Lastname { get; set; }
public string Street { get; set; }
[Required]
public string Zip { get; set; }
[Required]
public string City { get; set; }
[Required]
public bool Gender { get; set; }
[Required]
public int SoughtGender { get; set; }
[Required]
public string Password { get; set; }
[Required]
public double Latitude { get; set; }
[Required]
public double Longitude { get; set; }
}
public class Vote
{
[Key]
public int ID { get; set; }
[Required]
public User Voter { get; set; }
[Required]
public User TargetUser { get; set; }
[Required]
public int Decision { get; set; }
[Required]
public DateTime Timestamp { get; set; }
}
public class MySQLContext : DbContext
{
public MySQLContext (string constring)
: base(constring)
{ }
public DbSet<User> Users { get; set; }
public DbSet<Vote> Votes { get; set; }
protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
modelBuilder.Entity<Vote>().HasRequired(b => b.Voter).WithMany();
modelBuilder.Entity<Vote>().HasRequired(b => b.TargetUser).WithMany();
base.OnModelCreating(modelBuilder);
}
}
Now the framework does a nice job of creating the DB with all the proper keys. Now I inserted some dummy data and fired up the following query:
public override IEnumerable<Domain.Vote> FindVotes(Domain.User user)
{
var query = from v in context.Votes where v.Voter.Id == user.Id select v;
return from v in query.AsEnumerable() select v;
}
The query does return the proper Vote entities but the two User properties of the Vote object are Null. Shouldnt the framework populate those properties with the foreign keys of the users referenced in the Vote table?
Let me give you some background on EF so you can understand how this works. EF from day 1 only supported explicit load like one below
Customer.Orders.Load();
Hmm, the feedback was not welcomed by the community and developers wanted lazy loading. To support Lazy Loading EF team said you must mark your navigation property as virtual. So at runtime, Ef creates a proxy object that derives from your entity and overrides the virtual property. Below is an example of such code.
public class Customer
{
public string Name{get;set;}
public virtual ICollection<Order> Orders{get;set;}
}
At runtime there is a proxy that implements IEntityWithChangeTracker and concrete type of the collection is an entitycollection which has been around since version 1.
public class CustomerProxy:Customer,IEntityWithChangeTracker
{
private ICollection<Order> orders;
public override ICollection<Order> Orders
{
if(orders == null)
{
orders = new EntityCollection<Order>();
orders.Load();
}
return orders;
}
}
change your class to the follow
public class Vote {
[Key]
public int ID { get; set; }
[Required]
public virtual User Voter { get; set; }
[Required]
public virtual User TargetUser { get; set; }
[Required]
public int Decision { get; set; }
[Required]
public DateTime Timestamp { get; set; }
}
Notice I've added virtual to the Voter && TargetUser properties and you should be good to go.