Mapping nested classes via Entity Framework - entity-framework

I have class with this definition :
public class WebSiteContent
{
public Guid Id { get; set; }
public About About { get; set; }
public Tips Tips { get; set; }
public Images Images { get; set; }
}
where my About and Tips and Images are look like this :
public class About
{
public Guid Id { get; set; }
public string Text { get; set; }
public string Addres { get; set; }
public int PhoneNumber { get; set; }
public int Mobile { get; set; }
}
and Tips :
public class Tips
{
public Guid Guid { get; set; }
public string Content { get; set; }
}
and Images :
public class Images
{
public Guid Id { get; set; }
public string Background { get; set; }
public string Logo { get; set; }
public About About { get; set; }
}
here i just want to use about and Images and tips as a helper class to just create a property and don't want to have about,Images or tips table in database !
Entity framework needs Id to map all of above classes , how can I do that ?

here i just want to use about and Images and tips as a helper class to
just create a property and don't want to have about,Images or tips
table in database
So you are looking for complex type. Mark your About, Tips and Images classes with [ComplexType] attribute.
Entity framework needs Id to map all of above classes , how can I do
that ?
EF only needs Id for entities. If you map them as complex types you will not need to use any Id.
Btw. if you don't want to have those classes and their properties in database at all you can use [NotMapped] attribute instead.

Related

EF Core: How to organize models/tables and use DBQuery when I have 2 different tables relating to the same common one

Let's say I have a bike shops that sell various types of bikes: pro, kids, youth, leisure and any mixture. So I have a table of shops that refers/relates to a table of possible types. Now these shops also host events with the same types: events for pros, kids etc again any mixture. And so I have another table of events that also need to refer/relate to the same table of types:
I need to be able in a single quick query get a list of all bike types for a shop or event.
So I figured I'd have 3 main tables: Shops, Events, BikeTypes and two intermediate to link shops and events to bike types:
And I organized my models as:
public class BikeShop
{
public long Id { get; set; }
public string name { get; set; }
public string address { get; set; }
public string phone { get; set; }
}
public class BikeEvent
{
public long Id { get; set; }
public string name { get; set; }
public string description { get; set; }
public DateTime date { get; set; }
public string location { get; set; }
}
public class BikeType
{
public long Id { get; set; }
public string name { get; set; }
public string code { get; set; }
}
public class ShopBikeTypes
{
public long Id { get; set; }
public BikeShop shop { get; set; }
public BikeType biketype { get; set; }
}
public class EventBikeTypes
{
public long Id { get; set; }
public BikeEvent bikeevent { get; set; }
public BikeType biketype { get; set; }
}
With DataCotext:
public class DataContext : DbContext
{
public DbSet<BikeShop> Shops { get; set; }
public DbSet<BikeEvent> Events { get; set; }
public DbSet<BikeType> BikeTypes { get; set; }
public DbSet<ShopBikeTypes> ShopBikeTypes { get; set; }
public DbSet<EventBikeTypes> EventBikeTypes { get; set; }
}
Migration creates correct database structure just as my diagram. Great!
Now how do I make a straight forward query:
get list of all bike types for a shop
get list of all bike types for an event
Is my structure even correct?
Do I need some List<> in the main object models BikeShop and BikeEvent?
EF's include and theninclude seem to require some list?
This feels like such a typical scenario. What's the right way of doing this?
Thank you.
Those are the linq queries that you are asked but when i look at that your class models, i can say they are wrong. U need to define first which relation theyre having. if all of that relation has based on one-to-one, u wont gonna need any List<> in your class models. but if u have one-to-many relation,u gonna need them.
1- get list of all bike types for a shop
return DbContext.Shops
.Include(x>=x.ShopBikeTypes)
.ThenInclude(x=>x.BikeTypes).ToList();
2- get list of all bike types for an event
return DbContext.Events
.Include(x=>x.EventBikeTypes)
.ThenInclude(x=>x.BikeTypes).ToList();
3- Get all data in that relation
return DbContext.BikeTypes
.Include(x>=x.EventBikeTypes)
.ThenInclude(x=>x.Events).AsSplitQuery()
.Include(x=>x.ShopBikeTypes)
.ThenInclude(x>=x.Shops).AsSplitQuery()
.ToList();
it can be a tough query, do not try to use AsNoTracking() because it can cause Cartesian Explosion.
#BerkGarip: thank you for your help. I ended up with this models structure:
public class AShop
{
public long Id { get; set; }
public string name { get; set; }
public string address { get; set; }
public string phone { get; set; }
public List<AShopType> aTypes { get; set; }
}
public class AEvent
{
public long Id { get; set; }
public string name { get; set; }
public string description { get; set; }
public DateTime date { get; set; }
public string location { get; set; }
public List<AEventType> aTypes { get; set; }
}
public class AType
{
public long Id { get; set; }
public string name { get; set; }
public string code { get; set; }
}
public class AShopType
{
public long Id { get; set; }
public AType aType { get; set; }
}
public class AEventType
{
public long Id { get; set; }
public AType aType { get; set; }
}
In order to achieve what I needed using answer from #BerkGarip I figured out that the trick there was to have lists in the 'shop' and 'event' models to the intermediate objects which in turn have a single reference to 'type'. This way database layout is the same and it is many-to-many relationship and I can use 'include' and 'thenInclude' exactly as expected:
return await _context.AShops.Where(x => x.name == "Z")
.Include(x => x.aTypes)
.ThenInclude(y => y.aType)
.ToListAsync();

