New Model within ViewModel error on ID of 0 - c#

I have a viewmodel.
public class RegistrationViewModel
{
public RegisterModel Register { get; set; }
public Producer Producer { get; set; }
public IEnumerable<UserType> UserTypes { get; set; }
public IEnumerable<Producer> Producers { get; set; }
}
In the view, the user puts in their registration credentials and then selects a producer that they are a part of. They can also create a new producer on the page as well. However, when they do this my ModelState is invalid because the Producer doesn't have an ID field. This is a new Producer record and I shouldn't need to assign an ID before it is created in my database, right? ID is my identity field in SQL. I noticed that my scaffolded code for other domain models passes back an ID of 0 without any issues. Am I doing this correctly at all? Is this related to the viewmodel? Any help would be greatly appreciated.
Producer class:
public class Producer
{
public int ProducerID { get; set; }
public string Name { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Postal { get; set; }
public string Country { get; set; }
[DataType(DataType.PhoneNumber)]
public string Phone { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public string Website { get; set; }
public string CreatedBy { get; set; }
public DateTime CreatedOn { get; set; }
public string UpdatedBy { get; set; }
public DateTime? UpdatedOn { get; set; }
public Boolean Active { get; set; }
public virtual ICollection<Wine> Wines { get; set; }
}

I prefer to have a view model that is specific to the create action that doesn't have this key, although for reuse some do.
In that case, as you mentioned zero should be just fine. Ensure the key is written to the page though, check for a hidden field that has zero in it.

It is true that you do not assign an ID before inserting into the database. But the viewmodel is going to be invalid because it expects ProducerID to be filled. Try annotating the producerID field with
[Key]
public int ProducerID { get; set; }
If, however, the user selects an already existing Producer, and then that ProducerId is not associated with the registration, then you will obviously have an issue where the user is not associated with a Producer.

Related

EF Core - Save partial only if it does not exist

I have a model which has quite a few references governed by some foreign keys. I receive the entity as a JSON payload:
{
"Person": {
"Name": "John",
"Age": 24,
"Email": "john#contoso.com"
},
"RandomText": "This is my text"
}
Lets imagine this maps to a model which looks like this:
class Message {
public Guid PersonId { get; set; }
public Person Person { get; set; } // contains guid / name / age / email
public string Text { get; set; }
}
With an equivalent two tables, one for the person and one for the Message which has a reference to the person. These two are obviously 1 (Person) to many (Messages)
This illustrates my setup.
In order to automatically sync this I want to do some validations / checks on the data I receive, e.g: If the person exists, then attach that persons Guid, if the person does not exist, generate a Guid, save the person, then save the text.
My model is a little more complex, but follows the same pattern:
class Meeting {
public Guid LocationId { get; set; }
public Location Location { get; set; }
public string Subject { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public DateTime? BookedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
public bool WasCancelled { get; set; }
public bool WasNoShow { get; set; }
public bool WasAdhoc { get; set; }
public virtual ICollection<Extended> Extended { get; set; }
public bool WasEnded { get; set; }
public DateTime? EndedAt { get; set; }
public virtual ICollection<Attendee> Attendees { get; set; }
public virtual ICollection<MeetingPurpose> Purpose { get; set; }
public virtual ICollection<MeetingRoomMeeting> MeetingRooms { get; set; }
public Guid? DeliveryId { get; set; }
public virtual Delivery Delivery { get; set; }
}
MeetingRoomMeeting and MeetingPurpose are join tables which merely maps a many to many relationship:
public Guid MeetingRoomId { get; set; }
public virtual MeetingRoom MeetingRoom { get; set; }
public Guid MeetingId { get; set; }
public virtual Meeting Meeting { get; set; }
Again the point is, I have some data which may have been saved once already - I need to ensure if this is the case, and not save it again. Is there any pattern to this, or is it simplest to do it with raw queries, or maybe rip apart the class "Meeting" from the component classes and validate / save them individually?

Expanding classes using AutoMap

I have to import a set of data from one database to another with a somewhat different schema, and I'm considering using AutoMap. I could just write a bunch of SQL scripts, but I already have both databases in EF and I want to learn AutoMap ...
While many of the classes are similar, the problem I'm having is where the structure is really different. The target models were designed with several more layers of classes. Instead of flattening, I need to expand.
The target classes have the following properties:
public class Account
{
public int Id { get; set; }
public string Name { get; set; }
public ContactInfo Location { get; set; }
public List<Policy> Policies { get; set; }
}
public class ContactInfo
{
public int Id { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public State State { get; set; }
public string Zip { get; set; }
public string EMail { get; set; }
public List<Phone> PhoneNumbers { get; set; }
}
public class Phone
{
public int Id { get; set; }
public string Name { get; set; }
public string Number { get; set; }
}
public class Policy
{
public int Id { get; set; }
public PolicyNumber PolicyNumber { get; set; }
public List<Transaction> Transactions { get; set; }
}
The source tables, however, are relatively flattened.
public partial class Account
{
public string AccountId { get; set; }
public string AccountName { get; set; }
public string PolicyNumber { get; set; }
}
public partial class Transaction
{
public int TransactionId { get; set; }
public int AccountId { get; set; }
public Nullable<System.DateTime> EffectiveDate { get; set; }
public string InsuredName { get; set; }
public string InsuredAddress { get; set; }
public string InsuredCity { get; set; }
public string InsuredState { get; set; }
public string InsuredZip { get; set; }
public string InsuredPhone { get; set; }
}
I can create the Map, but I don't know how to tell AutoMapper to handle converting the string Policy to a policy object and then add it to the list of Policies.
Mapper.CreateMap<Source.Account, Destination.Account>();
Even worse, the source data inexplicitly has the name and address info at the transaction level. Before you tell me that AutoMap might not be the best solution, please understand that these two source tables are 2 out of over 40 tables in this database, and that the others are not nearly as troublesome.
Can I configure AutoMap to convert the string property PolicyNumber to a Policy Object and add it to the Policies List of the target class?
Any suggestions on how I can get the name and address information from the Transaction into a ContactInfo class and add it at the Account level?
Thank you.
Thanks to Thomas Weller. Custom Value Resolvers handled exactly what I needed.

How can i expose dto objects using wcf data service with ef code first?

I am trying to make a wcf data service where i dont want to get acces to the database models but instead i want to use Data transfer objects. I have been reading a lot on the internet about how to accomplish this but i cant get a good answer for my problem. It is the first time for me doing something with wcf data services so i am a little inexperienced.
Oke here are my models that are linked to my database using Entity Framework
public class User
{
[Key]
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string CountryCode { get; set; }
public string PhoneNumber { get; set; }
public ICollection<User> Contacts { get; set; }
public virtual Language Language { get; set; }
public User()
{
Contacts = new List<User>();
}
}
public class Message
{
[Key]
public int MessageId { get; set; }
public DateTime SentDate { get; set; }
public virtual User Sender { get; set; }
public virtual User Receiver { get; set; }
public string Content { get; set; }
public string OriginalCultureInfoEnglishName { get; set; }
public string ForeignCultureInfoEnglishName { get; set; }
}
public class Language
{
[Key]
public int LanguageId { get; set; }
public string CultureInfoEnglishName { get; set; }
}
Now i made a Service.svc which has my DatabaseContext so it can directly acces my database models. What i want to achieve is that instead of directly getting the database models i would like to get the DTO models when i query against my service.
A Example of how my dto's would look like
public class UserDTO
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Country { get; set; }
public string PhoneNumber { get; set; }
public ICollection<ContactDTO> Contacts { get; set; }
public virtual LanguageDTO Language { get; set; }
public UserModel()
{
Contacts = new List<ContactDTO>();
}
}
public class ContactDTO
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string Country { get; set; }
public string PhoneNumber { get; set; }
public virtual LanguageDTO Language { get; set; }
}
public class LanguageDTO
{
public int LanguageId { get; set; }
public string CultureInfoEnglishName { get; set; }
}
public class MessageDTO
{
public int MessageId { get; set; }
public DateTime SentDate { get; set; }
public virtual ContactDTO Sender { get; set; }
public virtual ContactDTO Receiver { get; set; }
public string Content { get; set; }
public string OriginalCultureInfoEnglishName { get; set; }
public string ForeignCultureInfoEnglishName { get; set; }
}
Now is it possible to do it like this by making a different context that i can use in my service.svc or is there any other way to achieve the this?
for example i would like to get ContactDto by userid which is a user but with less properties because they are not relevant in the client application. I see this happening by a uri http://localhost:54895/Service.svc/ContactDto(1)
Hopefully anyone can clear this up for me because it is really frustrating :)
I'm not sure that what you're interested in is possible, exactly. You are looking to have multiple entity sets per type (aka MEST), and I don't know how well that's supported.
Beyond that point, and into a discussion around DTOs in general...
If you use custom providers, you can implement your own IDataServiceMetadataProvider and IDataServiceQueryProvider. When your service starts, you can make calls into the IDataServiceMetadataProvider to control what entities and properties are exposed or hidden -- including exposing properties that do not actually exist on your entity. The upshot is that you end up with a DTO without coding a DTO class. The exposed metadata is the DTO. This is a good resource for creating your own providers.
In your case, this isn't a 100% solution, because you can't selectively choose when a property is exposed and when it's not.
Hope this helps...

Querying the database using EF Code First and Linq

I've spent a good deal of time and can't figure out how to make this query work. I am making a hours of operation type module where the users can choose something like the following:
Monday open from 8am to 11am closed from 11am to 1pm and open from 1pm to 5pm
This is completely dynamic and the users can choose how many opens and close they want (dynamically generated form inputs)
To do this I have made a couple of classes (I have no idea if this is a proper way of doing this because I've been using asp.net mvc, C# and EF for about a week now. Any suggestions would be greatly appreciated)
public class HoursOfOperation
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public IQueryable<CompanyHour> Monday { get; set; }
public IQueryable<CompanyHour> Tuesday { get; set; }
public IQueryable<CompanyHour> Wednesday { get; set; }
public IQueryable<CompanyHour> Thursday { get; set; }
public IQueryable<CompanyHour> Friday { get; set; }
public IQueryable<CompanyHour> Saturday { get; set; }
public IQueryable<CompanyHour> Sunday { get; set; }
//Navigation Property
public CompanyInformation Company { get; set; }
}
and
public class CompanyHour
{
public int id { get; set; }
public Status Status { get; set; }
public string From { get; set; }
public string To { get; set; }
}
public enum Status
{
Closed,
Open,
ByAppointmentsOnly
}
for completeness here is my companyInformation class
public class CompanyInformation
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
//[Required]
[DisplayName("Company Name:")]
public string companyName { get; set; }
[DisplayName("Website Address:")]
[Url(ErrorMessage="The Website field is not a valid fully-qualified http, https, or ftp URL. (Example: http://www.website.com)")]
public string website { get; set; }
public string contactTitle { get; set; }
//[Required]
[DisplayName("Contact First Name:")]
public string contactFirstName { get; set; }
//[Required]
[DisplayName("Contact Last Name:")]
public string contactLastName { get; set; }
//[Required]
[Phone]
[DisplayName("Phone Number:")]
public string contactPhoneNumber { get; set; }
[DisplayName("Address Display?")]
public bool displayAddress { get; set; }
[DisplayName("Phone Number?")]
public bool displayPhoneNumber { get; set; }
//[Required]
[DisplayName("Address 1:")]
public string address1 { get; set; }
[DisplayName("Address 2:")]
public string address2 { get; set; }
//[Required]
[DisplayName("City:")]
public string city { get; set; }
//[Required]
[DisplayName("State:")]
public string state { get; set; }
//[Required]
[DisplayName("Zip/Postal Code:")]
public string zipCode { get; set; }
[DisplayName("Search Engine?")]
public bool allowSearchEngines { get; set; }
//navigation Properties
public virtual ICollection<UserProfile> CompanyUsers { get; set; }
public virtual ICollection<HoursOfOperation> CompanyHours { get; set; }
}
The reason, I have hardcoded the monday, tue.... in the hoursofoperation class is to make it easy for mvc to map the dynamically generated fields (and that part works!!! :) )
Now I want to query the database and make a hours of operations model to send back to the view (on get) so I can bring back the saved information. I however can't figure out how to do that. I'm sending back a HoursOfOperation class.
the query I have currently:
var model = company.CompanyHours.Where(e => e.Company.id == company.id);
just returns a HoursOfOperation model with only the id (correct id) all the companyHours entities are all null.
Can anyone help me come up with the proper query?
I think you need to do this make use of InClude method to get the child enitities
context.Companies
.Include("CompanyHours")
.Where(e => e.Company.id == company.id) ;
Ok so I finally fixed this problem but the way I did it was completely restructure my models to a better and correct design.

