I am trying to do a blog project and I am using ado.net and I have 3-tier architecture.
In one classlibrary I have classes such as User and Comments:
public class User
{
public int userID{ get; set; }
public string userName{ get; set; }
public string userPassword { get; set; }
public string userMail{ get; set; }
}
public class Comments
{
public int ID { get; set; }
public int userID{ get; set; }
public string commentHeader{ get; set; }
public string commentContent{ get; set; }
}
I want to have a userName property in the Comments class. And I decided to create an open property in the Comments class.
Because I will show in these in a UI and I want to see the UserName along with UserID; for a better understanding about whom send this comment.
How I can create the following?
public string userName
{
get
{
return //(what I have to write here)
}
}
Multiple ways to do that.
Assuming you have list of Users in your code, you can query against that list and retrieve the UserName in your property. Something like:
public string userName
{
get
{
return userList.Single(r=>r.UserID == this.UserID).UserName; // Use single
//if you are sure there's going to be a single record against a user ID
//Otherwise you may use First / FirstOrDefault
}
}
Or
you may use composition and place User object inside the Comments class.
public class Comments
{
public int ID { get; set; }
public User user { get; set; } // User object in Comments class
public string commentHeader{ get; set; }
public string commentContent{ get; set; }
}
and then in your property you can simply do:
public string userName
{
get
{
return user.UserName;
}
}
public string userName
{
get
{
return userList.FirstOrDefault(user => user.userID == userID).userName;
}
}
where userList is
List<User> userList;
Related
I have an order object with its partial class containing changes history:
public class SomeOrder
{
public string SomeOrderNumber { get; set; }
public string Status { get; set; }
public IEnumerable<SomeOrderChangesHistory> ChangesHistory { get; set; }
}
public partial class SomeOrderChangesHistory
{
public string PropertyName { get; set; }
public string OldValue { get; set; }
public string NewValue { get; set; }
public DateTime DateTimeUtc { get; set; }
public string UserName { get; set; }
}
I'll be getting a list of SomeOrder and I want to filter out the orders if they are updated by api user.
The orders updated by api user will have one or more SomeOrderChangesHistory object in the ChangesHistory list with api user value in the UserName property (in SomeOrderChangesHistory object).
How do I accomplish this?
Based on #NetMage's excellent comment:
var ordersNotUpdatedByAPIUser = orders
.Where(o => !o.ChangeHistory.Any(ch => ch.UserName == "api user"))
.ToList()
It will filter out all the orders updated by api user which is exactly what I want.
Having an issue with projection and getting child objects to load. The following is simplified code to represent the logic I'm trying to implement, not the actual code.
public class TicketItem
{
public int TicketItemId { get; set; }
public string TicketReason { get; set; }
public Station Station { get; set; }
public TicketOwner TicketOwner { get; set; }
}
public class Station
{
public int StationId { get; set; }
public string Name { get; set; }
}
public class TicketOwner
{
public int TicketOwnerId { get; set; }
public Employee Employee { get; set; }
public Organization Organization { get; set; }
}
public class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Organization
{
public int OrganizationId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
public class CommonReasons
{
public int CommonReasonId { get; set; }
public string Reason { get; set; }
}
public TicketItem GetById(int id)
{
var query = from i in _dataContext.TicketItems
.Include("Station")
.Include("TicketOwner.Employee")
.Include("TicketOwner.Organization")
join r in _dataContext.CommonReasons on i.TicketReason equals r.CommonReasonId.ToString() into r1
from r2 in r1.DefaultIfEmpty()
where i.TicketItemId == id
select new TicketItem {
TicketItemId = i.TicketItemId,
TicketReason = r2.Reason == null ? i.Reason : r2.Reason,
Station = i.Station,
TicketOwner = i.TicketOwner
};
return query
.AsNoTracking()
.FirstOrDefault();
}
Most the code is self-explanatory. The part that is indirectly causing the trouble would be the relationship between TicketItem.TicketReason property (a string) and the CommonReasons entity. From the user interface side, the end-user has an input field of "Reason", and they can select from "common" reasons or input an adhoc reason. They original developer chose to have the TicketReason property contain either the key ID from the CommonReasons table (if the user selected from drop-down) or the adhoc reason typed in.
So, to handle this logic in the linq query, the only way I have found is to do a left join between TicketItem.TicketReason and CommonReasons.CommonReasonId, then use projection to modify the TicketReason column returning either the common reason text or adhoc text. If there is a different way to do this that would get me around the trouble I'm having with projection/include, I'm all ears.
For the "reason" logic, this query works, returning the proper text. The trouble is that none of the "grand-child" objects are returning, i.e. TicketItem.TicketOwner.Employee, TicketItem.TicketOwner.Organization. How do I get those objects to return also?
Changing the structure of the tables would be an absolute last resort, just based on the amount of code that would have to change. There are other spots in the code that are using the above logic but don't need the child objects.
Any help would be appreciated. Hope I've explained enough.
I have the following entity
public class Meeting
{
[Key]
public int Id { get; set; }
public Guid SubjectId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[Required]
public string Email { get; set; }
private ICollection<MeetingPeriod> _meetingTimes;
public virtual ICollection<MeetingPeriod> MeetingTimes
{
get { return _meetingTimes ?? (_meetingTimes = new Collection<MeetingPeriod>()); }
protected set { _meetingTimes = value; }
}
}
Got a few questions:
When I get a record I would like all the MeetingTimes to be sorted by default. Is this possible? I tried to return _meetingTimes.OrderBy but then I could not add any more meeting times as it was a readonly list.
I have added override Equals() to MeetingPeriod object. However when I try to compare MeetingTimes to an array of MeetingPeriod seems like the Equal() isn't getting called. What is going on here? It does get called correctly elsewhere. Seems like something to do with ICollection?
Revised entire post.
I'm trying to post the following JSON POST request via Fiddler:
{Username:"Bob", FirstName:"Foo", LastName:"Bar", Password:"123", Headline:"Tuna"}
However I'm getting this error:
Message "Cannot insert the value NULL into column 'Id', table 'xxx_f8dc97e46f8b49c2b825439607e89b59.dbo.User'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated." string
Though if I manually send a random Id along with the request then all is good. Like so:
{Id:"1", Username:"Bob", FirstName:"Foo", LastName:"Bar", Password:"123", Headline:"Tuna"}
Why does Entity Framework not generate and auto increment the Id's? My POCO class is as follows:
public class User
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public string Headline { get; set; }
public virtual ICollection<Connection> Connections { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<Phonenumber> Phonenumbers { get; set; }
public virtual ICollection<Email> Emails { get; set; }
public virtual ICollection<Position> Positions { get; set; }
}
public class Connection
{
public string ConnectionId { get; set; }
public int UserId { get; set; }
public virtual User User { get; set; }
}
public class Phonenumber
{
public string Id { get; set; }
public string Number { get; set; }
public int Cycle { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
Here is the controller method. When in debug mode and I send the request via Fiddler it breaks at db.SaveChanges(); and gives the error seen a bit above.
// POST api/xxx/create
[ActionName("create")]
public HttpResponseMessage PostUser(User user)
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, user);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = user.Id }));
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
What's wrong?
Solution
Change string Id to int instead and remove Data annotations. Renamed the Id to UserId, still following convention, and made changes where necessary in other POCO's to match up with the changes.
This is a guess :)
Is it because the ID is a string? What happens if you change it to int?
I mean:
public int Id { get; set; }
You have a bad table design. You can't autoincrement a string, that doesn't make any sense. You have basically two options:
1.) change type of ID to int instead of string
2.) not recommended!!! - handle autoincrement by yourself. You first need to get the latest value from the database, parse it to the integer, increment it and attach it to the entity as a string again. VERY BAD idea
First option requires to change every table that has a reference to this table, BUT it's worth it.
My database table for buildings stores the building type as a code. In a separate lookup table the description for that code is stored.
How should I design my ViewModel and where will I need to make the call to get the associated description value?
I sort of can see one option. I want to know if there is a better option.
BuildingViewModel
{
public string BuildingTypeCode { get;set;}
...other properties
}
Then in my view
code...
<p>#MyService.GetDescription(Model.BuildingTypeCode)</p>
...code
Am I incorrect in the way I am thinking? if I do the above I create a dependency in my View to the service?
Update 1
Working through some of the solutions offered. I seem to run into another issue. I can't access the constructor of each building directly...
public ViewResult Show(string ParcelId)
{
var result = _service.GetProperty(ParcelId);
var AltOwners = _service.GetAltOwners(ParcelId);
var Buildings = _service.GetBuildings(ParcelId);
ParcelDetailViewModel ViewModel = new ParcelDetailViewModel();
ViewModel.AltOwnership = new List<OwnerShipViewModel>();
ViewModel.Buildings = new List<BuildingViewModel>();
AutoMapper.Mapper.Map(result, ViewModel);
AutoMapper.Mapper.Map<IEnumerable<AltOwnership>, IEnumerable<OwnerShipViewModel>>(AltOwners,ViewModel.AltOwnership);
AutoMapper.Mapper.Map<IEnumerable<Building>, IEnumerable<BuildingViewModel>>(Buildings, ViewModel.Buildings);
ViewModel.Pool = _service.HasPool(ParcelId);
ViewModel.Homestead = _service.IsHomestead(ParcelId);
return View(ViewModel);
}
public class ParcelDetailViewModel
{
public IEnumerable<OwnerShipViewModel> AltOwnership { get; set; }
//public IEnumerable<ValueViewModel> Values { get; set; }
public IEnumerable<BuildingViewModel> Buildings { get; set; }
//public IEnumerable<TransferViewModel> Transfers { get; set; }
//public IEnumerable<SiteAddressViewModel> SiteAddresses { get; set; }
public string ParcelID { get; set; }
//public string ParcelDescription { get; set; }
//public int LandArea { get; set; }
//public string Incorporation { get; set; }
//public string SubdivisionCode {get;set;}
public string UseCode { get; set; }
//public string SecTwpRge { get; set; }
//public string Census { get; set; }
//public string Zoning { get; set; }
public Boolean Homestead {get;set;}
//public int TotalBuildingArea { get; set; }
//public int TotalLivingArea { get; set; }
//public int LivingUnits { get; set; }
//public int Beds { get; set; }
//public decimal Baths { get; set; }
public short Pool { get; set; }
//public int YearBuilt { get; set; }
}
My understanding is that the view model is meant for display ready data. I think the real problem here is putting model dependent logic into the view.
You can do your service lookup but keep that code in the controller. The view model should be considered display ready (save for some formatting).
class BuildingViewModel
{
public string BuildingTypeCode { get;set;}
...other properties
}
and then do the lookup before you render:
public ActionResult Building()
{
var typeCode = // get from original source?
var model = new BuildingViewModel
{
BuildingTypeCode = MyService.GetDescription(typeCode)
};
return View("Building", model);
}
Having come from a long line of JSP custom tags I dread having any code hidden in the view layout. IMO, that layer should be as dumb as possible.
I would recommend having a helper that does that, or a DisplayTemplate
public class ViewHelpers
{
public static string GetDescription(string code)
{
MyService.GetDescription(Model.BuildingTypeCode);
}
}
or
#ModelType string
#Html.DisplayFor("",MyService.GetDescription(Model.BuildingTypeCode));
More info on templates: http://www.headcrash.us/blog/2011/09/custom-display-and-editor-templates-with-asp-net-mvc-3-razor/
Both of these approaches introduce a dependency on your service but you can test/change them in one single place, instead of the whole application (plus the usage looks cleaner).