Querying the database using EF Code First and Linq - c#

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.

Related

EF Include is not working! returning null in a 1 to many relationship

i am trying to display a list of cities with a country, a 1 to many relation.
I created the models for both of them:
City model
[Key]
public int ID_Cidade { get; set;
public int ID_Pais { get; set; }
public RH_Pais Pais { get; set; }
public string Nome { get; set; }
public Boolean Capital { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public string Autor { get; set; }
public int OrdemCidade { get; set; }
public List<RH_Escritorios> Escritorios { get; set; }
Country model
[Key]
public int ID_Pais { get; set; }
public int ID_Moeda { get; set; }
public RH_Moeda Moeda { get; set; }
public string Nome { get; set; }
public string Nome_completo { get; set; }
public DateTime SysStartTime { get; set; }
public DateTime SysEndTime { get; set; }
public string Autor { get; set; }
public int OrdemPais { get; set; }
public List<RH_Cidades> Cidades { get; set; }
public List<RH_Idioma_Pais> Idiomas { get; set; }
and then i used fluent API to create the relationship
modelBuilder.Entity<RH_Cidades>()
.HasOne(m => m.Pais)
.WithMany(m => m.Cidades)
.HasForeignKey(m => m.ID_Pais);
and somehow when i generate the controller with EF, and i go to see the cities it causes a null error... this is because it has a include of the country when im trying to get the cities..
var rH_EntitiesContext = _context.RH_Cidades.Include(r => r.Pais).ToList();
The most annoying part is that i have the exact same situation in another relationship, with 1 to many and the include and it works perfectly!!
I have read and read my code for hours by now and i cannot see why the Include is giving me that error when in the offices controller with the same situation works...
Any help is appreciated!!!

C# mongodb model like Facebook

I'm working on a project where the MongoDB model will be similar to Facebook. So we all know how FB works, a user "likes" a band/company page, and that user will see all the posts from that page.
Is the below model how I should design this?
If a Page has million likes, then each Post will have a million sub documents of Like. That does not seem right, there must be a better way that I cant think of.
Thanks.
public class Person
{
public ObjectId Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Page
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public List<Like> PersonLikes { get; set; }
}
public class Like
{
public ObjectId Id { get; set; }
public ObjectId UserId { get; set; }
public DateTime DateLiked { get; set; }
}
public class Post
{
public ObjectId Id { get; set; }
public ObjectId PageId { get; set; }
public string Message { get; set; }
public List<Like> PersonLikes { get; set; }
}
My take assuming you only want to track likes
public class Page
{
public ObjectId Id { get; set; }
public DateTimeOffset Date { get; set; }
public string Name { get; set; }
public int NumberOfLikes { get; set; }
}
public class Post
{
public ObjectId Id { get; set; }
public ObjectId PageId { get; set; }
public DateTimeOffset Date { get; set; }
public string Message { get; set; }
public int NumberOfLikes { get; set; }
}
I would then queue the Reaction (Like or Dislike) for insertion, "sentiment" information doesn't have to be stored in real time, does it? These are not medications, bank transactions, etc.
public class Like
{
public ObjectId Id { get; set; }
public ObjectId ParentId { get; set;}
public ObjectId UserId { get; set; }
public DateTimeOffset Date { get; set; }
}
Queue where? to a collection of Likes. Why not part of the page or post? Because if a post goes viral (as you said even though the majority won't), you may end up with a 1,000,000 likes. Who is going to browse this information other than an analytic engine?
You also have to ensure a user can only express their reaction only once per item.
The post only exists on one page so it´s the page that should own the post, not the post owning the page.
public class Person
{
public ObjectId Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Page
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public List<Like> PersonLikes { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public ObjectId Id { get; set; }
public string Message { get; set; }
public List<Like> Likes { get; set; }
}
public class Like
{
public ObjectId Id { get; set; }
public ObjectId UserId { get; set; }
public DateTime DateLiked { get; set; }
}

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...

New Model within ViewModel error on ID of 0

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.

Categories