I have a problem with the table creation of EF5 Code first. I'm going to demonstrate two cases and their outputs. What I want to know what the difference between them and how I could be successful on my goal.
Case 1
public class User{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<UserMessage> Messages { get; set; }
}
public class UserMessage{
public int ID { get; set; }
public string Message { get; set; }
public User CreatedBy { get; set; }
public ICollection<User> PermittedUsers {get; set;}
}
Now in this case, entity framework generates only User and UserMessage classes that are only binding to each other with UserMessage_ID in User and CreatedBy_ID in UserMessage.
The problem that I'm curious is in here. How will EF5 recognize permitted users whenever I create a new message? Is it going to duplicate the same message for each permitted users? Or what?
Case 2
public class User{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<UserMessage> Messages { get; set; }
}
public class UserMessage{
public int ID { get; set; }
public string Message { get; set; }
public ICollection<User> PermittedUsers {get; set;}
}
In this case I have removed just only CreatedBy in UserMessage entity. Now EF5 generates 3 tables named : User, UserMessage, UserMessageUsers. The links between UserMessage and User is now over UserMessageUsers so that we can easily manage permitted users.
How can I add CreatedBy property into UserMessage without breaking up Case 2 ?
You can use fluent api to configurate it:
modelBuilder.Entity<UserMessage>()
.HasMany(d=>d.PermittedUsers)
.WithMany(d=>d.Messages)
.Map(c=>c.ToTable("UserMessageUsers"));
Related
I'm bit confused here, here is my bussiness logics:
When new user is added to a system it should belong to some company (only one company) so my users entity looks like this:
public class User : IdentityUser<long>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Company Company { get; set; }
public long? CompanyId { get; set; }
public string ProfileImageUrl { get; set; }
}
Basically when user is added there is a dropdown where admin can choose company which is related to that user and that is fine. (User is treated as employee of that company)
But after a while we realised that Every single company must have a commercialist (user) which is related to that company. So for example if there are some additional questions about products that company is selling, first person that we should contact is commercialist related to that company and my company entity looks like this:
public class Company : BaseEntity<long>, IDeleted
{
public string Title { get; set; }
public string Description { get; set; }
public long? CommercialistId { get; set; }
public User Commercialist { get; set; }
}
Now I have an issue here since I can't add two companies with same commercialist. For example commercialist John is covering two companies, Apple & Samsung.
But with this scenario it looks like I've created one to one relationship and John can cover only one of these companies.
How I could solve this to relate John with two or more companies that are under his support ? (without adding extra tables ?)
Thanks guys!
Cheers!
The easiest way would be to just to add IsCommercialist flag to User class.
public class User : IdentityUser<long>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsCommercialist {get; set;}
public long? CompanyId { get; set; }
[ForeignKey(nameof(CompanyId))]
[InverseProperty("Users")]
public Company Company { get; set; }
[InverseProperty(nameof(Company.Commercialist))]
public virtual ICollection<Company> CommercialistCompanies {get; set;}
public string ProfileImageUrl { get; set; }
}
public class Company : BaseEntity<long>, IDeleted
{
public string Title { get; set; }
public string Description { get; set; }
public long? CommercialistId { get; set; }
[ForeignKey(nameof(CommercialistId ))]
[InverseProperty("CommercialistCompanies")]
public User Commercialist { get; set; }
[InverseProperty(nameof(User.Company)]
public virtual ICollection<User> Users {get; set;}
}
but I am afraid that relations have to be defined manually, as I did, since EF will not be able to do it properly
I'm trying to think of a way to store actual templates of ticket items in my Entity Framework MVC project. The thing is, I've already done a Code First migration process in the past. What I need to do is create logic in my code to allow someone to save time creating a ticket by using pre-loaded data from a template. My current inheritance model uses an abstract class (MasterTicket) which is used as the parent since to me there can be multiple categories (a Google Calendar based task, "Appointment Task" and a purely internal task, "General Task"). Here's my parent abstract class:
[Table("Ticket")]
[ModelBinder(typeof(MasterTicketBinder))]
public abstract class MasterTicket
{
[Key]
public Guid id{ get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ART { get; set; }
public DateTime openTime{ get; set; }
public DateTime? closeTime { get; set; }
private bool active = true;
public bool Active{ get => active; set => active = value; }
public string summary{ get; set; }
public string description{ get; set; }
public DateTime updateTime{ get; set; }
//TODO: Create foreign key relationship to user model
public Guid userUpdateId{ get; set; }
//TODO: Create foreign key relationship for tickets from other systems
public Guid externalAppId{ get; set; }
//TODO: Create foreign key relationship to user model
public Guid userOpenId{ get; set; }
public Guid? userCloseId { get; set; }
public Guid userOwnerId{ get; set; }
private int timesUpdated = 0;
public int TimesUpdated { get => timesUpdated; set => timesUpdated = value; }
public DateTime expectedCompletionTime{ get; set; }
public DateTime actualCompletionTime{ get; set; }
public List<MasterTicketItem> masterTicketItems{ get; set; }
public MasterTicket()
{
}
}
An here's an example of the concrete Google Calendar-based "Appointment Task" child:
[Table("AppointmentTickets")]
public class ApptTaskTicket : MasterTicket
{
public DateTime currentApptTime { get; set; }
public DateTime? endApptTime { get; set; }
public bool allDay { get; set; }
public string customerName { get; set; }
//TODO: Create foreign relationship
public Guid subjectPrsnlId { get; set; }
public string gCalEventId { get; set; }
public string customerPhone { get; set; }
public string customerEmail { get; set; }
public string preferredContactMethod { get; set; }
public List<ApptConfirmItem> apptConfirmItems { get; set; }
}
I know I can easily create a column for the MasterTicket class to indicate that it's a template, but to me I feel it's cleaner to have a separate "Template Table" if you will that will store pre-existing values that can be filled in with a form. In this case, I think I would WANT to create a duplicate class that would store said templates so that there are only several rows. What would be the best way to do this with Code First? Does someone feel I should take a different approach? Maybe DB First is a better way to go?
In case it matters, here's my DBContext for the Tickets:
// Code-Based Configuration and Dependency resolution
[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class TicketDB : DbContext
{
public TicketDB(): base("AffirmativeServiceSystem.Properties.Settings.AffirmTaskManager")
{
}
public DbSet<MasterTicket> tickets { get; set; }
public DbSet<MasterTicketItem> ticketItems { get; set; }
}
Suppose I have two entities, bungalows and apartments. Both of them have varying fields and cannot be interchanged however both these entities have multiple tenants. Each tenant can only be part of either one bungalow or one apartment. How do I achieve this using Entity Framework?
I was thinking of creating 2 more entities bungalowTenants and apartmentTenants and using these to map. Each bungalowTenant would have one instance of a bungalow and a tenant and similarly for apartmentTenant.
Bungalows would have a collection of bungalowTenants and apartment of apartmentTenants.
public class Bungalow
{
public int Id { get; set; }
public int HouseNumber { get; set; }
public string Street { get; set; }
public ICollection<BungalowTenants> Tenants { get; set; }
}
public class Apartment
{
public int Id { get; set; }
public int ApartmentNumber{ get; set; }
public string Wing{ get; set; }
public string Building{ get; set; }
public ICollection<ApartmentTenants> Tenants { get; set; }
}
public class Tenant
{
public int Id{ get; set; }
public string Name{ get; set; }
}
public class ApartmentTenants
{
public int ApartmentId { get; set; }
public Apartment Apartment{ get; set; }
public int TenantId{ get; set; }
public Tenant Tenant{ get; set; }
}
public class BungalowTenants
{
public int BungalowId{ get; set; }
public Bungalow Bungalow{ get; set; }
public int TenantId{ get; set; }
public Tenant Tenant{ get; set; }
}
The problem with this approach is that it does not restrict in any way the same tenant to be a part of both, a bungalow and an apartment. I am unable to figure out how to do that using Entity Framework. I'd appreciate any help on this matter.
Not every business rule can be or needs to be translated to database constraints or model constraints.
And if you would enforce this, through model rules or programmed rules:
What if the tenants decide to move from a bungalow to an apartment? They will most probably want to start renting the new home days or even weeks before the cancellation date of the old one - or do you expect them to vacate the old home before midnight and enter the new home after midnight, with all their belongings packed in boxes on the pavement for a certain period? That does not seem very realistic.
I'm going back to EF (Code First) and ATM trying to set up a 1-1 relationship using DataAnnotations.
public class CmsMember
{
[Key]
public int nodeId { get; set; }
public string Email { get; set; }
public string LoginName { get; set; }
public string Password { get; set; }
public Client Client { get; set; }
}
public class Client
{
[ForeignKey("CmsMember")]
public int nodeId { get; set; }
public int ClientId { get; set; }
public string ClientName { get; set; }
public CmsMember CmsMember { get; set; }
}
I'm stuck on error (on add-migration command) saying:
** \tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'Client_CmsMember_Source' in relationship 'Client_CmsMember'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be ''. *
Any hint would be highly appreciated.
You need key attribute because your property name doesn't match the convention.
[Key, ForeignKey("CmsMember")]
public int nodeId { get; set; }
I think this should help you. There is the same error and your code is similar. You need to change the place of the attribute as well, should be above the property where you want to use in you case above
public CmsMember CmeMember { get; set; }
Consider this Poco:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Fullname { get; set; }
}
Now i want to implement a follow technique where a user may follow other users so basically its self Many to Many relationship
problem is i don't know how exactly i can achieve this in Entity Framework Code-First ?
I thought of a linker Table :
public class UserFollow
{
public int Id { get; set; }
public int Follower { get; set; }
public int Following { get; set; }
public DateTime FollowDate { get; set; }
}
i want to be able to get All Followers and Following from every User Object?
This is quite simple using EF code-first as you only need the User POCO:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Fullname { get; set; }
public ICollection<User> FollowedUsers { get; set; }
}
The collection means that a User is related to other users.
PS: I noted you added a timestamp in your solution example. To achieve that you should still add the collection changing the generic type to whatever suits your needs.
Hope it helps.