Collection Nested within Model is Not Bound by MVC 3 (Always null)

I have a model that represents various information about a university in ASP.NET MVC 3 and Entity Framework 5.0. The model has an ICollection of another model, called TrendModel. This collection seems to never be stored/bound by MVC at any point, no matter what I do.
When I manually set this collection to something at run time (after it is retrieved from the database), the collection is of course no longer null, but whatever I seem to set it to and then store in the database, trends is always null when I retrieve it from the database.
UniversityModel:
public class UniversityModel
{
[Key]
public string univ_id { get; set; }
public string ipeds_id { get; set; }
public string name { get; set; }
public bool religious { get; set; }
#region Location Information
public string city { get; set; }
public string state { get; set; }
public string urbanization { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
#endregion
public ICollection<TrendModel> trends { get; set; }
}
TrendModel:
public class TrendModel
{
[Key]
public string id { get; set; }
public ushort year { get; set; }
public uint? capacity { get; set; }
public uint? rate { get; set; }
public uint? meals { get; set; }
public bool? forProfit { get; set; }
public bool? control { get; set; }
public string degree { get; set; }
public bool? landgrant { get; set; }
public bool? athletic { get; set; }
public string calendar { get; set; }
public bool? required { get; set; }
}
Not sure if it is relevant, but if I put in a constructor for UniversityModel that sets trends to an empty list, then trends is no longer null and is an empty list.
Is this a model binding issue, or a post issue or something? Sorry if I'm completely off-base, I'm pretty new to MVC and ASP.NET.
you haven't included a foreign key in your trend model.try adding univ_id in your TrendModel class.
public class TrendModel
{
[Key]
public string id { get; set; }
.
.
.
[ForeignKey("univ_id")]
public string univ_id {get;set;}
}
As it turn out, the issue was fixed simply by me enforcing lazy loading on the trends, so the property now reads:
public virtual ICollection<TrendModel> trends { get; set; }

Categories