The entity type 'Program' requires a primary key to be defined

I am trying to make a simple website that tracks students, programs, and classes. I've created the entities and I'm getting an error when trying to add the migration.
"The entity type 'Program' requires a primary key to be defined."
I have tried using the [Key] attribute and there is an Id field. The other table was created just fine. What else should I try?
Here is the problem class:
public class Program
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Here is another table that I had no problems creating a migration for:
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CellPhone { get; set; }
public string HomePhone { get; set; }
public string WorkPhone { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public DateTime BirthDate { get; set; }
}
Here is what is in my ApplicationDbContext class:
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
//public DbSet<Attendance> Attendances { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<Bill> Bills { get; set; }
//public DbSet<Session> Sessions { get; set; }
public DbSet<Program> Programs { get; set; }
}
I've commented out the other entities because I was trying to add them one at a time. Trying to add a migration with all the entities resulted in the same error with the same specific class.
Complete shot in the dark, but based on the name of this class, I'm guessing you're referencing the wrong Program. Make sure that your DbSet<Program> is actually using your Program entity and not something like the Program class used at the console app level. You'll likely need to explicitly use the namespace, i.e. DbSet<MyApp.Models.Program>.
You might also consider changing the name of the class to remove any chance of ambiguity. There's some class names that are just going to wreck havoc trying to use them because they'll conflict with framework stuff constantly. It's usually more hassle than it's worth just to have that particular name. Program is one of those.
You can try to use this way:
public class Program
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool UseRanks { get; set; }
}
Adding [Key] attribute to the Id property.
In the file ApplicationDbContext.cs, you can override OnModelCreating method:
public DbSet<Program> Programs { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Program>().ToTable("Programs").HasKey(x => x.Id);
}

Map many to many objects using Entity Framework

For example we have profile and organisation. Both have articles.
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
}
public class Profile
{
public int Id { get; set; }
public string Email { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
public class Organisation
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
In this way Article should have two kinds of parent so it should have something like parent type to be able to access a parent when you select articles directly.
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public ArticleParentType Parent { get; set; }
}
Is it possible to map it using Entity Framework?
Is it a good idea to do it?
What is the best practice for storing this kind of data?
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentId { get; set; }
public ArticleParentType Parent { get; set; }
}
Is it possible to map it using Entity Framework?
Is it a good idea to do it?
Possible yes but not a good idea. The underlying Database can't use a foreign key for Parentid. It would be slow.
What is the best practice for storing this kind of data?
A simple approach, with 2 Nullable parents and without CascadeOnDelete:
public class Article
{
public int Id { get; set; }
public string Title { get; set; }
public virtual Profile Profile { get; set; }
public virtual Organisation Organisation { get; set; }
}
Alternatively you could use inheritance for Article, ie class OrganisationArticle : Article {}

