Extend read-only C# Model with custom information - c#

I have some design-problems based on a lack of best pratices. I have a given Model containing some user information that I cant change as I have read-only access via OData-Service-Call. For example:
public class User
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set: }
}
Now I'm interested in adding some user-related information and save this information in a local database using EntityFramework. The final goal is to get an extended model like the following:
public class ExtendedUser
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set: }
public char FavoriteChar { get; set; } // <-- additional Information
}
Because there are many users available and only a very few do have this additional Information (FavoriteChar) it might be a good idea to create another model for saving only the addiotional information. Espcially some values (e.g. email) might change and I do not want to sync those values all the time. So I thought about such a model:
public class FavoriteCharAssignment
{
public int UserId { get; set; }
public char FavoriteChar { get; set; }
}
And now the tricky part: How do I merge those both models (User and FavoriteCharAssignment) to get the ExtendedUser[]?
Users[] users = odata.Users.ToArray();
using(db = new Context())
{
FavoriteCharAssignment[] assignments = db.FavoriteCharAssignments.ToArray();
/*
* Here I need some magic to merge those two arrays to an ExtendedUser[]
*/
}
In SQL-words: I need to do a kindof cross-join between an OData-Serice and the EntityFramwork. :)

Related

Automapper with dynamic values C#

I am a bit stuck, hoping for guidance. I have 2 tables, Header and Details. However, the details is a bit different than most, and allows for a way to dynamically store data.: Yes, I am aware that I can create a table storing the details in the standard fashion, but the nature of the app needs to be more dynamic on the database side. I also realize I will have to modify the DTOs for different incarnations of the app, but this model is what I need to accomplish.
public class Header
{
public int Id { get; set; }
public string HeaderName { get; set; }
public ICollection<Detail> Details { get; set; }
}
public class Detail
{
public int Id { get; set; }
public int HeaderId { get; set; }
public string FieldName { get; set; }
public string FieldProperty { get; set; }
}
I want to use the following DTOs:
public class DataForDisplayDto
{
public int Id { get; set; }
public string HeaderName { get; set; }
public string TaskToPerform { get; set; }
public string Location { get; set; }
}
public class DataForCreationDto
{
public string HeaderName { get; set; }
public string TaskToPerform { get; set; }
public string Location { get; set; }
}
The data would be stored in the details in this fashion:
{
"FieldName": "tasktoperform",
"FieldProperty": "Thing to Do"
},
{
"FieldName": "location",
"FieldProperty": "Over there"
}
I am trying to use the Automapper to make it so I can read and write to the database using the DTOs, but I think I may be trying something it can't do.
Is there an article or something that anyone knows about that can point me in the direction to go? Or even the right keywords to search online for it. Is it even possible?
I suppose if it is not possible, I will have to do things a bit more manually, which is the last option, I am just hoping to do this with Automapper.
Thanks!
How about deriving your DTO from a base class that uses reflection to generate a mapping, and cache that mapping.
This way your DTO need only inherit a base class.

