Model to concatenate strings get overwritten - asp.net-mvc

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

Related

MVC user store's IUserStore.Create fails if User has complex type

I'm using ASP.Net MVC 5 from Visual Studio. I want to create a user profile with complex types. I have modified the code of the User class in IdentityModels.cs file. Here's the code:
public class User : IUser
{
public User()
: this(String.Empty)
{
}
public User(string userName)
{
UserName = userName;
Id = Guid.NewGuid().ToString();
}
[Key]
public string Id { get; set; }
public string UserName { get; set; }
public string Phone { get; set; }
public string MobilePhone { get; set; }
public string Email { get; set; }
public string Address { get; set; }
}
I've also changed the views for this model. This works great without any problems. However, if I change the type of the Address property above to Address, meaning: public Address Address { get; set; } it fails.
I've tried using the virtual keyword for it but it didn't work. Please note that every time I create the database tables from scratch. Also, I checked the database and the information is inserted into database with correct foreign keys but I don't know what the problem is.
The code execution fails in the code below in the line await Users.Create(user) which returns false:
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
try
{
// Create a profile, password, and link the local login before signing in the user
User user = new User(model.UserName)
{
UserAddress = model.Address,
Email = model.Email,
Phone = model.Phone,
MobilePhone = model.MobilePhone
};
if (await Users.Create(user) &&
await Secrets.Create(new UserSecret(model.UserName, model.Password)) &&
await Logins.Add(new UserLogin(user.Id, IdentityConfig.LocalLoginProvider, model.UserName)))
{
await SignIn(user.Id, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError(String.Empty, "Failed to create login for: " + model.UserName);
}
}
catch (DbEntityValidationException e)
{
ModelState.AddModelError("", e.EntityValidationErrors.First().ValidationErrors.First().ErrorMessage);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Update:
Here's the Address class in case you wonder:
public class Address
{
public int ID { get; set; }
[Required]
public string Country { get; set; }
[Required]
public string City { get; set; }
[Required]
public string Street { get; set; }
[Required]
public string PostalCode { get; set; }
}
Update 2
Here's the image of the entered data:
It seems that this is a bug. I won't select this as the answer until it is absolutely proven. However when I change my controller's code from:
if (await Users.Create(user) &&
await Secrets.Create...
to:
await Users.Create(user);
if (await Secrets.Create...
it works without any problems. Seems to me that this should be a bug since I can load and edit the data perfectly.
This means that for some reason, even if the IUserStore.Create succeeds, it returns false in case the model is a complex type.
The problem that you have here (at least specific to changing Address to be an object rather than a string), is that your models aren't built correctly to relate them properly. Here is what you should be looking at.
public class User : IUser
{
public User()
: this(String.Empty)
{
}
public User(string userName)
{
UserName = userName;
Id = Guid.NewGuid().ToString();
}
[Key]
public string Id { get; set; }
public string UserName { get; set; }
public string Phone { get; set; }
public string MobilePhone { get; set; }
public string Email { get; set; }
// This FK doesn't need to explicitly be declared, but I do so as it helps me
// with the understanding of my structure a bit better.
public int AddressId { get; set; }
public Address Address { get; set; }
}
You also need to relate your Address back to your User class. I'm not sure how you want to do that, but, assuming that multiple people can live at the same address, you'll want a one-to-many relationship. (Right now, you receive an error because you don't specify the relationship.)
You have to do this in the Address model:
public class Address
{
[Key]
public int ID { get; set; }
[Required]
public string Country { get; set; }
[Required]
public string City { get; set; }
[Required]
public string Street { get; set; }
[Required]
public string PostalCode { get; set; }
// I would give this a better property name than "Users" but just putting
// this here for now.
public virtual ICollection<User> Users { get; set; }
}
This way, when your database builds, Entity Framework can now properly build the relationships (where, before, it couldn't tell what you intended - hence the error when you switch over to Address).
Of course, there may be other issues, but, this is one that would cause problems.

Lazy loading does not work in entity framework 5

I have defined a (poco?) class in my domain project:
public class Club
{
public Club()
{
ContactPersons = new HashSet<ContactPerson>();
}
public int Id { get; set; }
[Required]
[StringLength(64)]
public string Name { get; set; }
public virtual ICollection<ContactPerson> ContactPersons { get; set; }
}
public class ContactPerson
{
public virtual int Id { get; set; }
[StringLength(64)]
public virtual string FirstName { get; set; }
[StringLength(64)]
public virtual string LastName { get; set; }
}
In my MVC project I have my clubcontroller:
public ActionResult Create(CreateClubViewModel model)
{
Club club = new Club();
model.Initialize(club);
IClubDb clubDb = DependencyResolverHelper.IClubDbService;
clubDb.Create(club); // create club in db
}
public ActionResult Display(string domain)
{
try
{
IClubDb clubDb = DependencyResolverHelper.IClubDbService;
Club club = clubDb.Get(domain);
return View(club);
}
catch (Exception) // user is not logged iin
{
return View();
}
}
Finally, in my DB project I create and retrieve the club,
public Club Get(string name)
{
return DataContext.Clubs
//.Include(x => x.ContactPersons)
.Single(r => r.Name == name);
}
public int Create(Club club)
{
DataContext.Clubs.Add(club);
return DataContext.SaveChanges();
}
I have tried everything to get EF to lazy load the ContactPersons of my club object when I call the Get club in the Display method but ContactPersons has always a length of zero. However, if I eager load contact persons using the .include (I have commented this part out), then obviously ContactPersons contains a number of contacts.
I am not sure what I am doing wrong:
I have followed the guidelines for defining poco classes: http://msdn.microsoft.com/en-us/library/dd468057.aspx
I have a public parameter less constructor (but not protected constructor)
I have lazyloading enabled
I think I am missing a concept, the poco club class is also my domain entity which I insert into DB. What am I doing wrong? Whay I can't get lazy loading to work?
try
ContactPersons.ToList();
this will force all entities to be loaded.
see Entity framework, when call ToList() it will load FK objects automatically?
It seems that your LazyLoading performs when your dbContext is closed. So it will not load.
You use ContactPerson in view, am i right?
Did you forget to include the foreign key in your entity?
public class ContactPerson
{
public virtual int Id { get; set; }
[StringLength(64)]
public virtual string FirstName { get; set; }
[StringLength(64)]
public virtual string LastName { get; set; }
public int ClubId { get; set; }
[ForeignKey("ClubId")]
public virtual Club Club { get; set; } // if you need
}

How to tell EF that this field is in the conceptual model but not in the database

What's that attribute that you annotate your model property with to tell EF that please don't look for this field in the database and please don't map it to anything in the database. This is just in the conceptual model?
[NotMapped]
http://msdn.microsoftcom/en-us/library/system.componentmodel.dataannotations.schema.notmappedattribute.aspx
namespace Models
{
public partial class Foo
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
[NotMapped]
public string FullName { get { return FirstName + " " + LastName; } }
}
}

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?

Merging 2 models into 1 model in MVC

I don't know exactly the term of my problem, maybe thats the reason why I can not find such relevant issues in here.
Say, I have these models.
public abstract class Member
{
public string ID { get; set; }
public string Username { get; set; }
public int MemberType { get; set; } //1 if person; 2 if business
//public string MemberName { get; set; }
}
public class Person : Member
{
public string LastName { get; set; }
public string FirstName{ get; set; }
}
public class Business : Member
{
public string BusinessName { get; set; }
public string TaxNo { get; set; }
}
Right now, I do not have a problem on accessing those models using fluent API.
Now, what I want to achieve is to add a property on my Member class which is MemberName, which will be derived from LastName and FirstName property of Person class if MemberType is 1 and BusinessName of Business class if MemberTYpe = 2.
Is there an easy way to achieve this kind of thing?
Thanks
This can be done with a bit of abstract magic.
On Member have this:
public abstract string MemberName { get; }
Then on Person you override as:
public override string MemberName
{
get{ return FirstName + " " + LastName; }
}
on Business you override as such:
public override string MemberName
{
get{ return BusinessName; }
}
Now, any instanceof any class which inherits Member, when calling the MemberName property will return the right representation. This is all basic inheritance/OOP/Polymorphism whatever you want to call it.

Resources