In my project, users can like a comment or a post, similar to Facebook likes. For this purpose, I created an abstract base class called Like keeping the if of the user who liked the post or the comment, and the datetime of the action. I have CommentLike class inheriting from Like class, which only have Comment property, and similarly, I have PostLike class inheriting from Like class, which only have Post property.
I use Entity Framework, and my database is generated successfully. In the generated database, there are CommentId, PostId, and Discriminator fields in the table. The thing is, if users like only one comment, and like only posts, then the CommentId field in the database will stay as null redundantly. I wonder if this is a problem. What if instead of these three fields, I only have one field, called RelatedItem which can indicate the associated Comment or the Post. In this case I can not define foreignkey I guess. Is this also a problem?
What would be best approach in such a situation?
public abstract class Like
{
public int LikeId { get; set; }
[Required]
public DateTime WhenLiked { get; set; }
[ForeignKey("WhoLiked")]
public string UserId { get; set; }
public Person WhoLiked { get; set; }
}
public class PostLike : Like
{
[Required]
public Post Post { get; set; }
[ForeignKey("Post")]
public int PostId { get; set; }
}
public class CommentLike : Like
{
[ForeignKey("Comment")]
public int CommentId { get; set; }
[Required]
public Comment Comment { get; set; }
}
Here is the database generated:
Related
I am creating some view models for my ASP MVC web app.
I created "code first" models for database. Is it a good way to derive view models from database models?
Example database model:
public class Project
{
[Key]
public int Id { get; set; }
public int? CustomerId { get; set; }
public int TypeId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
View model:
public class ViewModelProject : Project
{
[NotMapped]
public DateTime? Start { get; set; }
[NotMapped]
public DateTime? End { get; set; }
[NotMapped]
public string Manager { get; set; }
}
Is this the right way or is it completely false?
EDIT (subquestion):
I have some very simple database models like ProjectType, which only contains i.e. two properties. Should I also fragment those models in model view or can I make it that way:
Simple database model:
public class ProjectType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? Code { get; set; }
}
Can I use it like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public ProjectType Type { get; set; }
}
Or does it have to be fragmented like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int TypeCode { get; set; }
}
I would not recommend doing it this way. I (and many others) have tried it and it doesn't work well. You will inadvertedly run into troubles, since an MVC model has to be tailored to the view and what you get from the DB rarely fits. Sure, you can hammer it into place, but the code quickly gets messy and store-related and UI code starts to mangle together. This even shows in your example, since you have to put the NotMappedAttribute (which is related to data storage), to ViewModelProject (a class at UI level).
There are many other examples to show this problem, but an especially good one I find when you want to serialize a model object to JSON and send it to a JavaScript client. The JSON serializer takes the values of all public properties and adds them to the JSON. If you want to exclude a property, you have to mark it with a ScriptIgnoreAttribute, which you would also have to apply to the base class, which breaks separation between UI and store-related code.
The better way to go is to keep the staorage model and the MVC model separated and to map the data from one to the other (there are already pre-existing frameworks that help you with that, such as Automapper). This comes with additional advantages, for example better testability, since you are now not dependent on a specific data store to create model instances.
I feel like this is going to be very obvious to many of you, but my research led me nowhere.
I'm trying to build a class that will create objects with a list of properties like this one:
public class MyObject
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public List<OpenHours> OpenHours { get; set; }
public Filter Filters { get; set; }
}
I want the OpenHours object to store a list of daily hours so that they are accessible by doing MyObject.OpenHours[index].property.
I'm currently getting the error that the OpenHours object does not have a defined key, but I actually don't want it to be in my database as a different entity, I just want it to store properties the same way that it would if I listed each of the weekDay's properties directly in the MyObject class.
Here is the OpenHours class:
public class OpenHours
{
public DayOfWeek Day { get; set; }
public string StartTime { get; set; }
public string EndTime { get; set; }
}
I want each of my "MyObject" objects to have unique OpenHours values, so I do not want to create an Id just for it.
Am I missing something in the syntax, or is it bad logic to do so?
Thanks in advance for your answers!
Edit: Someone answered and deleted his answer afterwards, so I can't mark it as the right answer, but the solution was to add [ComplexType] to my class :
[ComplexType]
public class OpenHours
{
public DayOfWeek Day { get; set; }
public string StartTime { get; set; }
public string EndTime { get; set; }
}
if each entry is going to be unique then make a compound primary key if you do not want to introduce an id. Make all the properties the primary key. This will be less efficient in DB terms than just creating an Id as the primary key though.
Someone answered and deleted his answer afterwards, so I can't mark it as the right answer, but the solution was to add [ComplexType] to my class :
[ComplexType]
public class OpenHours
{
public DayOfWeek Day { get; set; }
public string StartTime { get; set; }
public string EndTime { get; set; }
}
Links for additional information on Complex Types:
Associations in EF Code First: Part 2 – Complex Types
Entity Framework Complex Types - EF Designer
Suppose I have multiple unrelated object (classes) where I can not get common abstract class for (and therefore unique primary key for all such classes). I would also like to apply list of common objects to all such classes (say for example list of Comments). My first approach would be something like this:
public class Comment
{
public int Id { get; set; }
public string CommentContent { get; set; }
public virtual ICommentable CommentableObject { get; set; }
}
public interface ICommentable
{
ICollection<Comment> Comments { get; set; }
}
public class Page : ICommentable
{
public int Id { get; set; }
public string PageContent { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Post : ICommentable
{
public int Id { get; set; }
public string PostContent { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
What EF code-first did, was creating single Comments table, with multiple nullable Foreign Keys (one for each related class) : Page_Id, Post_Id.
One of alternatives is to have separate Comments table for each class: PageComments, PostComments.
Is there any other more elegant solution to this common scenario ? Which one of two alternatives above is better ?
We're talking about an IsA (Is-A, Is A) relationship here. Your options are here: http://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph
they are essentially ways of mapping an is-a inheritance/implementation to an is-a database relationship. The second option (Table per Type) seems to do that in a way that is normalized, the third option I'm unfamiliar with.
In your case, if you're sure there will only be 2 ICommentable classes, you may want to stick with what you have. This will also allow you a bit more flexibility if you change your mind about them both implementing the same interface. Normalize 'till it hurts, denormalize 'till it works.
All,
I have read this article:
How AspNet Identity with my model
where the ApplicationUser has an additing property of
public int AddressId { get; set; }
that is a new property on the ApplicationUser.
But what I am wondering is what if I have a custom entity of my own and I want it to have a property that relates to the Application user:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public ApplicationUser CurrentlyBorrowedBy { get; set; }
}
or
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public Guid CurrentlyBorrowedBy { get; set; }
}
The reason I might want to do this is so I can call a method like GetAllBooksBorrowedForUser(userid) for example.
Do I set the properties type to ApplicationUser as show above
or
use a Guid because the DataType of the Id on ApplicationUser is a Guid
or
is this the completely wrong way to do it?
All suggestions welcome.
Note: this is just psuedo code as I just want an understanding of this before I dive into my project.
thanks
Russ
From what I know, it should be:
public int CurrentlyBorrowedByID { get; set; }
public virtual ApplicationUser CurrentlyBorrowedBy { get; set; }
Where the ApplicationUser instance allows you to easily navigate
All,
Of course after finishing writing my question I found the answer right in front of me.
The sample and blog post written by pranav rastogi here:
http://blogs.msdn.com/b/webdev/archive/2013/10/20/building-a-simple-todo-application-with-asp-net-identity-and-associating-users-with-todoes.aspx
explains how do do what I am talking about.
Still, feel tree to comment as there is more than one way to skin a cat.
thanks
Russ
I have two tables Articles and Events and I'd like to provide a commenting functionality to the users on both types. The hard part is that I'd like to use a navigation property that returns the comments belonging to the given EF object.
public class Article
{
public virtual ICollection<Comment> Comments { get; set; }
/* more properties here */
}
public class Event
{
public virtual ICollection<Comment> Comments { get; set; }
/* more properties here */
}
public class Comment
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CommentId { get; set; }
public string Msg { get; set; }
public DateTime SentAt { get; set; }
public int TargetId { get; set; }
public CommentTargeType TargetType { get; set; }
}
public enum CommentTargeType
{
Article,
Event
}
As you see the TargetId would be the id of the Article or of the Event and the TargetType is to distinguish these two types.
So, is there any way to do this? Or would it be better to create an ArticleComments and an EventComments type instead?
Your current design is essentially using the same field in your object to be a foreign key into 2 tables. I would advise against that because the database won't be able to force any constraints or do integrity checks.
You can add two int? fields, one called ArticleId and one called EventId to accomplish what you want. Since the types are int? they will be nullable fields in the database.
I would even go one step farther and use the ForeignKey attribute so that EntityFramework knows about this and creates the foreign keys for you.
[ForeignKey("Article")]
public int? ArticleId { ... }
public virtual Article Article { get; set; }
[ForeignKey("Event")]
public int? EventId { get; set; }
public virtual Event Event { get; set; }