C# Complex Property Setter option - c#

I have an ASP.Net MVC 5 (C#) application and I'm giving my users the ability to like posts and comments.
for this I have a Model called Likes with the following Properties:
public class Like
{
public Like()
{
this.CreatedUTC = System.DateTime.UtcNow;
this.isActive = true;
}
public long id { get; set; }
public string UserID { get; set; }
public bool isActive { get; set; }
public LikeType Type { get; set; }
public DateTime CreatedUTC { get; set; }
}
Type is an enum and it can be either Comments or Posts. I've also added the following Navigation Property to both Post Model and Comment Model:
public virtual ICollection<Like> Likes { get; set; }
My question is, can I have a setter function in the above line of code where it would automatically set Comments and Posts for the Like type? I know I can use the Value variable in the Setter but using Google I couldn't find how to use it for complex types as I have above (Like).
I'm sure this would be a better way of doing this than in the repository manually set that enum every-time I'm going to save a like.
UPDATE:
Seeing how we're starting a nice little conversation about this Questions, I will throw another alternative in the mix.
How about two Tables with a base class of Like, one CommentLikes and the other PostLikes Seeing that the size of this table will grow really fast, I'm thinking separating them would possibly be a good thing, Right?

I'd rather drop the "LikeType" and either have Comment and Post entity in the Like entity and distinguish by one of them being null or introduce two new entities
public class CommentLike
{
public Comment Comment { get; set; }
public Like Like { get; set; }
}
which holds a comment and a like and PostLike which holds a Post and a Like. The Comment then looks like this
public Comment
{
public virtual ICollection<CommentLike> { get; set; }
}
Another alternative is to create separate tables for comment and post likes. While what you ask for is definitely doable I would recommend more verbose but simpler solution which will result in code that is easier to maintain and has less bugs. Is there any specific reason you want to have a LikeType property?

I had same problem but didnt encounter an easy way.
class Post{
public virtual ICollection<Like> Likes {set;get;}
}
class Comment{
public virtual ICollection<Like> Likes {set;get;}
}
Then:
class Like{
//....
}
You dont need a bi-directional relationship. Do you have a case where you need to query Likes table? and if you do, you will have to manage parsing it as ENUM somewhere which can be an extension method.
EF will create Post_Id and Comment_Id implicityly in your table design. You wont be able to query it but you wont need to. IN my experience i never needed to.

My question is, can I have a setter function in the above line of code
where it would automatically set Comments and Posts for the Like type?
I assume you are using T4 template or the classes that were generated by EF are partialthen you can extend it by creating another partial class and a wrapper property for Likes
// Backing field
private ICollection<Like> _likesWrapper;
public ICollection<Like> LikesWrapper {
get {
// Lazy loading
if(_likes == null)
{
// Just create a new list or load it from the database.
_likes = new List<Like>();
}
return _likes;
}
set {
foreach(var val in value)
{
//Set the comment and posts
}
Likes = value;
}

Related

How do I 'inherit' a class properties to use with Entity Framework

I want to add a new property on my class, make it strongly typed so I can use it in my views and controllers, I've tried to inherit the properties, but Entity Framework or C# throws me errors...
I have this class:
public class Patient
{
public int Id { get; set; }
public string Message { get; set; }
public string FirstName { get; set; }
.....
}
which has a lot more properties in it, but shortened here.
I have a razor view, which is uses 'Patient' as it's model
using model Project.Models.Patient
So I had completed my view (or so I thought) and was asked to add functionality in the view. The functionality is to send a POST using a form of a 'Message' (a simple textarea in html). I've already got all the details I want, but this new 'Message'
So I thought, because I don't want this field in the database I could add it like this:
public class Patient
{
public int Id { get; set; }
public string Message { get; set; }
public string FirstName { get; set; }
[NotMapped]
public string Message { get; set; }
.....
}
But I'm not a fan of this, it doesn't relate to the Patient in any other way.
So I thought I could change my model in razor to something like this:
#model Project.Models.DTOs.PatientMessage
and inherit the Patient class and all it's properties (so I don't have to retype and copy past the fields again) and the new PatientMessage class would look like this:
public class PatientMessage : Patient
{
public string Message { get; set; }
}
But when I refresh my application, I receive a message stating the Application Database Context has changed, and I have to update this. I don't want to update my database, and I can't really see why I need to, it's an extra field which I don't want to include in my database.
So then I decided to make this class an 'abstract' class
public abstract class PatientMessage : Patient
{
public string Message { get; set; }
}
When I refreshed my page this time, I saw no need to update the Database, great I thought, and when I went near a page where the model was
#model Project.Models.Patient
I received this message
The abstract type 'Project.Models.DTOs.PatientMessage' has no mapped descendants and so cannot be mapped. Either remove 'Project.Models.DTOs.PatientMessage' from the model or add one or more types deriving from 'Project.Models.DTOs.PatientMessage' to the model.
MY QUESTION
Can I include this one field, without placing it on the Patient class, ideally without having to update models in my razor views, or would I have to change the models in the views and controllers and update the information to include the message and map all the details from a 'PatientMessage' to a 'Patient'
Please let me know if you need any further information.
Regards

Hide model classmember in controller in C# Web API?

I am trying to learn and understand C# Web API and MVC.
I understand the simple tutorials where one has a simple Product or Person class as a Model and then makes a CRUD Controller to make use of the model.
But I need it to be a bit more complex and can't figure it out.
I have following Model:
public class PersonModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public DateTime LastUpdated { get; set; }
}
Same as the table in my database. The LastUpdated column has a default constraint: (GETUTCDATE())
I am not interrested in exposing LastUpdated in my POST methods in PersonsController:
public void PostPerson(PersonModel person)
{
// Upload person to database
}
Because then one could insert an invalid datetime in LastUpdated - or I have to manuel set LastUpdated in my business logic, but why not just let my SQL server do it?
Anyway to hide LastUpdated in PostPerson?
As a sidenote I would like to be able to show LastUpdated in my GetPerson method.
How is that possible?
When you implement a property in a class, you can specify different access modifiers for the get vs. set accessors.
This is true whether you are implementing the property yourself, or using an automatic property.
Different combinations of access modifiers include:
get/set both public – client can read/write property value
get/set both private – client has no access to the property
get public, set private – property is read-only
get private, set public – property is write-only
// get/set both public
public string Name { get; set; }
// get/set both private
private string SecretName { get; set; }
// public get => read-only
public string CalcName { get; private set; }
// public set => write-only
public string WriteOnlyName { private get; set; }
You could create a custom DTO as a view model for the POST operation on this controller. This would be additionally handy because you probably also don't want the client to supply the Id value either (I assume). Something like this:
public class PersonDTO
{
public string Name { get; set; }
public string Title { get; set; }
}
This would be the input for the controller action:
public void PostPerson(PersonDTO person)
{
// Upload person to database
}
Then in the code you'd create a new PersonModel to add to the data context. Something like:
using (var db = new MyDataContext())
{
var newPerson = new PersonModel
{
Name = person.Name,
Title = person.Title
};
db.Persons.Add(newPerson);
db.SaveChanges();
}
(Or perhaps create a kind of translation method on the DTO which returns an instance of the model, acting as a sort of factory method and putting the logic in the object rather than in the controller.) This way the client isn't providing an entire PersonModel instance, just an object which describes the creation of that instance. The GET operation can still return the full PersonModel.
When building an API (using WebAPI, for example) it can often be really useful to fine-tune the inputs and outputs like this. And such custom DTOs/ViewModels really come in handy, albeit at the cost of slightly more code by creating essentially a translation layer to the backing models.
One tool I've found particularly handy in determining where in the API I need to tweak things is when using Swagger to generate my API docs. Looking through the generated docs, I may notice something which I don't want to be exposed. This is an indicator that I need to customize that API endpoint a little more so that the resulting docs are a little cleaner.
Try adding the exclude attribute above the property
[Exclude]
public DateTime LastUpdated {get; set(}

Create code from Pattern Graph

I got a graph from which I need to set some propery in objects. Im adding an example on which I will explain it better:
Assuming I have the following class:
public class Person
{
public int Account { get; set; }
public string BirthCity { get; set; }
public string Name { get; set; }
public Family Family { get; set; }
}
Each Person that gets to the DAL will automatically be assigned with Status according to that algorythm. My real problem is much more complex, but this example does explain it well I think.
The graph describes scenarios and I need to translate it to code. I want my solution to be as flexible to changes as possible. Ofcourse writing ifs and switch case is the easiest yet its not a good solution.
One idea I had was creating an Xml file suting the scenarios, but I think that it might not be that good.
Does anyone have any Ideas about this issue?

How to overwrite the implementation of a property created automatically in a partial class (T4 EF)?

I need to add some logic when setting property DateCreated.
Class is partial and created automatically by a T4 template.
public partial class GaAnalytic
{
public int AnalyticId { get; set; }
public System.DateTime DateCreated { get; set; }
}
I would like to know if is possible overwrite DateCreated implementation, or other possible solutions.
You simply cannot override in strict sense of the C# keyword a property in the same class. But there are workarounds.
Just until recently EF did not support enumeration properties so I needed to map those as integers and expose to our application as enumeration so basically I did kind of 'override' the property by introducing another that converted from int to enum and back.
For that unfortunately you need second name for the same value
//in generated partial
public DateTime DateCreatedDB { get; set; }
//in second file that contains your partial of that class
public DateTime DateCreated
{
get { // return converted DateCreatedDB }
set { // set DateCreatedDB to unconveted value }
}
From database and EF point of view there is a DateCreatedDB column that is mapped and processed. On the other hand you in your application use DateCreated.
If you use interfaces for your data model then it is a little bit simpler as you can provide explicit implementation for your interface property that does the conversion.
The other thing that you can do is to modify T4 template it is a bit of hassle to do it right as tools are not given out of the box, but it is doable and code would be cleaner.
You can overwrite using new keyword.
public class GaAnalyticEx : GaAnalytic
{
public new System.DateTime DateCreated { get; set; }
}

How to model entities to enforce a data models constraints at compile time?

I have the below data model that constrains ItemTypes with a subset of Events. Each ItemType has a valid set of Events, this is constrained in the ItemEvent table. For example, a Video can be { played, stopped, paused }, an Image can be { resized, saved, or shared }, and so on.
What is the best way to reflect this constraint in the Entity model so that I can get compile time assurance that an Event used is valid for a particular Item? Specifically, I am refactoring the AddItemEventLog method:
public void AddItemEventLog(Item item, string ItemEvent)
{
//
}
Obviously, this is a contrived example, just trying illustrate-- it allows a developer to pass in any ItemEvent string they desire. Even if I create an enumeration based on ItemEvent resultset, there isnt anything in the entity model to prevent a developer from passing in ItemEvent.Resize with an Item of type Video.
I have Item as the base class of Video, and I have tried to override an enum but now know that is not possible. I am less interested in checking for the validity of the Event at runtime, as I already will throw an exception when the DB raises a FK violation. I want to nip it in the bud at coding time if possible :)
Currently have classes modeled like this but open to any modifications:
//enums.cs
public enum ItemType : byte
{
Video = 1,
Image = 2,
Document = 3
}
//item.cs
public class Item : BaseModel
{
public int ItemId { get; set; }
public ItemTypeLookup.ItemType ItemType { get; set; }
public string ItemName { get; set; }
}
//video.cs
public class Video : Item
{
public string Width { get; set; }
public string Height { get; set; }
public string Thumb { get; set; }
}
I think that Code Contracts may be the only way to enforce something like this at compile time. Outside of compile time checks, writing unit tests to ensure the correct functionality is the next best thing!

Categories

Resources