Need help creating / using a collection within a class (C#, ASP.Net, MVC)

I'm trying to create a small web app that allows movies to be stored in a database. I have this Movie class:
public class Movie
{
public string Title { get; set; }
public string Synopsis { get; set; }
public List<string> Actors { get; set; }
public DateTime StartDate { get; set; }
public string MoviePic { get; set; } // path to image
public int RunningTime { get; set; } // in minutes
public string Trailer { get; set; } // youtube url
}
In my controller, I'm trying to create a movie using that class:
var jurassicPark = new Movie
{
Title = "Jurassic Park",
Synopsis = "Dinosaurs go crazy on an island.",
MoviePic = "jurassicLogo.jpg"
};
All of this works great, but I also want to add a Rating property, which can only be one of four strings representing an image of that rating sign. In other words, I don't want to just have a public string Rating property that can be any old string. I want to only have the choice between the four specific strings.
For example, I originally put this in the Movie class:
public class Rating
{
public string GRating = "g.jpg";
public string PgRating = "pg.jpg";
public string Pg13Rating = "pg13.jpg";
public string RRating = "r.jpg";
}
That didn't work, so I did some googling and tried this instead:
public enum Rating
{
GRated = "G.jpg",
PgRated = "PG.jpg",
Pg13Rated = "PG13.jpg",
RRated = "R.jpg"
}
That didn't work, either. I could call Movie.Rating.GRated in my controller, but I couldn't actually assign a rating to a movie. I tried adding public Rating Rating { get; set; } to the Movie Class, which seemed like it might allow me to add a Rating to my jurassicPark object in the controller, but it didn't like anything I tried (ex: Rating = Movie.Rating.Pg13Rated gave me a red squiggly).
It seems like this should be super simple, but I'm still somewhat new to ASP.Net and I'm having a lot of trouble with this one.
IMHO, The better solution is to create a separate lookup table to store the possible list of Ratings and have a foreign key in your movie table. On the database level this ensure that you are storing only one of those values(Referential integrity) even if your code fails to set the correct value
You can add additional properties to this lookup table. For example, a logo image for each rating, description for each rating etc.
public class Movie
{
public int Id {set;get;}
public string Title { get; set; }
public string Synopsis { get; set; }
public List<string> Actors { get; set; }
public DateTime StartDate { get; set; }
public string MoviePic { get; set; } // path to image
public int RunningTime { get; set; } // in minutes
public string Trailer { get; set; } // youtube url
public int RatingId {set;get;}
public Rating Rating { set;get;}
}
public class Rating
{
public int Id {set;get;}
public string Name {set;get;} ;
public string Description {set;get;} ;
public string LogoImageUrl {set;get;} ;
}
having said that, you can simply use an enum and store the string. but the above approach of a lookup table allows you to keep the additional properties for each rating items.

SimpleAuthentication - Storing User Specific Information To Database

I walked through a couple of tutorials and it seems they all leave out how you can utilize the logged in user to store information to a database. To help me illustrate my point, here is a model I've been using.
public class Note
{
public int ID { get; set; }
public int UserId { get; set; }
public string Text { get; set; }
}
This each user can write a note to the database. When I created the CRUD controller for this model I then updated the UserId property to the WebSecurity.CurrentUserId when doing Update/Create. Then when retrieving data back I filter the notes using Where in the linq expression. For some reason this just feels wrong.
Trolling through even more examples I came across someone doing it like so.
public class Note
{
public int ID { get; set; }
public virtual UserProfile User { get; set; }
public string Text { get; set; }
}
public class NoteDbContext : DbContext
{
public DbSet<Note> Notes { get; set; }
}
This looks a lot cleaner since the models are properly linked in C#. And wow, it actually builds! So now in my controller I will first get the user object from the database, then using a Where list their notes.
//First get the logged in user
var user = dbUser.UserProfiles.Where(x => x.UserId == WebMatrix.WebData.WebSecurity.CurrentUserId).First();
//Now get all their notes
var notes = db.Notes.Where(x => x.User == user);
However, this unexpectedly fails. So could someone please provide a sample of a good way to store the UserProfile object against other objects in the database? Basically, I just need a good example that shows now the UserProfile object can be linked to a Note object, and how you should properly query for Notes of a specific UserId.
The way you've defined your relationship, is that you are creating a one-to-one relationship between a Note and a User. I would expect that a user can have multiple notes, based on the query that you're having trouble with. Thus, in order to create a one-to-many between a user and their notes, you should create a collection on your UserProfile object. For instance,
public class UserProfile
{
...
public List<Note> Notes {get; set;}
}
...and to query, loading your Notes associated with that user,
var user = myUsers.Include(n=>n.Notes)
.Single(x => x.UserId == WebMatrix.WebData.WebSecurity.CurrentUserId);
Each user can have many notes, right? If so, change your class like this:
public class Note
{
public int ID { get; set; }
public int UserId { get; set; }
public string Text { get; set; }
public virtual UserProfile User { get; set; }
}
[Table("UserProfile")]
public class UserProfile
{
public UserProfile()
{
this.Notes = new HashSet<Note>();
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<Note> Notes{ get; set; }
}
Now, have users and notes connecting correctly. So, you can easily achive your goal like the following. You also don't need to struggle with WebMatrix.WebData.WebSecurity to get the current user! just use User.Identity.Name :
// ...
var notes = db.Notes.Where(x => x.User.UserName == User.Identity.Name).AsQueryable();

Custom model & client validation in MVC without data annotations

I have the below view models, which are used to represent a survey of questions, but they are structured into a more flattened grid to accommodate the default model binder.
// Main ViewModel for the Question View
public class SurveyRowList
{
...
public IList<SurveyRow> SurveyRowList { get; set; }
}
public class SurveyRow
{
public int QuestionId { get; set; }
public int? ParentQuestionId { get; set; }
public int SurveyId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string HelpInformation { get; set; }
public int RenderOrder { get; set; }
public SurveyRowType RowType { get; set; }
// Collection of the same answer control, 1 or more times
// for each line number
public IList<AnswerControl> AnswerControls { get; set; }
}
public enum SurveyRowType
{
QuestionGroup = 1,
Question = 2,
AnswerRow = 3
}
public class AnswerControl
{
public int Id { get; set; }
public int QuestionId { get; set; }
// a reference to the database record answer id
public int SurveyAnswerId { get; set; }
// control type of checkbox, dropdown, input, dropdown-additional-textbox, checkbox-group
public ControlType ControlType { get; set; }
// used to specify getting particular backing data for dropdown and checkbox-group
public ControlSpecificType ControlSpecificType { get; set; }
public string Description { get; set; }
public string HelpInformation { get; set; }
public int RenderOrder { get; set; }
public bool InLine { get; set; }
public int LineNumber { get; set; }
public AnswerControlValueType Value { get; set; }
}
public class AnswerControlValueType
{
// Default string backing value when possible
public string Value { get; set; }
// AnswerCheckBox
public bool CheckValue { get; set; }
// AnswerCheckBoxListModal
public string ModalName { get; set; }
// AnswerMultiSelectListValue
public int[] ListValues { get; set; }
// making the options list setter public so that this data can be re-attached after model binding
public IEnumerable<SelectListItem> ListOptions { get; set; }
// AnswerImageValue
public HttpPostedFileBase Image { get; set; }
// AnswerSelectListAdditionalValue
public string AdditionalInformation { get; set; }
}
Each SurveyRow is like a row of a table. Only the SurveyRowType.AnswerRow actually makes use of the AnswerControls list.
Example of their ordering when rendered by their type and order number can be seen in this image:
The image only shows a few simple examples, and there can be 1-10 lines per page to a max of 100, but I have also added a bit of explanation of some of the validation rules I would want to apply. There are more but these are just a few examples.
My problem is that I want to support this more complex validation but all the rules and error text are stored in a database, 1. because of user configuration, 2. because of existing localisation of the error text to support several languages.
I am looking for any suggestions that people might have to be able to support this.
I have seen things like Fluent Validation and I haven't delved too deep yet but so far I can't see any examples that would specifically not use Data Annotations on a model.. and also RequiredIf or DisabledIf or EnabledIf style validation rules that apply across a slightly more complex collection of objects.
I worked with MVC patterns in 2001 with servlets, and again in 2006, with a custom MVC framework implemented on top of ASP.NET, and looking at what people are doing nowadays makes me believe that most did not even care about looking at what MVC stands for, only that explain the models nonsense. A lot of developers working with ASP.net MVC, tend to bind the data that is coming from the client to models, but that is such a poor design. Models contain the data that should be forwarded to the template manager which is in most cases the Razor engine.
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
So my advice is: don't link the data that you get from the client into the models.
Get the data from the client, do a search on the Request object if it needs to
Validate the data (fluentvalidation)
apply the business rules
create the models
forward the models to the template engine
Also stopping using those crazy useless annotations.
My question was related to how I can support validating this complex model. I have since looked more at Fluent Validation and that has everything I need to do custom rules for a complex model, i.e. checking values across collections of objects within my model.

Many to Many self Join with Entity Framework Code First

Consider this Poco:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Fullname { get; set; }
}
Now i want to implement a follow technique where a user may follow other users so basically its self Many to Many relationship
problem is i don't know how exactly i can achieve this in Entity Framework Code-First ?
I thought of a linker Table :
public class UserFollow
{
public int Id { get; set; }
public int Follower { get; set; }
public int Following { get; set; }
public DateTime FollowDate { get; set; }
}
i want to be able to get All Followers and Following from every User Object?
This is quite simple using EF code-first as you only need the User POCO:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Fullname { get; set; }
public ICollection<User> FollowedUsers { get; set; }
}
The collection means that a User is related to other users.
PS: I noted you added a timestamp in your solution example. To achieve that you should still add the collection changing the generic type to whatever suits your needs.
Hope it helps.

Categories

Resources