Model - field based on values in other fields - asp.net-mvc

I've literally just started learning MVC.
I have created a simple model:
public class StaffMember
{
public Guid StaffMemberId { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string Team { get; set; }
public virtual ICollection<Observation> Observations { get; set; }
}
Now I have decided that I want to include a drop down list of all StaffMembers on the create page for the observation records. I manage to do that with the following code:
#Html.DropDownListFor(o => o.StaffMemberId,
new SelectList(Model.StaffMembers,
"StaffMemberId",
"Forename",
Model.StaffMemberId),
"-- Select Staff Member --")
This works perfectly, although, you'll notice that I can only include a single field, "Forename".
I want the drop down list to show the staff member's full name. I tried concatenating the fields manually i.e. "Forename" + " " + "Surname" but that threw and exception about there being no such field as "Forename" + " " + "Surname".
My question is this - is it possible to add to my model some sort of property that is simply based on the value of two existing properties. Something like:
public class StaffMember
{
private string _fullName;
public Guid StaffMemberId { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string Team { get; set; }
public virtual ICollection<Observation> Observations { get; set; }
public string FullName
{
get
{
return _fullName;
}
set
{
value = this.Forename + " " + this.Surname;
_fullName = value;
}
}
}
I tried the above, but when populating my database (I'm using entity model code first), that field always has a value of null, even though the field shows the correct value when debugging.
I'm using the following to auto populate the db with some test data:
var staff = new List<StaffMember>
{
new StaffMember
{
Forename = "Bob",
Surname = "Hope",
StaffMemberId = Guid.NewGuid(),
Team = "Test"
},
new StaffMember
{
Forename = "Stan",
Surname = "Laurel",
StaffMemberId = Guid.NewGuid(),
Team = "Test"
}
};
staff.ForEach(s => context.StaffMembers.Add(s));
context.SaveChanges();
Any pointers would be really useful here, especially if I am approaching this in completely the wrong way!

Yes, you're really close with the FullName property.
public class StaffMember
{
public string FullName
{
get
{
return this.Forename + " " + this.Surname;
}
}
}
No need for a private _fullName since you only need to get the values of Forename and Surname. And you don't need a set since you won't set a value back to this model using FullName

You can make this change in your Repository where you add Staff_Member
public void AddStaff(Staff_Member sm)
{
String fullName = sm.Forename.ToString()+" "+sm.Surname.ToString();
sm.FullName = fullName;
_context.Staff_Member.Add(sm);
}
However, you need to have set method for FullName as well in your Staff_Member model.

Related

Model to concatenate strings get overwritten

New to MVC here, so apologies for what may be a silly question.
I have created some database-first entity framework models for an existing database, which is working great. One of the models pulls out a first and last name from the database, which i can reference in my code.
namespace manage.mysite.com.DataModels
{
using System;
using System.Collections.Generic;
public partial class UserProfile
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public UserProfile()
{
this.webpages_Roles = new HashSet<webpages_Roles>();
this.Property_Info = new HashSet<Property_Info>();
}
public string Email { get; set; }
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string TelNumber { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<webpages_Roles> webpages_Roles { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Property_Info> Property_Info { get; set; }
}
}
I then added another string under lastName, to tie them together:
public string FullName {
get
{
return FirstName + " " + LastName;
}
}
This works absolutely perfectly, except the problem that every time i need to update the model from the database, this obviously get's overwritten. How do i stop this from happening?
Use NotMapped attribute:
[NotMapped]
public string FullName {
get
{
return FirstName + " " + LastName;
}
}
That is using Data Annotations. If you prefer Fluent Api then it would be this way:
modelBuilder.Entity<UserProfile>().Ignore(t => t.FullName);
Update
Use a partial class to avoid losing your custom properties every time you update your model from the DB:
public partial class UserProfile
{
[NotMapped]
public string FullName {
get
{
return FirstName + " " + LastName;
}
}
}

Constructor for object model similar from entity

I'm trying my best to follow some MVC guidelines and for now, I have created a model with the fields I need from an entity I have. I have created the following Model class:
public class PersonStyle
{
public string Name { get; set; }
public int? Age { get; set; }
public string City { get; set; }
public string Style { get; set; }
}
My Entity is sometihng like:
public class PersonOE
{
public string Name { get; set; }
public int? Age { get; set; }
public string City { get; set; }
}
Im trying to build a constructor for the following:
PersonON personBus = new personBus();
List<PersonStyle> personStyleList = new List<PersonStyle>(personBus.getPeople()); //getPeople(); returns a PersonOE list
For this all, I need suggestions on how to create the PersonStyle constructor that will put "null" into the only different variable from the PersonOE model.
All you need to do is use LINQ to generate your properties. Though, adding your Style to each of them could get a little harder to deal with, but you haven't given any input on where they're coming from. This is a quick and easy way to convert from your data to model objects.
List<PersonStyle> personStyleList = personBus.GetPeople()
.Select(p => new PersonStyle {
Name = p.Name,
Age = p.Age,
City = p.City
});

Bind Entity object to ListBox with multiple fields for DisplayMember

I am using Entity Framework 6 to model a list of clients from a database. I am binding the collection successfully to a listbox. What I can't figure out how to do is to use multiple fields from the object to bind to the DisplayMember property of the Windows Form ListBox.
This works ...
myLsiTBox.DataSource = context.Clients.ToList();
myLsiTBox.DisplayMember = "CompanyName";
myLsiTBox.ValueMember = "id";
This fails ...
myLsiTBox.DataSource = context.Clients.ToList();
myLsiTBox.DisplayMember = "CompanyName" + "-" + "LastName" + " - " + "FirstName";
myLsiTBox.ValueMember = "id";
How do I go about displaying the content from multiple fields in the ListBox?
If this was your client:
public class Client
{
public string CompanyName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
You could make a ClientViewModel and then bind the list box data source to the list of ClientViewModels and set the DisplayMember to "FullDetails".
public class ClientViewModel
{
public string CompanyName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullDetails { get { return string.Format("{0}-{1} - {2}", this.CompanyName, this.LastName, this.FirstName)} }
public ClientViewModel(Client c)
{
this.CompanyName = c.CompanyName;
this.FirstName = c.FirstName;
this.LastName = c.LastName;
}
}
..or just add the FullDetails property to the orignal Client class if you can.

Need help on EF Code First Fluent Mapping Many To Many

I am developing an ASP.NET MVC4 application with EF Code First. I am having a many-to-many relationship among following classes. I have defined relationship using EF fluent api in my context class. But I am getting an error as it is trying to insert values into one of my master table involved in many-to-many relation. Can anyone help me correct my problem. Thanks in advance and for valuable time.I am using repository pattern and unit of work with Ninject as dependency injection.
Participant Class
public class Participant
{
[Key]
public int Id { get; set; }
[DisplayName("First Name")]
[StringLength(50, ErrorMessage = "First name cannot be more than 50 characters")]
[Required(ErrorMessage = "You must fill in first name")]
public string FirstName { get; set; }
[DisplayName("Last Name")]
[StringLength(50, ErrorMessage = "Last name cannot be more than 50 characters")]
[Required(ErrorMessage = "You must fill in last name")]
public string LastName { get; set; }
[Required(ErrorMessage = "You must indicate your full birthday")]
[DisplayName("Birthday")]
[DataType(DataType.DateTime)]
public DateTime BirthDate { get; set; }
[DisplayName("Gender")]
[Required(ErrorMessage = "You must select gender")]
public int Gender { get; set; }
public string Address { get; set; }
public int CountryId { get; set; }
public Country Country { get; set; }
[DisplayName("Zip code")]
[StringLength(10, ErrorMessage = "Zip code cannot be more than 10 characters")]
public string ZipCode { get; set; }
public string Mobile { get; set; }
public string PhotoUrl { get; set; }
public int UserId { get; set; }
public User User { get; set; }
public virtual ICollection<Interest> Interests { get; set; }
}
Interest Class
public class Interest
{
public int Id { get; set; }
public string InterestName { get; set; }
public virtual ICollection<Participant> Participants { get; set; }
}
DataContext
public class STNDataContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Participant> Participants { get; set; }
public DbSet<Country> Countries { get; set; }
public DbSet<Interest> Interests { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<SecurityQuestion> SecurityQuestions { get; set; }
public DbSet<Tour> Tours { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Participant>().
HasMany(p => p.Interests).
WithMany(i => i.Participants).
Map(
m =>
{
m.ToTable("ParticipantInterests");
m.MapLeftKey("ParticipantId");
m.MapRightKey("InterestId");
});
modelBuilder.Entity<User>().HasRequired(u => u.Role);
modelBuilder.Entity<Participant>().HasRequired(p => p.Country);
}
public virtual void Commit()
{
base.SaveChanges();
}
}
Controller Code
public virtual ActionResult Register(StudentRegisterViewModel studentRegisterViewModel)
{
if (ModelState.IsValid)
{
if (_userService.IsUserExists(studentRegisterViewModel.Participant.User) == false)
{
// Attempt to register the user
//WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
//WebSecurity.Login(model.UserName, model.Password);
studentRegisterViewModel.Participant.User.Username = studentRegisterViewModel.Username;
studentRegisterViewModel.Participant.User.Email = studentRegisterViewModel.Email;
studentRegisterViewModel.Participant.User.DateCreated = DateTime.Now;
studentRegisterViewModel.Participant.User.Id = 3;
studentRegisterViewModel.Participant.User.IsApproved = false;
studentRegisterViewModel.Participant.User.RoleId = 2;
studentRegisterViewModel.Participant.CountryId = 1;
var participant = new Participant
{
Id = studentRegisterViewModel.Participant.Id,
FirstName = studentRegisterViewModel.Participant.FirstName,
LastName = studentRegisterViewModel.Participant.LastName,
Interests = new Collection<Interest>()
};
var interests = new List<Interest>();
foreach (var interestItem in studentRegisterViewModel.SelectedInterests)
{
var interest = new Interest { Id = interestItem, Participants = new Collection<Participant>() };
interest.Participants.Add(participant);
interests.Add(interest);
}
studentRegisterViewModel.Participant.Interests = interests;
_participantService.CreatParticipant(studentRegisterViewModel.Participant);
//_userService.CreatUser(studentRegisterViewModel.Participant.User);
//TODO: Need to check if do we need to register the user and get him signed-in. If yes signing in implementation goes here.
var user = _userService.GetUser(studentRegisterViewModel.Participant.User.Username);
//Session["User"] = user;
//FormsAuthentication.SetAuthCookie(user.Username, false);
//Growl("Welcome", "Thanks for registering and welcome to Truck Tracker.");
//return RedirectToAction("Index", "Home");
}
}
//return RedirectToAction("Index", "Home");
// If we got this far, something failed, redisplay form
studentRegisterViewModel.Gender =
Enum.GetNames(typeof(Gender)).Select(
x => new KeyValuePair<string, string>(x, x.ToString(CultureInfo.InvariantCulture)));
studentRegisterViewModel.Interests = _interestService.GetAllInterests();
return View(studentRegisterViewModel);
}
Ideally it should insert Participant into Participants Table and Participant Interests in ParticipantInterests many-to-many table. But it is giving following error
{"Cannot insert the value NULL into column 'InterestName', table 'StudyTourNetworkDB.dbo.Interests'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}
It is trying to insert into Interests table which should not happen.
Participant ParticipantInterests Interests
Id Id Id
FirstName ParticipantId InterestName
LastName InterestId
This is how the tables in the database. The Interest table has a fixed set of records(Study, Job, Other,etc) which get displayed in Interested In dropdown. The registering participant can select multiple interested in options and when he clicks Sign Up button the Participant record will get saved in Participant Table and selected Interests in ParticipantInterests table.
Thanks
I was messing around with the same things the other day. Pain to get it figured out but here is a very basic example of a many to many I got working:
namespace Project.Models
{
public class Affiliate
{
public Affiliate()
{
Merchants = new HashSet<Merchant>();
}
public int Id { get; set; }
public ICollection<Merchant> Merchants { get; set; }
}
}
namespace Project.Models
{
public class Merchant
{
public Merchant()
{
Affiliates = new HashSet<Affiliate>();
}
public int Id { get; set; }
public ICollection<Affiliate> Affiliates{ get; set; }
}
}
and in the DbContext I did this:
modelBuilder.Entity<Merchant>().
HasMany(c => c.Affiliates).
WithMany(p => p.Merchants).
Map(
m =>
{
m.MapLeftKey("MerchantId");
m.MapRightKey("AffiliateId");
m.ToTable("MerchantAffiliates");
});
Update
I am trying to understand what you are looking to accomplish. It seems like this:
A participant can be interested in many things. Multiple participants can be interested in the same thing. If that is the fact I would consider changing the model so a participant has a list of interests, but the interests table, in my opinion, does not need a list of participants. If you wanted to retrieve say all participants with an interest in hiking you could just do something like this:
Context.Participants.ToList().Where(x => x.Interest.Name == "hiking");
Make sense?

RavenDB Transformations and Joining Simple Data

I was wondering if someone could help me understand RavenDB transformations as I cant seem to get them working correctly. I tried following Ayende's post but I am not able to apply it to my situation. I have two models, a UserModel and an UserAddressModel. The code is as follows
public class UserModel
{
#region Properties
public string Id { get; set; }
public string AccountId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public DateTime InsertDate { get; set; }
#endregion
}
and
public class UserAddressModel
{
public string Id { get; set; }
public string AccountId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zipcode { get; set; }
public float Latitude { get; set; }
public float Longitude { get; set; }
public DateTime InsertDate { get; set; }
}
I have my RavenDB Index set up like such.
public class UserDashboard_ByName : AbstractIndexCreationTask<UserModel>
{
public UserDashboard_ByName()
{
Map = users => from user in users
select new { user.UserName, user.AccountId };
TransformResults =
(database, users) => from user in users
let useraddress = database.Load<UserAddressModel>(user.AccountId)
select new
{ FirstName = user.FirstName,
LastName = user.LastName,
Address1 = useraddress.Address1,
Address2 = useraddress.Address2
};
}
}
and I am calling it with the following code
using (var session = DataDocumentStore.Instance.OpenSession())
{
//Get the AccountId
var userDashboard =
(from user in session.Query<UserModel, UserDashboard_ByName>()
where user.UserName == userName
select user).SingleOrDefault();
}
When I call the index, it returns a UserModel type, not the anonymous type that I am expecting. Also, I do not understand how I can call
let useraddress = database.Load<UserAddressModel>(user.AccountId)
when there is no specific relationship that has been specified in code or anywhere else.
Maybe someone can explain to me how I should be joining data in RavenDB? Some expanded documentation or a nudge in the right direction to understanding this better would be greatly appreciated. Thanks in advance.
The problem is inside your TransformResult function where you call database.Load<UserAddressModel>(user.AccountId). You can only load the UserAddressModel with its id, not by a property like AccountId.
You have to store the id of the UserAddressModel inside your UserModel if you want to do it that way. However, I wouldn't model it in that way. UserAddressModel doesn't have any meaning on itself, so it should probably be part of UserModel. As a rule of thumb, you generally want to have your aggregrate roots as documents and everything else inside them.
You need to create another model (a view model basically), such as UserWithAddressModel that includes the 4 properties you wish to return:
public class UserWithAddressModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
}
Then do your query like this:
var userDashboard =
(from user in session.Query<UserModel, UserDashboard_ByName>()
where user.UserName == userName
select user).As<UserWithAddressModel>().SingleOrDefault();
I think this is what you are looking for.
UPDATE:
Try like this:
var userDashboard = session.Query<UserModel, UserDashboard_ByName>()
.Where(x => x.UserName == userName)
.As<UserWithAddressModel>()
.SingleOrDefault();
UPDATE2:
Sorry, just looked again at what you are trying to do, it won't work like that. I thought you had a reference to your UserAddressModel in your UserModel (such as UserAddressId).
Why are you splitting the 2 models up in the first place if they are a 1:1 relation?

Resources