Shared Image table with entity framework - 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.

Related

Can't get `Include` to work with EF core , without FK

I have 2 tables in SQL server without a FK :
So each Image has many Comments.
Using this command I've created scaffolded files :
dotnet ef dbcontext scaffold
"Server=sff-pc;Database=IMG;Trusted_Connection=True;"
Microsoft.EntityFrameworkCore.SqlServer -o Models -t Images -t
comments --context-dir Context -c MyContext -f
Here are the generated files :
public partial class Images
{
public int ImageId { get; set; }
public Guid ImgGuid { get; set; }
public string ImgExtension { get; set; }
public DateTime Datecreated { get; set; }
public string Origin { get; set; }
public decimal? Size { get; set; }
public string Ip { get; set; }
public int UserId { get; set; }
public string Description { get; set; }
public bool? IsActive { get; set; }
public int? VotesUp { get; set; }
public int? VotesDown { get; set; }
public int ImgType { get; set; }
}
public partial class Comments
{
public int CommentId { get; set; }
public int ImageId { get; set; }
public int UserId1 { get; set; }
public string CommentTxt { get; set; }
public DateTime DateCreated { get; set; }
public bool? IsActive { get; set; }
}
Question:
Using those generated classes and this full context file, How can I get each Image and Include its comments?
What have I tried :
I've tried adding the ForeignKey attribute :
public partial class Comments
{
public int CommentId { get; set; }
[ForeignKey("Images")] <--------------Here
public int ImageId { get; set; }
public int UserId1 { get; set; }
public string CommentTxt { get; set; }
public DateTime DateCreated { get; set; }
public bool? IsActive { get; set; }
}
And to run this :
var context = new MyContext();
var result = context.Images.Include("Comments"); //exception
foreach (var a in result)
{
Console.WriteLine(a);
}
Exception :
The property 'Comments' is not a navigation property of entity type 'Images'
When you use [ForeignKey("Images")] over your fk "Images" is expected to be a navigation property inside your Comments class not the name of your DbSet property in your DbContext. You can read more here and relationships here. In the case of your code based on the definition of your Comments class, you will need to have a property Images.
[ForeignKey("Images")]
public int ImageId { get; set; }
public Images Images { get; set; } // ForeignKey attribute points to this
While the above shows how you can use [ForeignKey("Images")], I would recommend making the property's name Image instead of Images. Not only will it be a better explanatory name, but it would also make the [ForeignKey("Image")] unnecessary. EF would automatically map Image to Imageid by naming convention.
Based on the way you are using to access comments using context.Images.Include("Comments"), you seem to be trying to access the list of comments under an image. However, if you notice your result variable would be a IQueryable of Images. To achieve this, you will need to add a navigation property into your Images class.
public IEnumerable<Comments> Comments { get; set; }
Since you have already mapped your foreign key, your mapping is implicit between ImageId and Comments. You can, however, use InverseProperty attribute to be safe (check the relationships link for more info). Once this is done you can use the following code:
var result = context.Images.Include(i => i.Comments);

Entity Framework Core error on Insert when exists a foreign key to a View

This is my model (semplified):
PRAT is the main table
public partial class PRAT
{
public int ID { get; set; }
public string PRATICA { get; set; }
public int ANNO { get; set; }
public string VARIANTE { get; set; }
[ForeignKey("ID")]
public VW_PRATICHE_CONTIPO VW_PRATICHE_CONTIPO { get; set; }
}
VW_PRATICHE_CONTIPO is a View (not a table!) in the database that contains some data related to PRAT table
public class VW_PRATICHE_CONTIPO
{
public int ID { get; set; }
public DateTime? DATAPRES { get; set; }
public string PROTGEN { get; set; }
public string TIPO { get; set; }
public string TIPOEXTRA { get; set; }
public string TIPOISTANZA { get; set; }
public string TIPOPRAT { get; set; }
}
The one-to-one relation between the table and the View is based on the ID field.
I need this because I want to do a query like this:
context.PRAT.Include(x=> x.VW_PRATICHE_CONTIPO)
This query works as exptected.
The problem happens when I try to save a new entity in PRAT.
When i do this:
context.PRAT.Add(prat);
await context.SaveChangesAsync();
I got this error:
The property 'ID' on entity type 'PRAT' has a temporary value. Either set a permanent value explicitly or ensure that the database is configured to generate values for this property.
If I remove the navigation property from PRAT all works fine, but I can't do the Include in my Query.
Can anybody help me?
Thank you.

If Exists Dont Add Data Entity Framework Many-To-Many

I have these two Models the logic is here One Post can have multiple Categories.
public class Post
{
public Post()
{
this.Categories = new HashSet<Category>();
}
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string ShortDescription { get; set; }
public string PostImage { get; set; }
public string Thumbnail { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime? PublishedDate { get; set; }
public string CreatedBy { get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
I have three static categories.
When I am trying to add new post its multiplexing CategoryTable creating new categories with same name ,And Mapping Them in to CategoryPostsTable.
The problem is here i want to map that data with existing categories. I dont want to add new category with same name.
I am using Repository Pattern how should i control that ? Is EF has some solution for that ?
I assume you have code like:
var post = new Post();
post.Categories.Add(cat);
context.Posts.Add(post);
...where cat is a Category object representing an existing category.
The latter Add method (DbSet.Add) doesn't only mark the received entity as Added but all entities in its object graph that are not attached to the context. So cat will also be marked as Added if it wasn't attached yet.
What you can do is
context.Entry(cat).State = System.Data.Entity.EntityState.Unchanged;
Now EF will only create the association to the category, but not insert a new category.

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; }
}

Mapping nested classes via 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.