How would a programmer add sample data to a Person class so it pre-populates the fields on the view?
Here is what I'm thinking but it doesn't work:
public class Person
{
private Boolean prepopulate = false;
public Person() { if (prepopulate) { Person(prepopulate); }}
public Person(Boolean prepopulate)
{
if (prepopulate)
{
this.prepopulate = prepopulate;
SampleData.Fill(ref this);
}
}
int Id {get; set;}
string Name {get; set;}
}
My create statement might look like this:
//
// GET: /Person/Create
public ActionResult Create()
{
Person person = new Person(prepopulate=true);
return View(person);
}
The fill would do something like this reference: link.
This is all you need to do to fix your problem, whenever a new entity is created it will automatically give it the properties inside the public Person() constructor. I would highly recommend reading up on the constructors and how they work so you understand it better and understand why it works.
public class Person
{
int Id {get; set;}
string Name {get; set;}
public Person()
{
Name = "Sample";
}
}
Related
I've got a model that represents a joint table (with payload) in my database:
public class UserHasCar
{
// Foreign keys
[Key, Column(Order = 0)]
public string ApplicationUserId { get; set; }
[Key, Column(Order = 1)]
public int CarId { get; set; }
// Navigation properties
[Required]
public virtual ApplicationUser ApplicationUser { get; set; }
[Required]
public virtual Car Car{ get; set; }
// Additional fields
public int YearsRidden { get; set; }
}
public class Car
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<UserHasCar> UserHasCars { get; set; }
}
public class ApplicationUser : IdentityUser
{
public int BirthYear{ get; set; }
public virtual ICollection<UserHasCar> UserHasCars { get; set; }
}
I have a form that includes multiple select boxes, and upon submitting I want to clear out all records related to that user who submitted the form in the UserHasCar table and replace them with the new updated information. I'm getting a An entity object cannot be referenced by multiple instances of IEntityChangeTracker. because I am doing something wrong, but I don't see where I am using more than one context. This code happens in my controller:
public ApplicationUser GetCurrentUser()
{
return UserManager.FindById(User.Identity.GetUserId());
}
public string GetUserId()
{
string id = User.Identity.GetUserId();
var user = UserManager.FindById(id);
return user.Id;
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ManageCars(FormCollection form)
{
string id = GetUserId();
// Remove cars records with my id from database
var queryCars = (from m in db.UserHasCars where m.ApplicationUserId == id select m).ToList();
foreach (var record in queryCars )
{
// Could the problem be here?
db.UserHasCars.Remove(record)
}
// Add user-submitted cars to the database
string carval = form["Cars[0]"];
Car car = (from m in db.Cars where m.Name == carval select m).First();
int carid = car.ID;
// I get the abovementioned title error here
db.UserHasCars.Add(
new UserHasCar()
{
ApplicationUser = GetCurrentUser(),
ApplicationUserId = id,
Car = car,
CarId = carid,
YearsRidden = 0
}
);
db.SaveChanges();
}
I've seen many SO posts, but can't seem the problem as why my code doesn't want to save the new database entries.
EDIT
The solution was to remove the call to get the user and replace it with a query. Why? I was making database conflict errors by having both types of calls (database and DataManager calls in the same controller action). I ended up using a modified GetUser() function instead of GetCurrentUser()
Code:
public ApplicationUser GetUser()
{
// As opposed to:
// UserManager.FindById(User.Identity.GetUserId())
// We make a database call to grab our user instead
// So we don't get database context conflicts by using UserManager
string id = GetUserId();
return db.Users.Where(m => m.Id == id).First();
}
public string GetUserId()
{
return User.Identity.GetUserId();
}
// snip
// in ManageCars(FormCollection form)
ApplicationUser user = GetUser();
// snip
var newRow = db.UserHasCars.Create();
newRow.ApplicationUser = user;
// snip
db.UserHasCars.Add(newRow);
Try removing this line:
ApplicationUser = GetCurrentUser(),
from your object instantiation when adding.
Entity populates this object automatically once you set the foreign key ApplicationUserId. If UserManager.FindById(User.Identity.GetUserId()) uses a different db context that's where your exception is coming from.
Also to save yourself further trouble down the line, you should always call db.SaveChanges() in between the two operations. If you're worried about the atomicity of the db operation, just wrap the whole thing in a Transaction.
And when adding new rows to a table, I usually prefer to use something like:
var newRow = db.SomeTable.Create();
newRow.SomeColumn1 = "something";
newRow.SomeColumn2 = 5;
db.SomeTable.Add(newRow);
db.SaveChanges();
In order to delete entries from UserHasCars you need to change their EntityState to Deleted.
Example:
foreach (var record in queryCars )
{
db.ObjectStateManager.ChangeObjectState(record, EntityState.Deleted);
}
Hope this will fix your issue.
class Feed : Entity {
public Guid Id {get;set;}
public string FeedText {get;set;}
public ISet<FeedUser> FeedUsers {get;set;}
public void AddFeedUser(User user) {
FeedUsers.Add(user.Id);
}
public void RemoveFeedUser(User user) {
FeedUsers.Remove(user.Id);
}
public void MarkUserAsReadFeed(User user)
{
var feedUser = FeedUsers.Find(u=>u.Id == user.Id);
feedUser.Read();
}
}
class FeedUser : ValueObject {
public Guid UserId {get;private set;}
public bool IsRead {get;private set;}
public DateTime? ReadDate=null {get;private set;}
public void Read(){
IsRead = true;
}
public void UnRead(){
IsRead = false;
}
}
In this case FeedUser is Value Object or Entity? I'm confuse because FeedUser no need identity but not 100% immutable (IsRead property changable)
A Feed have a lot of FeedUser. At NHibernate, should I load all FeedUsers property (Lazy Load or Eager loading) for add new FeedUser or remove from list?
Question1: The FeedUser is not a value object since it's mutable and has it's life cycle(but binding with the Feed's lifecycle). In this design, it's a local entity(userId as local identifier).
Question2: I'm afraid you have to load all FeedUsers first.
Indirect answer: If you think it's awkward, you may ask yourself what's the invariant to be protected? what about make FeedUser an aggregate?
class Feed : Entity {
public Guid Id {get;set;}
public string FeedText {get;set;}
public FeedUser AddFeedUser(User user) {
return new FeedUser(id, user); //sorry, I have to confess I'm not a .net guy.
}
}
class FeedUser : Entity {
public Guid id;
public Guid feedId;
public Guid UserId {get;private set;}
public bool IsRead {get;private set;}
public DateTime? ReadDate=null {get;private set;}
public void Read(){
IsRead = true;
}
public void UnRead(){
IsRead = false;
}
}
//FeedUserRepository is responsible for removeing FeedUser
I'm a complete noob to Fluent NHibernate, and I'm using the Query Object Pattern based on a recommendation. Which I'm also new to. I'll try to keep the code samples concise and helpful.
User class:
public class User {
public Guid ID { get; set; }
public string Name { get; set; }
}
Visibility:
public enum VisibilityType {
Anybody,
OwnersOnly,
Nobody
}
Car class:
public class Car {
public Guid ID { get; set; }
public VisibilityType Visibility { get; set; }
public ICollection<User> Owners { get; set; }
}
So I need to write a conditional restriction method for the query object. Return all cars that have VisibilityType.Public, but if a car has Visibility property value of VisibilityType.OwnersOnly, restrict the return to users who belong to that group.
Here's the current restriction method that I have working, but without the condition:
public class CarQueryObject
{
private User user { get; set; }
private const string OwnersProperty = "Owners";
private const string OwnersIDProperty = "Owners.ID";
public CarQueryObject RestrictToOwners()
{
// How do I add a conditional criteria here? Only restrict by owner
// if the QueryObject has VisibilityType.OwnersOnly? Note that it should
// *NOT* restrict VisibilityType.Anybody
CreateOwnersAlias();
Criteria.Add(Restrictions.Eq(OwnersIDProperty, user.Id));
return this;
}
public CarQueryObject JoinFetchOwned()
{
Criteria.SetFetchMode(OwnersProperty, FetchMode.Join);
return this;
}
public void CreateOwnersAlias()
{
Criteria.CreateAlias(OwnersProperty, OwnersProperty, JoinType.LeftOuterJoin);
JoinFetchOwned();
}
}
?_?
an idea to get shown cars
var carsShown = session.CreateCriteria<Car>()
.JoinAlias("Owner", "owner")
.Add(Expressions.Or(
Expression.Eq("Visibility", Visibility.Anybody),
Expression.Eq("Visibility", Visibility.OwnersOnly) && Expression.Eq("owner.Id", currentUser.Id)
))
.List<Car>();
Maybe it's simple but I'm stuck with it and I didn't find any answer on how it could be done. I have a parent entity User with a collection of child entities Operations. These two entities are just for UI so they are a kinf of views. Here is the pseudo code
public class User
{
public int Id {get; set;}
public IEnumerable<Operation> Operations {get; set;}
public int TotalSuccessfulAccesses {get; set;} // not mapped to the database
public int TotalFailedAccesses {get; set;} // not mapped to the database
}
public class Operation
{
public int Id {get; set; }
public int UserId {get; set; } // FK
public int NbSuccessfulAccesses {get; set; }
public int NbFailedAccesses {get; set; }
}
What I would like to do it's to get the User with TotalSuccesfulAccesses and TotalFailedAccesses initialized from the child collection in one round trip to the database.
For each user we should calculate Sum(Operation.NbSuccessfulAccesses) and Sum(Operation.NbFailedAccesse) and make a projection respectively to the User.TotalSuccesfulAccesses and User.TotalFailedAccesses.
I tried to play with multicriteria and several queries but I'm not satisfied with it. I would like to know if maybe there is a simple way to do it with projection or something other. Or maybe I missed something.
What would you recommend ?
Thanks in advance for you help.
I was able to get rid of the magic alias strings in the following way:
UserViewModel userView = null;
Add(Projections.Sum<User>(x => operations.NbSuccessfulAccesses).WithAlias(() => userView.TotalSuccessfulAccesses))
You probably need to separate your view models and your domain entities. I assume in your domain you have got a User class having a list of Operation and these entities are mapped accordingly.
You could then create a view model:
public class UserViewModel
{
public int UserId { get; set; }
public int TotalSuccessfulAccesses { get; set; }
public int TotalFailedAccesses {get; set;}
}
Using ICriteria you can create the following query:
var criteria = Session.CreateCriteria(typeof(User));
criteria.CreateAlias("Operations", "operations", JoinType.LeftOuterJoin);
var projList = Projections.ProjectionList();
projList.Add(Projections.GroupProperty("Id"));
projList.Add(Projections.Sum("operations.NbSuccessfulAccesses"), "TotalSuccessfulAccesses");
projList.Add(Projections.Sum("operations.NbFailedAccesses"), "TotalFailedAccesses");
criteria.SetProjection(projList);
criteria.SetResultTransformer(Transformers.AliasToBean<UserViewModel>());
var ret = criteria.List<UserViewModel>();
Create the view model according to your needs and add any properties in the projection list accordingly.
Hope that helps.
Thanks to Kay, I came up with the following translation :
Operation operations = null;
var q = GetSession().QueryOver<User>().Where(u => u.AccessKeyId == accessKeyId)
.Left.JoinQueryOver(x => x.Operations, () => operations)
.Select(Projections.ProjectionList()
.Add(Projections.Sum<User>(x => operations.NbSuccessfulAccesses), "TotalSuccessfulAccesses"))
.Add(Projections.Sum<User>(x => operations.NbFailedAccesses), "TotalFailedAccesses"))
.TransformUsing(Transformers.AliasToBean<UserViewModel>()).List< UserViewModel >();
However I would like to know if there is a mean to get rid of the magic string "TotalSuccessfulAccesses" and "TotalFailedAccesses".
if I use something like that
UserViewModel userView = null;
Add(Projections.Sum<User>(x => operations.NbSuccessfulAccesses), () => userView.TotalSuccessfulAccesses)
NHibernate yields an error :
Could not find a setter for property 'userView.TotalSuccessfulAccesses' in class 'Domain.Query.UserViewModel'
which is not true because there is a setter for TotalSuccessfulAccesses' property.
Any ideas ?
Thanks
Suppose I have a table:
ID(pk) | HOME_EMAIL | WORK_EMAIL | OTHER_EMAIL
-------------------------------------------------
and the .NET classes
class A {
int id;
List<MyEmail> emails;
}
class MyEmail {
string email;
}
I suppose there's no way to map those (multiple) columns into a single collection in NHibernate, or is there? :)
It's come to a point that we'd rather not tinker with the database schema anymore so we can't do much with the database, if that helps.
I would suggest working with Interfaces so you could do something like this
interface IUser
{
int Id {get; set;}
IEnumerable<string> Emails {get;}
}
class MyUser : IUser
{
public int Id {get; set;}
public IEnumerable<string> Emails
{
get
{
return new [] { SomeEmail, SomeOtherEmail };
}
}
public string SomeEmail { get; set; }
public string SomeOtherEmail { get; set; }
}
Your application can expect an IUser and not care where we got the list of emails. You would map MyUser in NH, while the application does not (and should not) care about the actual implementation.
If it doesn't have to be a collection, but could be a custom type instead, say EmailAddresses which contains three properties:
public class EmailAddresses
{
public virtual string Home { get; set; }
public virtual string Work { get; set; }
public virtual string Other { get; set; }
}
You could use a component to map the three columns into the three properties of this object as a single property on the parent:
public class MyUser
{
...
public virtual EmailAddresses { get; set; }
}
You can map these in NHibernate using components or if you're using Fluent NHibernate with the ComponentMap<T> classmap (automapper can't do components).
There is a feature that's very close to what you want, <dynamic-component>
The documentation at http://nhibernate.info/doc/nh/en/index.html#components-dynamic should get you started.