Storing IEnumerable<string> in Entity Framework

Is it possible to store an IEnumerable<string> in Entity Framework?
I'm using code-first in ASP.NET MVC5 and I have a model that looks a little like this, but ImageUris does not appear as a column in my database (all the other properties do).
public class Product
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Condition { get; set; }
public decimal Price { get; set; }
public IEnumerable<string> ImageUris { get; set; }
}
PS: In case you are interested in why I'm storing Uris rather than images themselves, they are uris to Azure Storage Blobs.
You cannot save multiple records in single column of the relational database. There is no such data type that supports this.
You can create a separate table for Image Uris and then store your image Uris there.
Your entity code would look something like this:
public class Product
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Condition { get; set; }
public decimal Price { get; set; }
public virtual ICollection<ImageUri> ImageUris { get; set; }
}
public class ImageUri
{
[Key]
public int Id { get; set; }
public string Uri { get; set; }
}

Shared Image table with entity framework

I would like to create a table for images within my database that can be used by several different models. I'm using entity framework and have defined my images class as follows:
public class Images
{
public int ID { get; set; }
public String Name {get; set;}
public byte[] ImageData { get; set; }
public string Type { get; set; }
}
I would then like to link to this from any of my other models that need to hold an image. E.g
public class Project
{
public int ID { get; set; }
public String Name { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public virtual ICollection<tImages> Images { get; set; }
}
and also
public class User
{
public int ID { get; set; }
public String UserName { get; set; }
public virtual ICollection<tImages> Images { get; set; }
}
The trouble is that entity framework is adding a foreign key for both project and user to the image table. I kind of expected this I guess.
What I want is to define an image key that can be used to index into my image table. I'm just not sure how to define the classes to get this affect. E.g how do I define my entity classes to acheive the result below:
Project Table
//ID Name StartDate EndDate Image
//1 Project1 05/02/2013 06/04/2013 PROJ01IMG
User Table
//ID UserName Image
//1 Bob USER01IMG
Image Table
//ID Name Imagekey ImageData Type
//1 img1 PROJ01IMG 0xFFF00F1 .. etc JPEG
//2 teamphoto PROJ01IMG 0xFEB0011 ..etc JPEG
//3 outline PROJ01IMG 0xFFF0AA3 ..etc PNG
//4 bob USER01IMG 0xFFF01233 ..etc JPEG
Of course it may be that having the foreign keys is the correct approach and I shouldn't worry about it? Its just that I have a lot of models and they all need to store images so I'd rather just have them in one table rather than multiple image table as it will make searching/ galleries etc of all images easier down the line I think.
I get the feeling that this a complete noob question and I'm missing something obvious so apologies if it is.
If you don't want EF to map a FK, and instead you will manually populate a list based on the image key, define your entities like this. But I think you are better off with what you had, using FK's.
public class Project
{
public int ID { get; set; }
public String Name { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public string ImageKey { get; set; }
[NotMapped]
public List<Image> Images {get; set;}
}
public class User
{
public int ID { get; set; }
public String UserName { get; set; }
public string ImageKey { get; set; }
[NotMapped]
public List<Image> Images {get; set;}
}
I suppose you might try defining your classes like this to see if it's what you want:
public class Images
{
public int ID { get; set; }
public String Name {get; set;}
public byte[] ImageData { get; set; }
public string Type { get; set; }
public virtual User User { get; set; }
public virtual Project Project { get; set; }
}
public class Project
{
public int ID { get; set; }
public String Name { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
public class User
{
public int ID { get; set; }
public String UserName { get; set; }
}
That should map a FK to Images in Project as well as in User, which is what I think you're really looking for.